Add caching for lrclib lyrics

This commit is contained in:
jojii
2025-02-05 19:42:22 +01:00
parent a8cae47f61
commit 29b04778f1
5 changed files with 93 additions and 11 deletions
+80
View File
@@ -2,10 +2,15 @@ package backend
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
@@ -14,6 +19,38 @@ import (
"github.com/dweymouth/supersonic/backend/mediaprovider"
)
func FetchLrcLibLyricsCached(name, artist, album string, durationSecs int, cacheDir string) (*mediaprovider.Lyrics, error) {
hash := makeTrackIdHash(name, artist, album)
cacheFilePath := filepath.Join(cacheDir, fmt.Sprintf("%s_lyrics.txt", hash))
// File is cached. Try to use it
if _, err := os.Stat(cacheFilePath); err == nil {
lyrics, err := readCachedLyrics(cacheFilePath)
if err == nil {
return lyrics, nil
}
// On an error, remove the file.
if !os.IsNotExist(err) {
os.Remove(cacheFilePath)
}
}
// Fetch the lyrics
lyrics, err := FetchLrcLibLyrics(name, artist, album, durationSecs)
if err != nil {
return nil, err
}
// Try to write it into cache
err = writeCachedLyrics(cacheFilePath, lyrics)
if err != nil {
log.Printf("Failed to serialize fetched lyrics: %s", err)
}
return lyrics, nil
}
// FetchLrcLibLyrics is a static function to search and fetch lyrics from lrclib.net
func FetchLrcLibLyrics(name, artist, album string, durationSecs int) (*mediaprovider.Lyrics, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
@@ -105,3 +142,46 @@ type lrcLibResponse struct {
PlainLyrics string `json:"plainLyrics"`
SyncedLyrics string `json:"syncedLyrics"`
}
// Write lyrics to the given file.
func writeCachedLyrics(cacheFile string, lyrics *mediaprovider.Lyrics) error {
serialized, err := json.Marshal(lyrics)
if err != nil {
return err
}
f, err := os.Create(cacheFile)
if err != nil {
return nil
}
defer f.Close()
f.Write(serialized)
return nil
}
// Read lyrics from the given cache file.
func readCachedLyrics(cacheFile string) (*mediaprovider.Lyrics, error) {
cachedBytes, err := os.ReadFile(cacheFile)
if err != nil {
return nil, err
}
var lyrics mediaprovider.Lyrics
err = json.Unmarshal(cachedBytes, &lyrics)
if err != nil {
return nil, err
}
return &lyrics, nil
}
// Create a "unique" hash for a song to identify it.
func makeTrackIdHash(name, artist, album string) string {
hasher := md5.New()
identifier := fmt.Sprintf("%s;%s;%s", name, artist, album)
hasher.Write([]byte(identifier))
return hex.EncodeToString(hasher.Sum(nil))
}