diff --git a/cmdHandlers.go b/cmdHandlers.go index c336eaf..105d46d 100644 --- a/cmdHandlers.go +++ b/cmdHandlers.go @@ -297,9 +297,12 @@ func saveSong(filePath string, force bool) error { return fmt.Errorf("failed to get YouTube ID for song: %v", err) } + fileName := strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath)) if track.Title == "" { - return fmt.Errorf("no title found in metadata") + // If title is empty, use the file name + track.Title = fileName } + if track.Artist == "" { return fmt.Errorf("no artist found in metadata") } @@ -310,11 +313,10 @@ func saveSong(filePath string, force bool) error { } // Move song in wav format to songs directory - fileName := strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath)) wavFile := fileName + ".wav" sourcePath := filepath.Join(filepath.Dir(filePath), wavFile) newFilePath := filepath.Join(SONGS_DIR, wavFile) - err = os.Rename(sourcePath, newFilePath) + err = utils.MoveFile(sourcePath, newFilePath) if err != nil { return fmt.Errorf("failed to rename temporary file to output file: %v", err) } diff --git a/db/sqlite.go b/db/sqlite.go index 0a44d60..03691a6 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -35,7 +35,7 @@ func createTables(db *sql.DB) error { id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, artist TEXT NOT NULL, - ytID TEXT UNIQUE, + ytID TEXT, key TEXT NOT NULL UNIQUE ); ` diff --git a/spotify/downloader.go b/spotify/downloader.go index 5601909..1e32841 100644 --- a/spotify/downloader.go +++ b/spotify/downloader.go @@ -307,7 +307,7 @@ func ProcessAndSaveSong(songFilePath, songTitle, songArtist, ytID string) error err = dbclient.StoreFingerprints(fingerprints) if err != nil { dbclient.DeleteSongByID(songID) - return fmt.Errorf("error to storing fingerpring: %v", err) + return fmt.Errorf("error to storing fingerprint: %v", err) } fmt.Printf("Fingerprint for %v by %v saved in DB successfully\n", songTitle, songArtist) diff --git a/utils/helpers.go b/utils/helpers.go index 98c1e56..b1d2ac5 100644 --- a/utils/helpers.go +++ b/utils/helpers.go @@ -1,18 +1,10 @@ package utils import ( - "context" - "encoding/base64" "encoding/binary" "fmt" - "log/slog" + "io" "os" - "song-recognition/models" - "song-recognition/wav" - "strings" - "time" - - "github.com/mdobak/go-xerrors" ) func DeleteFile(filePath string) error { @@ -32,6 +24,36 @@ func CreateFolder(folderPath string) error { return nil } +func MoveFile(sourcePath string, destinationPath string) error { + srcFile, err := os.Open(sourcePath) + if err != nil { + return err + } + + destFile, err := os.Create(destinationPath) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, srcFile) + if err != nil { + return err + } + + err = srcFile.Close() + if err != nil { + return err + } + + err = os.Remove(sourcePath) + if err != nil { + return err + } + + return nil +} + func FloatsToBytes(data []float64, bitsPerSample int) ([]byte, error) { var byteData []byte @@ -68,52 +90,3 @@ func FloatsToBytes(data []float64, bitsPerSample int) ([]byte, error) { return byteData, nil } - -func ProcessRecording(recData *models.RecordData, saveRecording bool) ([]float64, error) { - decodedAudioData, err := base64.StdEncoding.DecodeString(recData.Audio) - if err != nil { - return nil, err - } - - now := time.Now() - fileName := fmt.Sprintf("%04d_%02d_%02d_%02d_%02d_%02d.wav", - now.Second(), now.Minute(), now.Hour(), - now.Day(), now.Month(), now.Year(), - ) - filePath := "tmp/" + fileName - - err = wav.WriteWavFile(filePath, decodedAudioData, recData.SampleRate, recData.Channels, recData.SampleSize) - if err != nil { - return nil, err - } - - reformatedWavFile, err := wav.ReformatWAV(filePath, 1) - if err != nil { - return nil, err - } - - wavInfo, _ := wav.ReadWavInfo(reformatedWavFile) - samples, _ := wav.WavBytesToSamples(wavInfo.Data) - - if saveRecording { - logger := GetLogger() - ctx := context.Background() - - err := CreateFolder("recordings") - if err != nil { - err := xerrors.New(err) - logger.ErrorContext(ctx, "Failed create folder.", slog.Any("error", err)) - } - - newFilePath := strings.Replace(reformatedWavFile, "tmp/", "recordings/", 1) - err = os.Rename(reformatedWavFile, newFilePath) - if err != nil { - logger.ErrorContext(ctx, "Failed to move file.", slog.Any("error", err)) - } - } - - DeleteFile(fileName) - DeleteFile(reformatedWavFile) - - return samples, nil -} diff --git a/wav/convert.go b/wav/convert.go index 1c815ba..0d6dc20 100644 --- a/wav/convert.go +++ b/wav/convert.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" "path/filepath" + "song-recognition/utils" "strings" ) @@ -43,7 +44,7 @@ func ConvertToWAV(inputFilePath string, channels int) (wavFilePath string, err e } // Rename the temporary file to the output file - err = os.Rename(tmpFile, outputFile) + err = utils.MoveFile(tmpFile, outputFile) if err != nil { return "", fmt.Errorf("failed to rename temporary file to output file: %v", err) } diff --git a/wav/wav.go b/wav/wav.go index 010ac5d..1b05186 100644 --- a/wav/wav.go +++ b/wav/wav.go @@ -2,13 +2,22 @@ package wav import ( "bytes" + "context" + "encoding/base64" "encoding/binary" "encoding/json" "errors" "fmt" "io/ioutil" + "log/slog" "os" "os/exec" + "song-recognition/models" + "song-recognition/utils" + "strings" + "time" + + "github.com/mdobak/go-xerrors" ) // WavHeader defines the structure of a WAV header @@ -198,5 +207,62 @@ func GetMetadata(filePath string) (FFmpegMetadata, error) { return metadata, err } + // convert all keys of the Tags map to lowercase + for k, v := range metadata.Format.Tags { + metadata.Format.Tags[strings.ToLower(k)] = v + } + for k, v := range metadata.Streams[0].Tags { + metadata.Streams[0].Tags[strings.ToLower(k)] = v + } + return metadata, nil } + +func ProcessRecording(recData *models.RecordData, saveRecording bool) ([]float64, error) { + decodedAudioData, err := base64.StdEncoding.DecodeString(recData.Audio) + if err != nil { + return nil, err + } + + now := time.Now() + fileName := fmt.Sprintf("%04d_%02d_%02d_%02d_%02d_%02d.wav", + now.Second(), now.Minute(), now.Hour(), + now.Day(), now.Month(), now.Year(), + ) + filePath := "tmp/" + fileName + + err = WriteWavFile(filePath, decodedAudioData, recData.SampleRate, recData.Channels, recData.SampleSize) + if err != nil { + return nil, err + } + + reformatedWavFile, err := ReformatWAV(filePath, 1) + if err != nil { + return nil, err + } + + wavInfo, _ := ReadWavInfo(reformatedWavFile) + samples, _ := WavBytesToSamples(wavInfo.Data) + + if saveRecording { + logger := utils.GetLogger() + ctx := context.Background() + + err := utils.CreateFolder("recordings") + if err != nil { + err := xerrors.New(err) + logger.ErrorContext(ctx, "Failed create folder.", slog.Any("error", err)) + } + + newFilePath := strings.Replace(reformatedWavFile, "tmp/", "recordings/", 1) + err = os.Rename(reformatedWavFile, newFilePath) + if err != nil { + logger.ErrorContext(ctx, "Failed to move file.", slog.Any("error", err)) + } + } + + utils.DeleteFile(fileName) + utils.DeleteFile(reformatedWavFile) + + return samples, nil +}