Files
SpotiFLAC-Mobile/go_backend/download_preparation_cache.go
T

130 lines
3.6 KiB
Go

package gobackend
import (
"strings"
"sync"
"time"
)
const (
downloadPreparationCacheTTL = 5 * time.Minute
downloadPreparationCacheMax = 128
)
type preparedDownloadRequestEntry struct {
key string
request DownloadRequest
metadataPrepared bool
createdAt time.Time
}
var (
preparedDownloadRequests = make(map[string]preparedDownloadRequestEntry)
preparedDownloadRequestsMu sync.Mutex
)
func downloadPreparationKey(req DownloadRequest) string {
return strings.Join([]string{
strings.TrimSpace(req.ItemID),
strings.ToLower(strings.TrimSpace(req.Service)),
strings.ToLower(strings.TrimSpace(req.Source)),
strings.TrimSpace(req.SpotifyID),
strings.TrimSpace(req.TidalID),
strings.TrimSpace(req.QobuzID),
strings.TrimSpace(req.DeezerID),
strings.ToLower(strings.TrimSpace(req.TrackName)),
strings.ToLower(strings.TrimSpace(req.ArtistName)),
}, "\n")
}
func prunePreparedDownloadRequestsLocked(now time.Time) {
for itemID, entry := range preparedDownloadRequests {
if now.Sub(entry.createdAt) >= downloadPreparationCacheTTL {
delete(preparedDownloadRequests, itemID)
}
}
for len(preparedDownloadRequests) >= downloadPreparationCacheMax {
var oldestID string
var oldestAt time.Time
for itemID, entry := range preparedDownloadRequests {
if oldestID == "" || entry.createdAt.Before(oldestAt) {
oldestID = itemID
oldestAt = entry.createdAt
}
}
if oldestID == "" {
break
}
delete(preparedDownloadRequests, oldestID)
}
}
func cacheDownloadRequestForVerification(key string, req DownloadRequest, metadataPrepared bool) {
itemID := strings.TrimSpace(req.ItemID)
if itemID == "" || strings.TrimSpace(key) == "" {
return
}
preparedDownloadRequestsMu.Lock()
defer preparedDownloadRequestsMu.Unlock()
now := time.Now()
prunePreparedDownloadRequestsLocked(now)
preparedDownloadRequests[itemID] = preparedDownloadRequestEntry{
key: key,
request: req,
metadataPrepared: metadataPrepared,
createdAt: now,
}
}
func cachePreparedDownloadRequest(key string, req DownloadRequest) {
cacheDownloadRequestForVerification(key, req, true)
}
func cacheUnpreparedDownloadRequest(key string, req DownloadRequest) {
cacheDownloadRequestForVerification(key, req, false)
}
func takePreparedDownloadRequest(key string, fresh DownloadRequest) (DownloadRequest, bool, bool) {
itemID := strings.TrimSpace(fresh.ItemID)
if itemID == "" || strings.TrimSpace(key) == "" {
return fresh, false, false
}
preparedDownloadRequestsMu.Lock()
defer preparedDownloadRequestsMu.Unlock()
now := time.Now()
prunePreparedDownloadRequestsLocked(now)
entry, ok := preparedDownloadRequests[itemID]
if !ok {
return fresh, false, false
}
delete(preparedDownloadRequests, itemID)
if entry.key != key {
return fresh, false, false
}
prepared := entry.request
fresh.ISRC = prepared.ISRC
fresh.SpotifyID = prepared.SpotifyID
fresh.TrackName = prepared.TrackName
fresh.ArtistName = prepared.ArtistName
fresh.AlbumName = prepared.AlbumName
fresh.AlbumArtist = prepared.AlbumArtist
fresh.CoverURL = prepared.CoverURL
fresh.TrackNumber = prepared.TrackNumber
fresh.DiscNumber = prepared.DiscNumber
fresh.TotalTracks = prepared.TotalTracks
fresh.TotalDiscs = prepared.TotalDiscs
fresh.ReleaseDate = prepared.ReleaseDate
fresh.DurationMS = prepared.DurationMS
fresh.Genre = prepared.Genre
fresh.Label = prepared.Label
fresh.Copyright = prepared.Copyright
fresh.Composer = prepared.Composer
fresh.TidalID = prepared.TidalID
fresh.QobuzID = prepared.QobuzID
fresh.DeezerID = prepared.DeezerID
return fresh, entry.metadataPrepared, true
}