quintodrome/core/artwork
Deluan Quintão acd69f6a4f
feat(playlist): support #EXTALBUMARTURL directive and sidecar images (#5131)
* feat(playlist): add migration for playlist image field rename and external URL

* refactor(playlist): rename ImageFile to UploadedImage and ArtworkPath to UploadedImagePath

Rename playlist model fields and methods for clarity in preparation for
adding external image URL and sidecar image support. Add the new
ExternalImageURL field to the Playlist model.

* feat(playlist): parse #EXTALBUMARTURL directive in M3U imports

* feat(playlist): always sync ExternalImageURL on re-scan, preserve UploadedImage

* feat(artwork): add sidecar image discovery and cache invalidation for playlists

Add playlist sidecar image support to the artwork reader fallback chain.
A sidecar image (e.g., MyPlaylist.jpg next to MyPlaylist.m3u) is discovered
via case-insensitive base name matching using model.IsImageFile(). Cache
invalidation uses max(playlist.UpdatedAt, imageFile.ModTime()) to bust
stale artwork when sidecar or ExternalImageURL local files change.

* feat(artwork): add external image URL source to playlist artwork reader

Add fromPlaylistExternalImage source function that resolves playlist
cover art from ExternalImageURL, supporting both HTTP(S) URLs (via
the existing fromURL helper) and local file paths (via os.Open).
Insert it in the Reader() fallback chain between sidecar and tiled cover.

* refactor(artwork): simplify playlist artwork source functions

Extract shared fromLocalFile helper, use url.Parse for scheme check,
and collapse sidecar directory scan conditions.

* test(artwork): remove redundant fromPlaylistSidecar tests

These tests duplicated scenarios already covered by findPlaylistSidecarPath
tests combined with fromLocalFile (tested via fromPlaylistExternalImage).
After refactoring fromPlaylistSidecar to a one-liner composing those two
functions, the wrapper tests add no value.

* fix(playlist): address security review comments from PR #5131:

- Use url.PathUnescape instead of url.QueryUnescape for file:// URLs so
  that '+' in filenames is preserved (not decoded as space).
- Validate all local image paths (file://, absolute, relative) against
  known library boundaries via libraryMatcher, rejecting paths outside
  any configured library.
- Harden #EXTALBUMARTURL against path traversal and SSRF by adding EnableM3UExternalAlbumArt config flag (default false, also
  disabled by EnableExternalServices=false) to gate HTTP(S) URL storage
  at parse time and fetching at read time (defense in depth).
- Log a warning when os.ReadDir fails in findPlaylistSidecarPath for
  diagnosability.
- Extract resolveLocalPath helper to simplify resolveImageURL.

Signed-off-by: Deluan <deluan@navidrome.org>

* feat(playlist): implement human-friendly filename generation for uploaded playlist cover images

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
2026-03-02 11:39:59 -05:00
..
artwork.go test: fix ignored artwork tests (#4103) 2025-05-22 15:48:24 -04:00
artwork_internal_test.go feat(playlist): support #EXTALBUMARTURL directive and sidecar images (#5131) 2026-03-02 11:39:59 -05:00
artwork_suite_test.go Fix tests and clean up code a bit 2022-12-28 15:31:56 -05:00
artwork_test.go Fix image stuttering (#3035) 2024-05-24 20:19:26 -04:00
cache_warmer.go feat: Multi-library support (#4181) 2025-07-18 18:41:12 -04:00
cache_warmer_test.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
image_cache.go Add lastUpdated to coverArt ids. Helps with invalidating art cache client-side. 2023-02-08 20:03:31 -05:00
reader_album.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
reader_album_test.go fix(server): prefer cover.jpg over cover.1.jpg (#4684) 2025-11-14 12:19:10 -05:00
reader_artist.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
reader_artist_test.go fix(server): prioritize artist base image filenames over numeric suffixes and add tests for sorting 2025-11-14 13:15:50 -05:00
reader_mediafile.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
reader_playlist.go feat(playlist): support #EXTALBUMARTURL directive and sidecar images (#5131) 2026-03-02 11:39:59 -05:00
reader_resized.go fix(artwork): clamp requested square size to original dimensions for cover art, to avoid upscaling 2026-01-28 12:46:46 -05:00
sources.go chore(deps): bump golangci-lint to v2.10.0 and suppress new gosec false positives 2026-02-17 09:28:42 -05:00
wire_providers.go Handle "naked" CoverArtIDs (IDs of album, mediafiles and playlists) 2022-12-28 15:31:56 -05:00