Make 'wav' module separating it from 'utils'.

This commit is contained in:
Chigozirim Igweamaka 2024-05-09 20:48:49 +01:00
parent 316d8c036b
commit 4e93c857b5
4 changed files with 159 additions and 117 deletions

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"song-recognition/models" "song-recognition/models"
"strings"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
@ -111,7 +112,7 @@ func (db *DbClient) GetTables(addresses []uint32) (map[uint32][]models.Table, er
table := models.Table{ table := models.Table{
AnchorTimeMs: uint32(itemMap["anchorTimeMs"].(int64)), AnchorTimeMs: uint32(itemMap["anchorTimeMs"].(int64)),
SongID: itemMap["songID"].(string), SongID: uint32(itemMap["songID"].(int64)),
} }
docTables = append(docTables, table) docTables = append(docTables, table)
} }
@ -122,7 +123,7 @@ func (db *DbClient) GetTables(addresses []uint32) (map[uint32][]models.Table, er
} }
func (db *DbClient) TotalSongs() (int, error) { func (db *DbClient) TotalSongs() (int, error) {
existingSongsCollection := db.client.Database("song-recognition").Collection("existing-songs") existingSongsCollection := db.client.Database("song-recognition").Collection("songs")
total, err := existingSongsCollection.CountDocuments(context.Background(), bson.D{}) total, err := existingSongsCollection.CountDocuments(context.Background(), bson.D{})
if err != nil { if err != nil {
return 0, err return 0, err
@ -131,29 +132,7 @@ func (db *DbClient) TotalSongs() (int, error) {
return int(total), nil return int(total), nil
} }
func (db *DbClient) SongExists(songTitle, songArtist, ytID string) (bool, error) { func (db *DbClient) RegisterSong(songTitle, songArtist, ytID string) (uint32, error) {
existingSongsCollection := db.client.Database("song-recognition").Collection("existing-songs")
key := fmt.Sprintf("%s - %s", songTitle, songArtist)
var filter bson.M
if len(ytID) == 0 {
filter = bson.M{"_id": key}
} else {
filter = bson.M{"ytID": ytID}
}
var result bson.M
if err := existingSongsCollection.FindOne(context.Background(), filter).Decode(&result); err == nil {
return true, nil
} else if err != mongo.ErrNoDocuments {
return false, fmt.Errorf("failed to retrieve registered songs: %v", err)
}
return false, nil
}
func (db *DbClient) RegisterSong(songTitle, songArtist, ytID string) error {
existingSongsCollection := db.client.Database("song-recognition").Collection("songs") existingSongsCollection := db.client.Database("song-recognition").Collection("songs")
// Create a compound unique index on ytID and key, if it doesn't already exist // Create a compound unique index on ytID and key, if it doesn't already exist
@ -163,105 +142,110 @@ func (db *DbClient) RegisterSong(songTitle, songArtist, ytID string) error {
} }
_, err := existingSongsCollection.Indexes().CreateOne(context.Background(), indexModel) _, err := existingSongsCollection.Indexes().CreateOne(context.Background(), indexModel)
if err != nil { if err != nil {
return fmt.Errorf("failed to create unique index: %v", err) return 0, fmt.Errorf("failed to create unique index: %v", err)
} }
// Attempt to insert the song with ytID and key // Attempt to insert the song with ytID and key
key := fmt.Sprintf("%s - %s", songTitle, songArtist) songID := GenerateUniqueID()
_, err = existingSongsCollection.InsertOne(context.Background(), bson.M{"_id": key, "ytID": ytID}) key := GenerateSongKey(songTitle, songArtist)
_, err = existingSongsCollection.InsertOne(context.Background(), bson.M{"_id": songID, "key": key, "ytID": ytID})
if err != nil { if err != nil {
if mongo.IsDuplicateKeyError(err) { if mongo.IsDuplicateKeyError(err) {
return fmt.Errorf("song with ytID or key already exists: %v", err) return 0, fmt.Errorf("song with ytID or key already exists: %v", err)
} else { } else {
return fmt.Errorf("failed to register song: %v", err) return 0, fmt.Errorf("failed to register song: %v", err)
} }
} }
return songID, nil
}
type Song struct {
Title string
Artist string
YouTubeID string
}
func (db *DbClient) GetSongByID(songID uint32) (Song, error) {
songsCollection := db.client.Database("song-recognition").Collection("songs")
var song bson.M
filter := bson.M{"_id": songID}
err := songsCollection.FindOne(context.Background(), filter).Decode(&song)
if err != nil {
if err == mongo.ErrNoDocuments {
return Song{}, fmt.Errorf("song not found")
}
return Song{}, fmt.Errorf("failed to retrieve song: %v", err)
}
ytID := song["ytID"].(string)
title := strings.Split(song["key"].(string), "---")[0]
artist := strings.Split(song["key"].(string), "---")[1]
songInstance := Song{title, artist, ytID}
return songInstance, nil
}
func (db *DbClient) GetSongByYTID(ytID string) (Song, error) {
songsCollection := db.client.Database("song-recognition").Collection("songs")
var song bson.M
filter := bson.M{"ytID": ytID}
err := songsCollection.FindOne(context.Background(), filter).Decode(&song)
if err != nil {
if err == mongo.ErrNoDocuments {
return Song{}, fmt.Errorf("song not found")
}
return Song{}, fmt.Errorf("failed to retrieve song: %v", err)
}
title := strings.Split(song["key"].(string), "---")[0]
artist := strings.Split(song["key"].(string), "---")[1]
songInstance := Song{title, artist, song["ytID"].(string)}
return songInstance, nil
}
func (db *DbClient) GetSongByKey(key string) (Song, error) {
songsCollection := db.client.Database("song-recognition").Collection("songs")
var song bson.M
filter := bson.M{"key": key}
err := songsCollection.FindOne(context.Background(), filter).Decode(&song)
if err != nil {
if err == mongo.ErrNoDocuments {
return Song{}, fmt.Errorf("song not found")
}
return Song{}, fmt.Errorf("failed to retrieve song: %v", err)
}
ytID := song["ytID"].(string)
title := strings.Split(song["key"].(string), "---")[0]
artist := strings.Split(song["key"].(string), "---")[1]
songInstance := Song{title, artist, ytID}
return songInstance, nil
}
func (db *DbClient) DeleteSongByID(songID uint32) error {
songsCollection := db.client.Database("song-recognition").Collection("songs")
filter := bson.M{"_id": songID}
_, err := songsCollection.DeleteOne(context.Background(), filter)
if err != nil {
return fmt.Errorf("failed to delete song: %v", err)
}
return nil return nil
} }
func (db *DbClient) InsertChunkTag(chunkfgp int64, chunkTag interface{}) error {
chunksCollection := db.client.Database("song-recognition").Collection("chunks")
filter := bson.M{"fingerprint": chunkfgp}
var result bson.M
err := chunksCollection.FindOne(context.Background(), filter).Decode(&result)
if err == nil {
// If the fingerprint already exists, append the chunkTag to the existing list
// fmt.Println("DUPLICATE FINGERPRINT: ", chunkfgp)
update := bson.M{"$push": bson.M{"chunkTags": chunkTag}}
_, err := chunksCollection.UpdateOne(context.Background(), filter, update)
if err != nil {
return fmt.Errorf("failed to update chunkTags: %v", err)
}
return nil
} else if err != mongo.ErrNoDocuments {
return err
}
// If the document doesn't exist, insert a new document
_, err = chunksCollection.InsertOne(context.Background(), bson.M{"fingerprint": chunkfgp, "chunkTags": []interface{}{chunkTag}})
if err != nil {
return fmt.Errorf("failed to insert chunk tag: %v", err)
}
return nil
}
func (db *DbClient) GetChunkTags(chunkfgp int64) ([]primitive.M, error) {
chunksCollection := db.client.Database("song-recognition").Collection("chunks")
filter := bson.M{"fingerprint": chunkfgp}
result := bson.M{}
err := chunksCollection.FindOne(context.Background(), filter).Decode(&result)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
}
return nil, fmt.Errorf("failed to retrieve chunk tag: %w", err)
}
var listOfChunkTags []primitive.M
for _, data := range result["chunkTags"].(primitive.A) {
listOfChunkTags = append(listOfChunkTags, data.(primitive.M))
}
return listOfChunkTags, nil
}
func (db *DbClient) GetChunkTagForSong(songTitle, songArtist string) (bson.M, error) {
chunksCollection := db.client.Database("song-recognition").Collection("chunks")
filter := bson.M{
"chunkTags": bson.M{
"$elemMatch": bson.M{
"songtitle": songTitle,
"songartist": songArtist,
},
},
}
var result bson.M
if err := chunksCollection.FindOne(context.Background(), filter).Decode(&result); err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
}
return nil, fmt.Errorf("failed to find chunk: %v", err)
}
var chunkTag map[string]interface{}
for _, chunk := range result["chunkTags"].(primitive.A) {
chunkMap, ok := chunk.(primitive.M)
if !ok {
continue
}
if chunkMap["songtitle"] == songTitle && chunkMap["songartist"] == songArtist {
chunkTag = chunkMap
break
}
}
return chunkTag, nil
}

17
utils/utils.go Normal file
View file

@ -0,0 +1,17 @@
package utils
import (
"math/rand"
"time"
)
func GenerateUniqueID() uint32 {
rand.Seed(time.Now().UnixNano())
randomNumber := rand.Uint32()
return randomNumber
}
func GenerateSongKey(songTitle, songArtist string) string {
return songTitle + "---" + songArtist
}

41
wav/convert.go Normal file
View file

@ -0,0 +1,41 @@
package wav
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
func ConvertToWAV(inputFilePath string, channels int) (wavFilePath string, errr error) {
_, err := os.Stat(inputFilePath)
if err != nil {
return "", fmt.Errorf("input file does not exist: %v", err)
}
if channels != 1 || channels != 2 {
channels = 1
}
fileExt := filepath.Ext(inputFilePath)
outputFile := strings.TrimSuffix(inputFilePath, fileExt) + ".wav"
// Execute FFmpeg command to convert to WAV format with one channel (mono)
cmd := exec.Command(
"ffmpeg",
"-y", // Automatically overwrite if file exists
"-i", inputFilePath,
"-c", "pcm_s16le", // Output PCM signed 16-bit little-endian audio
"-ar", "44100",
"-ac", fmt.Sprint(channels),
outputFile,
)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to convert to WAV: %v, output %v", err, string(output))
}
return outputFile, nil
}

View file

@ -1,4 +1,4 @@
package utils package wav
import ( import (
"bytes" "bytes"