From e79564caa21c9a7e879fa29a459f5d54982929a9 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 15:51:36 +0200 Subject: [PATCH 1/6] chore: drop KOITO_FETCH_IMAGES_DURING_IMPORT It's better to have fast import and backfill images after it. --- .../content/docs/reference/configuration.md | 5 -- internal/cfg/cfg.go | 68 ++++++++++--------- internal/cfg/getters.go | 6 -- internal/importer/lastfm.go | 2 +- internal/importer/listenbrainz.go | 2 +- internal/importer/maloja.go | 2 +- internal/importer/spotify.go | 2 +- 7 files changed, 39 insertions(+), 48 deletions(-) diff --git a/docs/src/content/docs/reference/configuration.md b/docs/src/content/docs/reference/configuration.md index 4b28ad44..cc990026 100644 --- a/docs/src/content/docs/reference/configuration.md +++ b/docs/src/content/docs/reference/configuration.md @@ -145,11 +145,6 @@ If the environment variable is defined without **and** with the suffix at the sa - Description: A unix timestamp. If an imported listen has a timestamp before this, it will be discarded. -##### KOITO_FETCH_IMAGES_DURING_IMPORT - -- Default: `false` -- Description: When true, images will be downloaded and cached during imports. - ##### KOITO_CORS_ALLOWED_ORIGINS - Default: No CORS policy diff --git a/internal/cfg/cfg.go b/internal/cfg/cfg.go index 57353e96..b0a7ef12 100644 --- a/internal/cfg/cfg.go +++ b/internal/cfg/cfg.go @@ -57,38 +57,37 @@ type config struct { listenPort int configDir string // baseUrl string - sqliteEnabled bool - databaseUrl string - musicBrainzUrl string - musicBrainzRateLimit int - logLevel int - structuredLogging bool - lbzRelayEnabled bool - lbzRelayUrl string - lbzRelayToken string - defaultPw string - defaultUsername string - defaultTheme string - disableDeezer bool - disableCAA bool - disableMusicBrainz bool - subsonicUrl string - subsonicParams string - lastfmApiKey string - subsonicEnabled bool - skipImport bool - fetchImageDuringImport bool - allowedHosts []string - allowAllHosts bool - allowedOrigins []string - disableRateLimit bool - importThrottleMs int - userAgent string - importBefore time.Time - importAfter time.Time - artistSeparators []*regexp.Regexp - loginGate bool - forceTZ *time.Location + sqliteEnabled bool + databaseUrl string + musicBrainzUrl string + musicBrainzRateLimit int + logLevel int + structuredLogging bool + lbzRelayEnabled bool + lbzRelayUrl string + lbzRelayToken string + defaultPw string + defaultUsername string + defaultTheme string + disableDeezer bool + disableCAA bool + disableMusicBrainz bool + subsonicUrl string + subsonicParams string + lastfmApiKey string + subsonicEnabled bool + skipImport bool + allowedHosts []string + allowAllHosts bool + allowedOrigins []string + disableRateLimit bool + importThrottleMs int + userAgent string + importBefore time.Time + importAfter time.Time + artistSeparators []*regexp.Regexp + loginGate bool + forceTZ *time.Location } var ( @@ -163,7 +162,10 @@ func loadConfig(getenv func(string) string, version string) (*config, error) { cfg.disableRateLimit = parseBool(getenv(DISABLE_RATE_LIMIT_ENV)) cfg.structuredLogging = parseBool(getenv(ENABLE_STRUCTURED_LOGGING_ENV)) - cfg.fetchImageDuringImport = parseBool(getenv(FETCH_IMAGES_DURING_IMPORT_ENV)) + fetchImageDuringImport := getenv(FETCH_IMAGES_DURING_IMPORT_ENV) + if fetchImageDuringImport != "" { + return nil, fmt.Errorf(`loadConfig: %s has no effect. Images are always fetched after import`, FETCH_IMAGES_DURING_IMPORT_ENV) + } cfg.disableDeezer = parseBool(getenv(DISABLE_DEEZER_ENV)) cfg.disableCAA = parseBool(getenv(DISABLE_COVER_ART_ARCHIVE_ENV)) diff --git a/internal/cfg/getters.go b/internal/cfg/getters.go index b095ea68..1d911b48 100644 --- a/internal/cfg/getters.go +++ b/internal/cfg/getters.go @@ -181,12 +181,6 @@ func ImportWindow() (time.Time, time.Time) { return globalConfig.importBefore, globalConfig.importAfter } -func FetchImagesDuringImport() bool { - lock.RLock() - defer lock.RUnlock() - return globalConfig.fetchImageDuringImport -} - func ArtistSeparators() []*regexp.Regexp { lock.RLock() defer lock.RUnlock() diff --git a/internal/importer/lastfm.go b/internal/importer/lastfm.go index f5abcbd2..25e15aaa 100644 --- a/internal/importer/lastfm.go +++ b/internal/importer/lastfm.go @@ -116,7 +116,7 @@ func ImportLastFMFile(ctx context.Context, store importStore, mbzc mbz.MusicBrai Client: "lastfm", Time: ts, UserID: 1, - SkipCacheImage: !cfg.FetchImagesDuringImport(), + SkipCacheImage: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/listenbrainz.go b/internal/importer/listenbrainz.go index e089b34d..138b1076 100644 --- a/internal/importer/listenbrainz.go +++ b/internal/importer/listenbrainz.go @@ -153,7 +153,7 @@ func ImportListenBrainzFile(ctx context.Context, store importStore, mbzc mbz.Mus Time: ts, UserID: 1, Client: client, - SkipCacheImage: !cfg.FetchImagesDuringImport(), + SkipCacheImage: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/maloja.go b/internal/importer/maloja.go index 99122266..87c9b5f7 100644 --- a/internal/importer/maloja.go +++ b/internal/importer/maloja.go @@ -79,7 +79,7 @@ func ImportMalojaFile(ctx context.Context, store importStore, mbzc mbz.MusicBrai Time: ts.Local(), Client: "maloja", UserID: 1, - SkipCacheImage: !cfg.FetchImagesDuringImport(), + SkipCacheImage: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/spotify.go b/internal/importer/spotify.go index 9aaa4f59..cdd308d6 100644 --- a/internal/importer/spotify.go +++ b/internal/importer/spotify.go @@ -66,7 +66,7 @@ func ImportSpotifyFile(ctx context.Context, store importStore, mbzc mbz.MusicBra Time: item.Timestamp, Client: "spotify", UserID: 1, - SkipCacheImage: !cfg.FetchImagesDuringImport(), + SkipCacheImage: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { From 7020b138feca1aadb6440911cdd29d9b336bc580 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 16:00:52 +0200 Subject: [PATCH 2/6] chore: fix var shadowing --- internal/catalog/associate_album.go | 10 ++++------ internal/catalog/associate_artists.go | 15 ++++++--------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/internal/catalog/associate_album.go b/internal/catalog/associate_album.go index c5651688..6c8bfae4 100644 --- a/internal/catalog/associate_album.go +++ b/internal/catalog/associate_album.go @@ -133,9 +133,8 @@ func createOrUpdateAlbumWithMbzReleaseID(ctx context.Context, d db.AlbumStore, o imgid = uuid.New() if !opts.SkipCacheImage { l.Debug().Msg("Downloading album image from source...") - err = imagecache.DownloadImage(imgid, imgUrl) - if err != nil { - l.Err(err).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") + if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { + l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") } } } @@ -219,9 +218,8 @@ func matchAlbumByTitle(ctx context.Context, d db.AlbumStore, opts AssociateAlbum imgid = uuid.New() if !opts.SkipCacheImage { l.Debug().Msg("Downloading album image from source...") - err = imagecache.DownloadImage(imgid, imgUrl) - if err != nil { - l.Err(err).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") + if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { + l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") } } } diff --git a/internal/catalog/associate_artists.go b/internal/catalog/associate_artists.go index c116e28b..2b691dce 100644 --- a/internal/catalog/associate_artists.go +++ b/internal/catalog/associate_artists.go @@ -134,9 +134,8 @@ func matchArtistsByMBIDMappings(ctx context.Context, d db.ArtistStore, opts Asso imgid = uuid.New() if !opts.SkipCacheImage { l.Debug().Msg("Downloading artist image from source...") - err = imagecache.DownloadImage(imgid, imgUrl) - if err != nil { - l.Err(err).Msg("Failed to cache image") + if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { + l.Err(dlErr).Msg("Failed to cache image") } } } else { @@ -247,9 +246,8 @@ func resolveAliasOrCreateArtist(ctx context.Context, mbzID uuid.UUID, names []st imgid = uuid.New() if !opts.SkipCacheImage { l.Debug().Msg("Downloading artist image from source...") - err = imagecache.DownloadImage(imgid, imgUrl) - if err != nil { - l.Err(err).Msg("Failed to cache image") + if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { + l.Err(dlErr).Msg("Failed to cache image") } } } else if err != nil { @@ -296,9 +294,8 @@ func matchArtistsByNames(ctx context.Context, names []string, existing []*models imgid = uuid.New() if !opts.SkipCacheImage { l.Debug().Msg("Downloading artist image from source...") - err = imagecache.DownloadImage(imgid, imgUrl) - if err != nil { - l.Err(err).Msg("Failed to cache image") + if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { + l.Err(dlErr).Msg("Failed to cache image") } } } else if err != nil { From 1e83d75bb1b979e509cf1c8b29edf9af380929c9 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 16:01:35 +0200 Subject: [PATCH 3/6] chore: fix lookup error reporting --- internal/catalog/associate_album.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/catalog/associate_album.go b/internal/catalog/associate_album.go index 6c8bfae4..31c2dc69 100644 --- a/internal/catalog/associate_album.go +++ b/internal/catalog/associate_album.go @@ -137,9 +137,7 @@ func createOrUpdateAlbumWithMbzReleaseID(ctx context.Context, d db.AlbumStore, o l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") } } - } - - if err != nil { + } else if err != nil { l.Debug().Msgf("createOrUpdateAlbumWithMbzReleaseID: failed to get album images for %s: %s", release.Title, err.Error()) } @@ -219,11 +217,10 @@ func matchAlbumByTitle(ctx context.Context, d db.AlbumStore, opts AssociateAlbum if !opts.SkipCacheImage { l.Debug().Msg("Downloading album image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { - l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") + l.Err(dlErr).Msg("matchAlbumByTitle: failed to cache image") } } - } - if err != nil { + } else if err != nil { l.Debug().AnErr("error", err).Msgf("matchAlbumByTitle: failed to get album images for %s", opts.ReleaseName) } From 8107c860ada70fb35fa9fd61050206953ebfac63 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 16:07:02 +0200 Subject: [PATCH 4/6] chore: rename SkipCacheImage --- internal/catalog/associate_album.go | 6 +++--- internal/catalog/associate_artists.go | 8 ++++---- internal/catalog/catalog.go | 20 ++++++++++---------- internal/importer/lastfm.go | 2 +- internal/importer/listenbrainz.go | 2 +- internal/importer/maloja.go | 18 +++++++++--------- internal/importer/spotify.go | 18 +++++++++--------- 7 files changed, 37 insertions(+), 37 deletions(-) diff --git a/internal/catalog/associate_album.go b/internal/catalog/associate_album.go index 31c2dc69..1d56766b 100644 --- a/internal/catalog/associate_album.go +++ b/internal/catalog/associate_album.go @@ -23,7 +23,7 @@ type AssociateAlbumOpts struct { ReleaseName string TrackName string // required Mbzc mbz.MusicBrainzCaller - SkipCacheImage bool + SkipImageLookup bool } func AssociateAlbum(ctx context.Context, d db.AlbumStore, opts AssociateAlbumOpts) (*models.Album, error) { @@ -131,7 +131,7 @@ func createOrUpdateAlbumWithMbzReleaseID(ctx context.Context, d db.AlbumStore, o if err == nil && imgUrl != "" { imgid = uuid.New() - if !opts.SkipCacheImage { + if !opts.SkipImageLookup { l.Debug().Msg("Downloading album image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") @@ -214,7 +214,7 @@ func matchAlbumByTitle(ctx context.Context, d db.AlbumStore, opts AssociateAlbum }) if err == nil && imgUrl != "" { imgid = uuid.New() - if !opts.SkipCacheImage { + if !opts.SkipImageLookup { l.Debug().Msg("Downloading album image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("matchAlbumByTitle: failed to cache image") diff --git a/internal/catalog/associate_artists.go b/internal/catalog/associate_artists.go index 2b691dce..5efe1725 100644 --- a/internal/catalog/associate_artists.go +++ b/internal/catalog/associate_artists.go @@ -25,7 +25,7 @@ type AssociateArtistsOpts struct { TrackTitle string Mbzc mbz.MusicBrainzCaller - SkipCacheImage bool + SkipImageLookup bool } func AssociateArtists(ctx context.Context, d db.ArtistStore, opts AssociateArtistsOpts) ([]*models.Artist, error) { @@ -132,7 +132,7 @@ func matchArtistsByMBIDMappings(ctx context.Context, d db.ArtistStore, opts Asso }) if imgErr == nil && imgUrl != "" { imgid = uuid.New() - if !opts.SkipCacheImage { + if !opts.SkipImageLookup { l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") @@ -244,7 +244,7 @@ func resolveAliasOrCreateArtist(ctx context.Context, mbzID uuid.UUID, names []st }) if err == nil && imgUrl != "" { imgid = uuid.New() - if !opts.SkipCacheImage { + if !opts.SkipImageLookup { l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") @@ -292,7 +292,7 @@ func matchArtistsByNames(ctx context.Context, names []string, existing []*models }) if err == nil && imgUrl != "" { imgid = uuid.New() - if !opts.SkipCacheImage { + if !opts.SkipImageLookup { l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") diff --git a/internal/catalog/catalog.go b/internal/catalog/catalog.go index 6ca8f038..dc3e4ed4 100644 --- a/internal/catalog/catalog.go +++ b/internal/catalog/catalog.go @@ -42,8 +42,8 @@ type SubmitListenOpts struct { // artist, release, release group, and track in DB SkipSaveListen bool - // When true, skips caching the images and only stores the image url in the db - SkipCacheImage bool + // When true, skips requests for album and artist images + SkipImageLookup bool MbzCaller mbz.MusicBrainzCaller ArtistNames []string @@ -88,13 +88,13 @@ func SubmitListen(ctx context.Context, store submitListenStore, opts SubmitListe ctx, store, AssociateArtistsOpts{ - ArtistMbzIDs: opts.ArtistMbzIDs, - ArtistNames: opts.ArtistNames, - ArtistName: opts.Artist, - ArtistMbidMap: opts.ArtistMbidMappings, - Mbzc: opts.MbzCaller, - TrackTitle: opts.TrackTitle, - SkipCacheImage: opts.SkipCacheImage, + ArtistMbzIDs: opts.ArtistMbzIDs, + ArtistNames: opts.ArtistNames, + ArtistName: opts.Artist, + ArtistMbidMap: opts.ArtistMbidMappings, + Mbzc: opts.MbzCaller, + TrackTitle: opts.TrackTitle, + SkipImageLookup: opts.SkipImageLookup, }) if err != nil { l.Err(err).Msg("Failed to associate artists to listen") @@ -116,7 +116,7 @@ func SubmitListen(ctx context.Context, store submitListenStore, opts SubmitListe TrackName: opts.TrackTitle, Mbzc: opts.MbzCaller, Artists: artists, - SkipCacheImage: opts.SkipCacheImage, + SkipImageLookup: opts.SkipImageLookup, }) if err != nil { l.Error().Err(err).Msg("Failed to associate release group to listen") diff --git a/internal/importer/lastfm.go b/internal/importer/lastfm.go index 25e15aaa..e1afb703 100644 --- a/internal/importer/lastfm.go +++ b/internal/importer/lastfm.go @@ -116,7 +116,7 @@ func ImportLastFMFile(ctx context.Context, store importStore, mbzc mbz.MusicBrai Client: "lastfm", Time: ts, UserID: 1, - SkipCacheImage: true, + SkipImageLookup: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/listenbrainz.go b/internal/importer/listenbrainz.go index 138b1076..8aa91940 100644 --- a/internal/importer/listenbrainz.go +++ b/internal/importer/listenbrainz.go @@ -153,7 +153,7 @@ func ImportListenBrainzFile(ctx context.Context, store importStore, mbzc mbz.Mus Time: ts, UserID: 1, Client: client, - SkipCacheImage: true, + SkipImageLookup: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/maloja.go b/internal/importer/maloja.go index 87c9b5f7..74c5fbf8 100644 --- a/internal/importer/maloja.go +++ b/internal/importer/maloja.go @@ -71,15 +71,15 @@ func ImportMalojaFile(ctx context.Context, store importStore, mbzc mbz.MusicBrai continue } opts := catalog.SubmitListenOpts{ - MbzCaller: mbzc, - Artist: item.Track.Artists[0], - ArtistNames: artists, - TrackTitle: item.Track.Title, - ReleaseTitle: item.Track.Album.Title, - Time: ts.Local(), - Client: "maloja", - UserID: 1, - SkipCacheImage: true, + MbzCaller: mbzc, + Artist: item.Track.Artists[0], + ArtistNames: artists, + TrackTitle: item.Track.Title, + ReleaseTitle: item.Track.Album.Title, + Time: ts.Local(), + Client: "maloja", + UserID: 1, + SkipImageLookup: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { diff --git a/internal/importer/spotify.go b/internal/importer/spotify.go index cdd308d6..8f943652 100644 --- a/internal/importer/spotify.go +++ b/internal/importer/spotify.go @@ -58,15 +58,15 @@ func ImportSpotifyFile(ctx context.Context, store importStore, mbzc mbz.MusicBra continue } opts := catalog.SubmitListenOpts{ - MbzCaller: mbzc, - Artist: item.ArtistName, - TrackTitle: item.TrackName, - ReleaseTitle: item.AlbumName, - Duration: dur / 1000, - Time: item.Timestamp, - Client: "spotify", - UserID: 1, - SkipCacheImage: true, + MbzCaller: mbzc, + Artist: item.ArtistName, + TrackTitle: item.TrackName, + ReleaseTitle: item.AlbumName, + Duration: dur / 1000, + Time: item.Timestamp, + Client: "spotify", + UserID: 1, + SkipImageLookup: true, } err = catalog.SubmitListen(ctx, store, opts) if err != nil { From 47a0a62a3ee01104dca0b9d85e10e8a85bebe447 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 16:07:10 +0200 Subject: [PATCH 5/6] fix: don't fetch images on import We should avoid doing any image requests when importing. --- internal/catalog/associate_album.go | 47 ++++++++++++----------- internal/catalog/associate_artists.go | 54 +++++++++++++++------------ 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/internal/catalog/associate_album.go b/internal/catalog/associate_album.go index 1d56766b..3de160c6 100644 --- a/internal/catalog/associate_album.go +++ b/internal/catalog/associate_album.go @@ -121,24 +121,25 @@ func createOrUpdateAlbumWithMbzReleaseID(ctx context.Context, d db.AlbumStore, o } } - l.Debug().Msg("Searching for album images...") var imgid uuid.UUID - imgUrl, err := images.GetAlbumImage(ctx, images.AlbumImageOpts{ - Artists: utils.UniqueIgnoringCase(slices.Concat(utils.FlattenMbzArtistCreditNames(release.ArtistCredit), utils.FlattenArtistNames(opts.Artists))), - Album: release.Title, - ReleaseMbzID: &opts.ReleaseMbzID, - }) - - if err == nil && imgUrl != "" { - imgid = uuid.New() - if !opts.SkipImageLookup { + var imgUrl string + if !opts.SkipImageLookup { + l.Debug().Msg("Searching for album images...") + var imgErr error + imgUrl, imgErr = images.GetAlbumImage(ctx, images.AlbumImageOpts{ + Artists: utils.UniqueIgnoringCase(slices.Concat(utils.FlattenMbzArtistCreditNames(release.ArtistCredit), utils.FlattenArtistNames(opts.Artists))), + Album: release.Title, + ReleaseMbzID: &opts.ReleaseMbzID, + }) + if imgErr == nil && imgUrl != "" { + imgid = uuid.New() l.Debug().Msg("Downloading album image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("createOrUpdateAlbumWithMbzReleaseID: failed to cache image") } + } else if imgErr != nil { + l.Debug().Msgf("createOrUpdateAlbumWithMbzReleaseID: failed to get album images for %s: %s", release.Title, imgErr.Error()) } - } else if err != nil { - l.Debug().Msgf("createOrUpdateAlbumWithMbzReleaseID: failed to get album images for %s: %s", release.Title, err.Error()) } album, err = d.SaveAlbum(ctx, db.SaveAlbumOpts{ @@ -207,21 +208,23 @@ func matchAlbumByTitle(ctx context.Context, d db.AlbumStore, opts AssociateAlbum return nil, fmt.Errorf("matchAlbumByTitle: %w", err) } else { var imgid uuid.UUID - imgUrl, err := images.GetAlbumImage(ctx, images.AlbumImageOpts{ - Artists: utils.FlattenArtistNames(opts.Artists), - Album: opts.ReleaseName, - ReleaseMbzID: &opts.ReleaseMbzID, - }) - if err == nil && imgUrl != "" { - imgid = uuid.New() - if !opts.SkipImageLookup { + var imgUrl string + if !opts.SkipImageLookup { + var imgErr error + imgUrl, imgErr = images.GetAlbumImage(ctx, images.AlbumImageOpts{ + Artists: utils.FlattenArtistNames(opts.Artists), + Album: opts.ReleaseName, + ReleaseMbzID: &opts.ReleaseMbzID, + }) + if imgErr == nil && imgUrl != "" { + imgid = uuid.New() l.Debug().Msg("Downloading album image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("matchAlbumByTitle: failed to cache image") } + } else if imgErr != nil { + l.Debug().AnErr("error", imgErr).Msgf("matchAlbumByTitle: failed to get album images for %s", opts.ReleaseName) } - } else if err != nil { - l.Debug().AnErr("error", err).Msgf("matchAlbumByTitle: failed to get album images for %s", opts.ReleaseName) } a, err = d.SaveAlbum(ctx, db.SaveAlbumOpts{ diff --git a/internal/catalog/associate_artists.go b/internal/catalog/associate_artists.go index 5efe1725..61b99748 100644 --- a/internal/catalog/associate_artists.go +++ b/internal/catalog/associate_artists.go @@ -127,19 +127,21 @@ func matchArtistsByMBIDMappings(ctx context.Context, d db.ArtistStore, opts Asso l.Warn().AnErr("error", err).Msg("matchArtistsByMBIDMappings: MusicBrainz unreachable, creating new artist with provided MusicBrainz ID mapping") var imgid uuid.UUID - imgUrl, imgErr := images.GetArtistImage(ctx, images.ArtistImageOpts{ - Aliases: []string{a.Artist}, - }) - if imgErr == nil && imgUrl != "" { - imgid = uuid.New() - if !opts.SkipImageLookup { + var imgUrl string + if !opts.SkipImageLookup { + var imgErr error + imgUrl, imgErr = images.GetArtistImage(ctx, images.ArtistImageOpts{ + Aliases: []string{a.Artist}, + }) + if imgErr == nil && imgUrl != "" { + imgid = uuid.New() l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") } + } else { + l.Err(imgErr).Msgf("matchArtistsByMBIDMappings: Failed to get artist image for artist '%s'", a.Artist) } - } else { - l.Err(imgErr).Msgf("matchArtistsByMBIDMappings: Failed to get artist image for artist '%s'", a.Artist) } artist, err = d.SaveArtist(ctx, db.SaveArtistOpts{ @@ -239,19 +241,21 @@ func resolveAliasOrCreateArtist(ctx context.Context, mbzID uuid.UUID, names []st } var imgid uuid.UUID - imgUrl, err := images.GetArtistImage(ctx, images.ArtistImageOpts{ - Aliases: aliases, - }) - if err == nil && imgUrl != "" { - imgid = uuid.New() - if !opts.SkipImageLookup { + var imgUrl string + if !opts.SkipImageLookup { + var imgErr error + imgUrl, imgErr = images.GetArtistImage(ctx, images.ArtistImageOpts{ + Aliases: aliases, + }) + if imgErr == nil && imgUrl != "" { + imgid = uuid.New() l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") } + } else if imgErr != nil { + l.Warn().AnErr("error", imgErr).Msg("Failed to get artist image from ImageSrc") } - } else if err != nil { - l.Warn().AnErr("error", err).Msg("Failed to get artist image from ImageSrc") } u, err := d.SaveArtist(ctx, db.SaveArtistOpts{ @@ -287,19 +291,21 @@ func matchArtistsByNames(ctx context.Context, names []string, existing []*models } if errors.Is(err, db.ErrNotFound) { var imgid uuid.UUID - imgUrl, err := images.GetArtistImage(ctx, images.ArtistImageOpts{ - Aliases: []string{name}, - }) - if err == nil && imgUrl != "" { - imgid = uuid.New() - if !opts.SkipImageLookup { + var imgUrl string + if !opts.SkipImageLookup { + var imgErr error + imgUrl, imgErr = images.GetArtistImage(ctx, images.ArtistImageOpts{ + Aliases: []string{name}, + }) + if imgErr == nil && imgUrl != "" { + imgid = uuid.New() l.Debug().Msg("Downloading artist image from source...") if dlErr := imagecache.DownloadImage(imgid, imgUrl); dlErr != nil { l.Err(dlErr).Msg("Failed to cache image") } + } else if imgErr != nil { + l.Debug().AnErr("error", imgErr).Msgf("Failed to get artist images for %s", name) } - } else if err != nil { - l.Debug().AnErr("error", err).Msgf("Failed to get artist images for %s", name) } a, err = d.SaveArtist(ctx, db.SaveArtistOpts{Name: name, Image: imgid, ImageSrc: imgUrl}) if err != nil { From 5c68feda795dc1291103683e0ce7d6ada0eb0466 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Sun, 2 Aug 2026 16:29:59 +0200 Subject: [PATCH 6/6] chore: run backfill after importer We don't need to restart to kick it off. --- engine/engine.go | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/engine/engine.go b/engine/engine.go index fa02e021..ef344d7e 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -236,23 +236,33 @@ func Run( l.Info().Msg("Engine: Beginning startup tasks...") - l.Debug().Msg("Engine: Checking import configuration") - if !cfg.SkipImport() { - go func() { + go func() { + l.Info().Msg("Engine: Checking image cache migration status") + if err := catalog.MigrateImageCache(ctx, store); err != nil { + l.Err(err).Msg("Engine: Failed to migrate image cache") + } + l.Info().Msg("Engine: Pruning orphaned images") + if err := catalog.PruneOrphanedImages(ctx, store); err != nil { + l.Err(err).Msg("Engine: Failed to prune orphaned images") + } + + l.Debug().Msg("Engine: Checking import configuration") + if !cfg.SkipImport() { RunImporter(l, store, mbzC) - }() - } + } + + l.Info().Msg("Engine: Attempting to fetch missing artist images") + if err := catalog.FetchMissingArtistImages(ctx, store); err != nil { + l.Err(err).Msg("Engine: Failed to fetch missing artist images") + } + l.Info().Msg("Engine: Attempting to fetch missing album images") + if err := catalog.FetchMissingAlbumImages(ctx, store); err != nil { + l.Err(err).Msg("Engine: Failed to fetch missing album images") + } + }() - l.Info().Msg("Engine: Pruning orphaned images") - go catalog.PruneOrphanedImages(logger.NewContext(l), store) - l.Info().Msg("Engine: Checking image cache migration status") - go catalog.MigrateImageCache(logger.NewContext(l), store) l.Info().Msg("Engine: Running duration backfill task") go catalog.BackfillTrackDurationsFromMusicBrainz(ctx, store, mbzC) - l.Info().Msg("Engine: Attempting to fetch missing artist images") - go catalog.FetchMissingArtistImages(ctx, store) - l.Info().Msg("Engine: Attempting to fetch missing album images") - go catalog.FetchMissingAlbumImages(ctx, store) l.Info().Msg("Engine: Initialization finished") quit := make(chan os.Signal, 1)