// Package coverart finds and fetches album cover artwork. // // Two-layer model: a directory-walking sidecar lookup (cover.jpg / folder.jpg // next to the audio files) and a MusicBrainz Cover Art Archive (MBCAA) // fallback for albums with an MBID but no sidecar. The Enricher orchestrates // the two; the API and Subsonic packages reuse the sidecar helper directly. package coverart import ( "context" "os" "path/filepath" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // SidecarNames is the lookup order for cover art living next to audio files. // Matches common library conventions: cover.* wins over folder.*; JPEG wins // over PNG when both are present. var SidecarNames = []string{ "cover.jpg", "cover.jpeg", "cover.png", "folder.jpg", "folder.jpeg", "folder.png", } // FindSidecar returns the absolute path to a sidecar cover image in // albumDir, or "" when none of the conventional names are present as a // regular file. Directories named like sidecar files are skipped. func FindSidecar(albumDir string) string { for _, name := range SidecarNames { candidate := filepath.Join(albumDir, name) info, err := os.Stat(candidate) if err != nil || info.IsDir() { continue } return candidate } return "" } // ResolveAlbumPath returns the on-disk path to an album's cover image, // preferring the explicit album.cover_art_path when set and the file // exists, falling back to a sidecar (cover.jpg / folder.jpg) next to the // first track in the album's directory. "" means no art was found. // // Shared by internal/api/media.go (browser endpoint) and // internal/subsonic/stream.go (Subsonic endpoint); they were byte-identical // duplicates before extraction. func ResolveAlbumPath(ctx context.Context, q *dbq.Queries, album dbq.Album) string { if album.CoverArtPath != nil && *album.CoverArtPath != "" { if _, err := os.Stat(*album.CoverArtPath); err == nil { return *album.CoverArtPath } } tracks, err := q.ListTracksByAlbum(ctx, dbq.ListTracksByAlbumParams{AlbumID: album.ID}) if err != nil || len(tracks) == 0 { return "" } return FindSidecar(filepath.Dir(tracks[0].FilePath)) }