Add caching for lrclib lyrics
This commit is contained in:
+3
-3
@@ -57,7 +57,7 @@ type App struct {
|
||||
displayAppName string
|
||||
appVersionTag string
|
||||
configDir string
|
||||
cacheDir string
|
||||
CacheDir string
|
||||
portableMode bool
|
||||
|
||||
isFirstLaunch bool // set by config file reader
|
||||
@@ -103,7 +103,7 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas
|
||||
displayAppName: displayAppName,
|
||||
appVersionTag: appVersionTag,
|
||||
configDir: confDir,
|
||||
cacheDir: cacheDir,
|
||||
CacheDir: cacheDir,
|
||||
portableMode: portableMode,
|
||||
}
|
||||
a.bgrndCtx, a.cancel = context.WithCancel(context.Background())
|
||||
@@ -411,7 +411,7 @@ func (a *App) LoginToDefaultServer(string) error {
|
||||
}
|
||||
|
||||
func (a *App) DeleteServerCacheDir(serverID uuid.UUID) error {
|
||||
path := path.Join(a.cacheDir, serverID.String())
|
||||
path := path.Join(a.CacheDir, serverID.String())
|
||||
log.Printf("Deleting server cache dir: %s", path)
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -150,10 +150,10 @@ type PlaylistWithTracks struct {
|
||||
}
|
||||
|
||||
type Lyrics struct {
|
||||
Title string
|
||||
Artist string
|
||||
Synced bool
|
||||
Lines []LyricLine
|
||||
Title string `json:"title"`
|
||||
Artist string `json:"artist"`
|
||||
Synced bool `json:"synced"`
|
||||
Lines []LyricLine `json:"lines"`
|
||||
}
|
||||
|
||||
type LyricLine struct {
|
||||
|
||||
Reference in New Issue
Block a user