mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-14 19:20:37 +03:00
When retrieving images from external sources, avoid calling it again if data is already cached locally.
Relates to https://github.com/navidrome/navidrome/issues/2130#issuecomment-1412742918
This commit is contained in:
parent
4a7e86e989
commit
f4b50c493c
@ -117,6 +117,7 @@ var (
|
|||||||
VariousArtists = "Various Artists"
|
VariousArtists = "Various Artists"
|
||||||
VariousArtistsID = fmt.Sprintf("%x", md5.Sum([]byte(strings.ToLower(VariousArtists))))
|
VariousArtistsID = fmt.Sprintf("%x", md5.Sum([]byte(strings.ToLower(VariousArtists))))
|
||||||
UnknownArtist = "[Unknown Artist]"
|
UnknownArtist = "[Unknown Artist]"
|
||||||
|
UnknownArtistID = fmt.Sprintf("%x", md5.Sum([]byte(strings.ToLower(UnknownArtist))))
|
||||||
VariousArtistsMbzId = "89ad4ac3-39f7-470e-963a-56509c546377"
|
VariousArtistsMbzId = "89ad4ac3-39f7-470e-963a-56509c546377"
|
||||||
|
|
||||||
ServerStart = time.Now()
|
ServerStart = time.Now()
|
||||||
|
@ -48,7 +48,15 @@ type cacheWarmer struct {
|
|||||||
wakeSignal chan struct{}
|
wakeSignal chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ignoredIds = map[string]struct{}{
|
||||||
|
consts.VariousArtistsID: {},
|
||||||
|
consts.UnknownArtistID: {},
|
||||||
|
}
|
||||||
|
|
||||||
func (a *cacheWarmer) PreCache(artID model.ArtworkID) {
|
func (a *cacheWarmer) PreCache(artID model.ArtworkID) {
|
||||||
|
if _, shouldIgnore := ignoredIds[artID.ID]; shouldIgnore {
|
||||||
|
return
|
||||||
|
}
|
||||||
a.mutex.Lock()
|
a.mutex.Lock()
|
||||||
defer a.mutex.Unlock()
|
defer a.mutex.Unlock()
|
||||||
a.buffer[artID] = struct{}{}
|
a.buffer[artID] = struct{}{}
|
||||||
|
@ -42,7 +42,9 @@ func newArtistReader(ctx context.Context, artwork *artwork, artID model.ArtworkI
|
|||||||
em: em,
|
em: em,
|
||||||
artist: *ar,
|
artist: *ar,
|
||||||
}
|
}
|
||||||
a.cacheKey.lastUpdate = ar.ExternalInfoUpdatedAt
|
// TODO Find a way to factor in the ExternalUpdateInfoAt in the cache key. Problem is that it can
|
||||||
|
// change _after_ retrieving from external sources, making the key invalid
|
||||||
|
//a.cacheKey.lastUpdate = ar.ExternalInfoUpdatedAt
|
||||||
var files []string
|
var files []string
|
||||||
var paths []string
|
var paths []string
|
||||||
for _, al := range als {
|
for _, al := range als {
|
||||||
@ -64,10 +66,10 @@ func newArtistReader(ctx context.Context, artwork *artwork, artID model.ArtworkI
|
|||||||
func (a *artistReader) Key() string {
|
func (a *artistReader) Key() string {
|
||||||
hash := md5.Sum([]byte(conf.Server.Agents + conf.Server.Spotify.ID))
|
hash := md5.Sum([]byte(conf.Server.Agents + conf.Server.Spotify.ID))
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s.%x.%t ",
|
"%s.%t.%x",
|
||||||
a.cacheKey.Key(),
|
a.cacheKey.Key(),
|
||||||
hash,
|
|
||||||
conf.Server.EnableExternalServices,
|
conf.Server.EnableExternalServices,
|
||||||
|
hash,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +180,16 @@ func clearName(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *externalMetadata) UpdateArtistInfo(ctx context.Context, id string, similarCount int, includeNotPresent bool) (*model.Artist, error) {
|
func (e *externalMetadata) UpdateArtistInfo(ctx context.Context, id string, similarCount int, includeNotPresent bool) (*model.Artist, error) {
|
||||||
|
artist, err := e.refreshArtistInfo(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.loadSimilar(ctx, artist, similarCount, includeNotPresent)
|
||||||
|
return &artist.Artist, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *externalMetadata) refreshArtistInfo(ctx context.Context, id string) (*auxArtist, error) {
|
||||||
artist, err := e.getArtist(ctx, id)
|
artist, err := e.getArtist(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -188,30 +198,28 @@ func (e *externalMetadata) UpdateArtistInfo(ctx context.Context, id string, simi
|
|||||||
// If we don't have any info, retrieves it now
|
// If we don't have any info, retrieves it now
|
||||||
if artist.ExternalInfoUpdatedAt.IsZero() {
|
if artist.ExternalInfoUpdatedAt.IsZero() {
|
||||||
log.Debug(ctx, "ArtistInfo not cached. Retrieving it now", "updatedAt", artist.ExternalInfoUpdatedAt, "id", id, "name", artist.Name)
|
log.Debug(ctx, "ArtistInfo not cached. Retrieving it now", "updatedAt", artist.ExternalInfoUpdatedAt, "id", id, "name", artist.Name)
|
||||||
err = e.refreshArtistInfo(ctx, artist)
|
err := e.populateArtistInfo(ctx, artist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If info is expired, trigger a refresh in the background
|
// If info is expired, trigger a populateArtistInfo in the background
|
||||||
if time.Since(artist.ExternalInfoUpdatedAt) > consts.ArtistInfoTimeToLive {
|
if time.Since(artist.ExternalInfoUpdatedAt) > consts.ArtistInfoTimeToLive {
|
||||||
log.Debug("Found expired cached ArtistInfo, refreshing in the background", "updatedAt", artist.ExternalInfoUpdatedAt, "name", artist.Name)
|
log.Debug("Found expired cached ArtistInfo, refreshing in the background", "updatedAt", artist.ExternalInfoUpdatedAt, "name", artist.Name)
|
||||||
go func() {
|
go func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
err := e.refreshArtistInfo(ctx, artist)
|
err := e.populateArtistInfo(ctx, artist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error refreshing ArtistInfo", "id", id, "name", artist.Name, err)
|
log.Error("Error refreshing ArtistInfo", "id", id, "name", artist.Name, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
return artist, nil
|
||||||
err = e.loadSimilar(ctx, artist, similarCount, includeNotPresent)
|
|
||||||
return &artist.Artist, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *externalMetadata) refreshArtistInfo(ctx context.Context, artist *auxArtist) error {
|
func (e *externalMetadata) populateArtistInfo(ctx context.Context, artist *auxArtist) error {
|
||||||
// Get MBID first, if it is not yet available
|
// Get MBID first, if it is not yet available
|
||||||
if artist.MbzArtistID == "" {
|
if artist.MbzArtistID == "" {
|
||||||
mbid, err := e.ag.GetArtistMBID(ctx, artist.ID, artist.Name)
|
mbid, err := e.ag.GetArtistMBID(ctx, artist.ID, artist.Name)
|
||||||
@ -314,12 +322,11 @@ func (e *externalMetadata) SimilarSongs(ctx context.Context, id string, count in
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *externalMetadata) ArtistImage(ctx context.Context, id string) (*url.URL, error) {
|
func (e *externalMetadata) ArtistImage(ctx context.Context, id string) (*url.URL, error) {
|
||||||
artist, err := e.getArtist(ctx, id)
|
artist, err := e.refreshArtistInfo(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.callGetImage(ctx, e.ag, artist)
|
|
||||||
if utils.IsCtxDone(ctx) {
|
if utils.IsCtxDone(ctx) {
|
||||||
log.Warn(ctx, "ArtistImage call canceled", ctx.Err())
|
log.Warn(ctx, "ArtistImage call canceled", ctx.Err())
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user