Skip to content

Alternative artwork/box set approach - #1536

Open
darrell-k wants to merge 10 commits into
LMS-Community:public/9.2from
darrell-k:artwork
Open

Alternative artwork/box set approach#1536
darrell-k wants to merge 10 commits into
LMS-Community:public/9.2from
darrell-k:artwork

Conversation

@darrell-k

@darrell-k darrell-k commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

Here is an alternative approach to #1513

It fixes a couple of existing new&changed artwork scanning problems including embedded artwork not being removed after being removed from the music file and issues I found with albums in multiple directories.

I've tried to implement the functionality of #1513 but I have not yet coded the "file/folder name to disc number" heuristics or the discsubtitle processing. But these should be relatively straightforward additions to the code structure in this PR.

I've also ensured that for box sets, if a particular disc doesn't have specific artwork, we fall back to the overall album artwork.

Needs much more testing, not just by me!

Comments please.

Signed-off-by: darrell-k <darrell@darrell.org.uk>
@darrell-k darrell-k mentioned this pull request Mar 16, 2026
@michaelherger

Copy link
Copy Markdown
Member

Copilot's thoughts (Concern #4 is what made me raise an eyebrow):

Concerns & Observations:

  1. Database query complexity - The SQL GROUP BY now includes dirname and tracks.disc, which could significantly change grouping behavior and potentially impact performance. This warrants testing with large libraries.

    GROUP BY tracks.cover, tracks.album, dirname, tracks.disc
  2. Unclear variable initialization - In updateStandaloneArtwork(), $newCover and $newAlbumCover are declared but not always initialized before use. This could lead to undefined behavior.

  3. Incomplete feature - As noted in the PR description, the "file/folder name to disc number" heuristics aren't implemented yet. This makes the current solution partially functional.

  4. CoveridGeneration refactoring - The changes to generateImageId() logic in Slim/Schema.pm and Slim/Schema/Track.pm distinguish between embedded vs. external artwork, which is good for deduplication. However, this logic is duplicated across two files—could be consolidated.

  5. Potential query performance issue - The new $sth_album_urls query executes for each album in the loop. Consider caching results or using a larger batch query to avoid N+1 queries.

  6. Edge case: empty parent artwork - When _findCommonParent() returns undef for multiple directory paths, the code sets $parentArtwork = undef and $parentArtworkId = undef. The downstream logic should clearly handle this case.

Testing Recommendations:

  • Box sets with multiple directories - Critical test case
  • Disc-specific artwork detection - Verify the naming patterns are recognized
  • Cache behavior - Ensure the new disc-specific caching doesn't cause memory issues
  • Performance - Run on a large library to catch any query bottlenecks
  • Embedded vs. external artwork - Verify the cover ID deduplication works correctly

Minor Issues:

  • Line in updateStandaloneArtwork(): The condition $urlDir ne dirname($cover) assumes $cover is always a valid file path—add safety checks.
  • Missing comments explaining the new $commonParent parameter's purpose in findStandaloneArtwork().

Overall, this is a thoughtful approach to a complex problem, but it would benefit from the noted refinements before merging.

@darrell-k

Copy link
Copy Markdown
Contributor Author

On the concerns:

  1. Definitely. But some performance hit is inevitable if we're going to go down this road.
  2. As I understand it, by declaring them at the top of the fetch loop, they're always starting of undef each time through, which is what we want. But I could declare them explicitly undef it that makes things clearer.
  3. Yes, it's just telling me what I already said!
  4. It's a simple enough if statement, but yes, why not consolidate it? I'll do this.
  5. A memory cache of all albums to be processed could be very large in updateStandaloneArtwork, smaller in precacheAllArtwork. We have an index on tracks.album so I suggest leaving it alone unless performance testing highlights any big problems.
  6. Would only happen if the user has an album split across different file systems. Though considering this has made me wonder how dirname() handles symbolic links. Having said that, _findCommonParent needlessly returns undef if called with a single path. I might change this so that it just returns the input parameter in that case - safer if someone in the future uses it a bit carelessly.

On testing:

Except for performance testing, I've tested the other stuff to the point of boredom, but I intend to do some more testing and it's a good checklist.

Given the almost infinite combinations of adding/removing/changing artwork both at the disc/track level and album parent level, we can only do our best.

Once we've verified performance is OK and it passes regression testing (ie current behaviour for the simple cases of changing artwork in a single album folder and embedded artwork) I'd suggest merging it to 9.2 for user feedback.

On minor issues:

$urlDir : the test is already protected by Slim::Music::Info::isFileURL($url).
Missing comments: yes that should be explained.

@mikeysas

Copy link
Copy Markdown

@darrell-k - happy to help testing when you are ready for that.

I have some test cases set up from before. I was testing with embedded artwork where I had one with artwork embedded that varied by disc and another with embedded artwork varied by Grouping all with the “box set” artwork as cover.jpg.

Signed-off-by: darrell-k <darrell@darrell.org.uk>
@darrell-k

darrell-k commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

@darrell-k - happy to help testing when you are ready for that.

I have some test cases set up from before. I was testing with embedded artwork where I had one with artwork embedded that varied by disc and another with embedded artwork varied by Grouping all with the “box set” artwork as cover.jpg.

Thanks for the offer.
Replace these files in your 9.2 installation

  • Slim/Control/Commands.pm
  • Slim/Music/Artwork.pm
  • Slim/Schema.pm
  • Slim/Schema/Track.pm

with the versions from my branch https://github.com/darrell-k/slimserver/tree/artwork

Start with a full rescan to ensure a good starting point. Then put the new & changed scan through its paces.

@darrell-k

Copy link
Copy Markdown
Contributor Author

@mikeysas I should have reminded you that discsubtitle matching and file name heuristics are not implemented yet. I'm working on it now.

Comment thread Slim/Music/Artwork.pm Outdated
Signed-off-by: darrell-k <darrell@darrell.org.uk>
@darrell-k

Copy link
Copy Markdown
Contributor Author

Initial performance tests show quite a hit (40 seconds combined for updateStandaloneArtwork and precacheArtwork combined for the 40,000 track test library, compared to 1 second for current 9.2!

I'll work on this tomorrow.

@mikeysas

Copy link
Copy Markdown

I saw this when testing the previous version also and suspect this needs to be addressed in Material....

NOTE:
cover.jpg
image

Embedded artwork in the first track
image

When you click on box set release from any of the browse menus or search results, it displays correctly:
image

When you click on the release name in the Now Playing screen or on the playlist queue note that the embedded artwork from first track displays on the top left:
image

@darrell-k

Copy link
Copy Markdown
Contributor Author

@mikeysas Yes, this can be resolved by Material sending an extra tag (J) in the tracks command and then using the returned album image id (which is confusingly called artwork_track_id).

There's a related issue: the artist shown in the album heading is the lead artist of the track, rather than the lead artist of the album. This will require an LMS change, and possibly another Material change, so I'll hold off creating a PR for Material until I've decided how to approach the LMS query amendment, which is probably going to need an extra join to the contributors table for the name.

@darrell-k

Copy link
Copy Markdown
Contributor Author

Initial performance tests show quite a hit (40 seconds combined for updateStandaloneArtwork and precacheArtwork combined for the 40,000 track test library, compared to 1 second for current 9.2!

I'll work on this tomorrow.

I've got it down to 5 seconds for this test case.

I conditioned a couple of SQL UPDATE statements to stop them being issued unnecessarily, but the big improvements are:

  • Just pass the track url & disc number to findStandaloneArtwork() rather than instantiating a Track instance. If the user has a wildcard image name preference, a Track will still be instantiated by Slim::Music::TitleFormatter::infoFormat() but no longer in other cases.
  • Process the album level artwork after all rows for an album have been fetched, rather than when we first see a new album. This allows us to build an array of album folder paths on the way through rather than hitting the database with an extra fetch for each album to get them.

I also tried replacing the dirname SQL grouping with Perl code, but it added a lot of complication and only saved 1 second. Turns out Sqlite is quite good at such things!

I'm going to look at whether similar efficiencies are useful in precacheAllArtwork() but pushing these changes now to allow review and testing of the new & changed scan.

@mikeysas please check I haven't broken anything with the latest changes if you get the chance. You only need to refresh your Slim/Music/Artwork.pm from my branch to pick up this change.

I also need to make sure I haven't broken online albums, and also test the async call from the main process.

Signed-off-by: darrell-k <darrell@darrell.org.uk>
@michaelherger

Copy link
Copy Markdown
Member

How did you profile? I've found NYTProf to be super helpful. Once you've installed it on your system you do:

perl -d:NYTProf slimserver.pl

[run a scan, then stop LMS - the data can be huge!]

nytprofhtml -f NYTProf/nytprof.out -o NYTProf/smallartwork --open

Which should give a web page where you can drill down to hot spots etc.

DBIx unfortunately is known to tend to be slow. You could avoid it in infoFormat() if you provided metadata known from the scan. I see that you sometimes do this. Maybe it would be worth using raw SQL to get it for the other cases, rather than rely on infoFormat. That really was intended to render title information of the currently playing track - which doesn't change often.

@darrell-k

Copy link
Copy Markdown
Contributor Author

Timings from the scan messages. Experimented by commenting out different bits of the code. As you say, the DBIx stuff was a prime suspect. Thanks for the tool recommendation, I'll try it out.

I'll look at further changes to ensure that DBIx is never used in findStandaloneArtwork().

@darrell-k

Copy link
Copy Markdown
Contributor Author

DBIx unfortunately is known to tend to be slow. You could avoid it in infoFormat() if you provided metadata known from the scan. I see that you sometimes do this. Maybe it would be worth using raw SQL to get it for the other cases, rather than rely on infoFormat. That really was intended to render title information of the currently playing track - which doesn't change often.

I've been struggling a bit with this, trying to create a compatible hash with raw SQL, but I just found that the variable artwork name stuff (I'm testing with an artwork format of %ARTIST - ALBUM) doesn't work in current 9.2 with the metadata hash provided by Slim::Music::Artwork::updateStandaloneArtwork:

[26-04-02 17:00:52.4029] Slim::Music::Artwork::findStandaloneArtwork (113) No variable cover Slim::Schema::Album=HASH(0x564720957b08).jpg found from ARTIST - ALBUM

Or am I missing something?

@michaelherger

Copy link
Copy Markdown
Member

The failure: is this with stock 9.2? And 9.1 would be correct? There aren't too many changes in 9.2 yet.

@darrell-k

Copy link
Copy Markdown
Contributor Author

I've examined the code and the source history. I can't see how the hash created in Slim::Music::Artwork::updateStandaloneArtwork can ever have worked for variable title format fields other than those in the tracks table since it was introduced 13 years ago!

I dumped the hash received by Slim::Music::TitleFormatter and the album columns are within an embedded Slim::Schema::Album object and I can't see the code ever having dealt with that. And artist/albumartist/trackartist/contributor.name are not there in any form.

@michaelherger

Copy link
Copy Markdown
Member

Are you saying that if I define ARTIST - ALBUM as the artwork pattern, then "Elvis - Love Me Tender.jpg" would never have been found?

@michaelherger

michaelherger commented Apr 3, 2026

Copy link
Copy Markdown
Member

Oh, is the answer in the code already?

# XXX This may break for some people as it's not using a Track object anymore

So this would have been broken for >16 years, for anyone trying to use more than just track title. The artist would not even be referenced in that data structure...

@michaelherger

Copy link
Copy Markdown
Member

Hmm... and it's different whether you run a full wipe & rescan, or just a rescan. In the former case we'd get a flattened $meta object, including artist information. In the latter we don't. So the good news is it is not consistent, working sometimes 😁. It depends on the caller. Maybe we should look into fixing them? I guess we did too many optimisations over the years, without paying much attention to this case.

@darrell-k

Copy link
Copy Markdown
Contributor Author

Yes, I can fix it now we've confirmed it is broken.

Signed-off-by: darrell-k <darrell@darrell.org.uk>
@darrell-k

Copy link
Copy Markdown
Contributor Author

See latest commit. I've coded direct SQL to build the necessary metadata for TitleFormatter and tried to introduce consistency in response to the findings above.

Not massively tested, and probably not the last word on the issue.

@darrell-k

Copy link
Copy Markdown
Contributor Author

@mikeysas Yes, this can be resolved by Material sending an extra tag (J) in the tracks command and then using the returned album image id (which is confusingly called artwork_track_id).

There's a related issue: the artist shown in the album heading is the lead artist of the track, rather than the lead artist of the album. This will require an LMS change, and possibly another Material change, so I'll hold off creating a PR for Material until I've decided how to approach the LMS query amendment, which is probably going to need an extra join to the contributors table for the name.

On the second issue, this has been resolved by recent LMS/Material changes.

This needs more testing, including now the title format fixes which do not apply when using Material.

@darrell-k
darrell-k marked this pull request as ready for review July 27, 2026 23:20
@michaelherger

Copy link
Copy Markdown
Member

Wow... had forgotten about this one, too. Is the performance hit still there? In order to prevent memory exhaustion caching DB queries in memory we use Tie::Cache::LRU and similar in some places. Could that be of help?

I'll hopefully find some time over the weekend to look into this, as I want to give it some testing, too.

@michaelherger michaelherger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I'm slow these days. Some more questions...

I'll try to run tests locally to see the performance impact. Just to make sure I get this right: this change mostly impacts the rescan, but not wipe & scan?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for all these changes in what seems unrelated to artwork? Are they to fix the custom artwork file name parsing or something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of removing track object instantiation and replacing with direct SQL, I tested titleFormatter, which is used in the artwork custom name processing.

As mentioned earlier in this thread I found it was broken so tried to fix and make consistent.

The multiple value/array question you raised below did cross my mind, too.

Comment thread Slim/Music/TitleFormatter.pm Outdated
Comment on lines +50 to +52
my $rtn = $_[0]->{ lc($attr) } || $_[0]->{ 'tracks.' . lc($attr) } || '';
utf8::decode($rtn);
return $rtn;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would Slim::Utils::Unicode::utf8on(...) do the trick to avoid the same repeated three lines?

return Slim::Utils::Unicode::utf8on($_[0]->{ lc($attr) } || $_[0]->{ 'tracks.' . lc($attr) } || '');

In order to avoid the repeated lengthy call you could define a local alias at the top of the file:

*utf8on = \&Slim::Utils::Unicode::utf8on;

Comment on lines +131 to +133
my $discc = $_[0]->{discc} || $_[0]->{'albums.discc'} || '';
# suppress disc counts of 1 or less
return ($discc && $discc > 1 ? $discc : '');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an opinionated change - which I'm ok with. But we need to keep in mind that some people might be surprised and not like it.

Applies to all the following disc related changes.

if ( ref $_[0] eq 'HASH' ) {
return $_[0]->{artist} || $_[0]->{albumartist} || $_[0]->{trackartist} || $_[0]->{'contributors.name'} || '';
my $artists = $_[0]->{artist} || $_[0]->{albumartist} || $_[0]->{trackartist} || $_[0]->{'contributors.name'} || '';
my $rtn = ref $artists && scalar @$artists ? join(' & ', @$artists) : $artists ? $artists : '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... this could potentially break things, right? We'd previously only return a single element, now we'd concatenate names? And concatenate them with a hard coded separator - when we have a pref for "split characters". Should we be using one of them instead? That's another opinionated change we'll have to defend.

Comment on lines 322 to 332
$parsedFormats{'VOLUME'} = sub {

my $url;
my $output = '';

if ( ref $_[0] eq 'HASH' ) {
return $_[0]->{volume} || '';
$url = $_[0]->{url} || $_[0]->{'tracks.url'};
}
else {
$url = $_[0]->get('url');
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh... that got me confused: what has the audio volume to do with a URL? 😉

More seriously: what is the newly introduced version getting from? What are you assuming is $_[0] there?


$output = (splitpath($url))[2];
$output =~ s/\.[^\.]*?$//;
$output = Slim::Utils::Misc::unescape($output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be done by pathFromFileURL already?

Comment thread Slim/Schema.pm
Comment on lines +1818 to 1828
# Generate coverid value based on artwork, mtime, filesize:
# if cover is embedded in the file (ie it's a number, the size of the embedded image) use the track URL,
# if cover is external use the URL of the image.
# This avoids generating multiple cover ids for the same image. I'm not sure if they would ever get cached
# because Slim::Music::Artwork would consolidate them, but this seems cleaner.
$columnValueHash{coverid} = Slim::Schema::Track->generateCoverId( {
cover => $columnValueHash{cover},
url => $url,
url => $columnValueHash{cover} =~ /^\d+$/ ? $url : Slim::Utils::Misc::fileURLFromPath($columnValueHash{cover}),
mtime => $columnValueHash{timestamp},
size => $columnValueHash{filesize},
} );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this the same as in Track.pm? If so: can we consolidate in to one helper? Or use Slim::Schema::Track::coverid here?

@michaelherger michaelherger Jul 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but we could call Slim::Music::Artwork->generateImageId() with almost the same parameters. And then have generateImageId() sort out the URL value? There actually already is a code branch dealing with the all numerical cover ID.

Comment thread Slim/Music/Artwork.pm
url => Slim::Utils::Misc::fileURLFromPath($parentArtwork),
}) || '';
$sth_update_albums->execute( $parentArtworkId, $albumid );
Slim::Utils::ImageResizer->resize($parentArtwork, "music/$parentArtworkId/cover_", join(',', @specs), undef);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slim::Utils::ImageResizer is not loaded nor needed unless pre-caching is enabled.

$isEnabled && Slim::Utils::ImageResizer->resize($parentArtwork, "music/$parentArtworkId/cover_", join(',', @specs), undef);

@michaelherger michaelherger Aug 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, did you add that line to pre-cache the album artwork, so we don't need to change the schema to add the artwork file URL? Would we still be able to get the original size file (or any resized version of it)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The titles query doesn't return a url for local content. albums.artwork is currently set to (one of if multiples) tracks.coverid.

So I just push the album image through the same process as for track images.

There may be holes in this, for example if there's code I haven't identified that looks up the associated file url from the tracks table using tracks.coverid = albums.artwork.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And sure enough there is a problem:

Clicking the image on the album info page in default skin opens a url for example http://localhost:9000/Default/music/50628676/cover which results in no image shown in the resulting new tab in the case of an album-level only image.

I guess we'd need to cache the original image (pass an extra spec to ::ImageResizer->resize?)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be the result of having no reference to the original file.

I'll have something to play with tonight. It would create helper entries in the tracks table (content type dir - for the album level folder). Using that seems to address the resizing challenges nicely.

Comment thread Slim/Control/Commands.pm
types => 'audio',
recursive => 0,
} ) if scalar @paths;
Slim::Music::Artwork->precacheAllArtwork if scalar @paths;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? The scanner would run in its separate process, but calling precacheAllArtwork() here would do the job in-process. And why only if the scanner was run for a specific folder?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think because in the single album scan it otherwise is not called.

Comment thread Slim/Music/Artwork.pm
$meta->{"albumid"} = delete $meta->{"tracks.album"};
$meta->{"workid"} = delete $meta->{"tracks.work"};

if ( $1 =~ /ARTIST|COMPOSER|CONDUCTOR|BAND/ ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Store $1 in a named variable. This can easily break if we add some regex to the previous few lines.

@michaelherger

Copy link
Copy Markdown
Member

Unfortunately the performance hit by this PR is unacceptable in my (limited) testing: Mac M2Pro, 16GB, SSD for the data, 20k tracks on NAS (1Gb), another 5k tracks from local SSD. The artwork processing takes 30x the time of 9.2. 30s vs. 1s. I'll continue the investigation.

@darrell-k

Copy link
Copy Markdown
Contributor Author

Ouch! That's much worse than I was seeing. I'm not at my computer right now but later I'll check that I pushed everything.

@darrell-k

Copy link
Copy Markdown
Contributor Author

Ouch! That's much worse than I was seeing. I'm not at my computer right now but later I'll check that I pushed everything.

This was a response to your performance observation just now. I didn't reply in the right place.

@michaelherger

Copy link
Copy Markdown
Member

Unfortunately the performance hit by this PR is unacceptable in my (limited) testing: Mac M2Pro, 16GB, SSD for the data, 20k tracks on NAS (1Gb), another 5k tracks from local SSD. The artwork processing takes 30x the time of 9.2. 30s vs. 1s. I'll continue the investigation.

So I decided to run the scanner under NYTProf. I'm not sure whether you're familiar with it. But it gives us a pretty good impression. The big penalty comes from repeatedly calling findStandaloneArtwork(). As this is stored on a NAS in my test case (which might often be the case with those Pi installations!), that's relatively slow. And calling it thousands of times is adding up:

Screenshot 2026-07-30 at 16 27 39

Looking at the results of 9.2 we see a totally different picture:

Screenshot 2026-07-30 at 16 27 30

I can send you the full reports if you like.

Comment thread Slim/Music/Artwork.pm
@albumDirs = Slim::Utils::Misc::uniq(@albumDirs);
my $commonParent = _findCommonParent(\@albumDirs);

if ( my $parentArtwork = Slim::Music::Artwork->findStandaloneArtwork({}, {}, Slim::Utils::Misc::fileURLFromPath($commonParent), 1) ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is costing about 24s in my test case.

@michaelherger

Copy link
Copy Markdown
Member

@darrell-k first let me thank you once again for the energy and time you put into these changes. And I definitely don't want to sound ungrateful. I've recently been too busy to give quicker feedback.

Unfortunately I think this time we've lost track of what the PR tries to fix/add/improve. It mentions another approach to box set handling, but then admits that problem wasn't solved. It then tries to fix a bunch of other artwork related issues instead. And title formatting (which then isn't used).

The more time I spend trying to understand everything in this PR, the more I believe we should step back a bit. Let's try to come up with a well defined list of issues, and try to address them. Then create smaller PRs, each one solving one problem, or a well defined group of related problems.

Maybe it's time to re-think the artwork scan? Should the scanner not only index audio files, but collect a list of artwork files while it's crawling the media folders? This could avoid later repeated reading of the same folders again. Finding a set of artwork files in a folder always requires reading the full file list, which then would be filtered. If we already knew the candidate file name from the initial scan, we wouldn't have to do this again (that's what's costing most of the time in my tests). This might be a major task, but at least we'd know what we're targeting.

Would you remember a list of bugs you tried to fix in this PR? One might actually be the one addressed (slightly differently) in #1607?

michaelherger added a commit that referenced this pull request Jul 30, 2026
Extracted and tweaked from #1536

Signed-off-by: Michael Herger <michael@herger.net>
Comment thread Slim/Music/Artwork.pm

if ( keys %$meta == 0 && $trackid ) {

my @cols = map { "tracks.$_" } keys %{Slim::Schema::Track->attributes};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could all of this be replaced with a call to the titles query?

@darrell-k

Copy link
Copy Markdown
Contributor Author

@darrell-k first let me thank you once again for the energy and time you put into these changes. And I definitely don't want to sound ungrateful. I've recently been too busy to give quicker feedback.

Unfortunately I think this time we've lost track of what the PR tries to fix/add/improve. It mentions another approach to box set handling, but then admits that problem wasn't solved. It then tries to fix a bunch of other artwork related issues instead. And title formatting (which then isn't used).

The more time I spend trying to understand everything in this PR, the more I believe we should step back a bit. Let's try to come up with a well defined list of issues, and try to address them. Then create smaller PRs, each one solving one problem, or a well defined group of related problems.

Maybe it's time to re-think the artwork scan? Should the scanner not only index audio files, but collect a list of artwork files while it's crawling the media folders? This could avoid later repeated reading of the same folders again. Finding a set of artwork files in a folder always requires reading the full file list, which then would be filtered. If we already knew the candidate file name from the initial scan, we wouldn't have to do this again (that's what's costing most of the time in my tests). This might be a major task, but at least we'd know what we're targeting.

Would you remember a list of bugs you tried to fix in this PR? One might actually be the one addressed (slightly differently) in #1607?

Yes, it's been a long time since we discussed this!

This PR is my reworking of the AI-assisted #1513

The primary objective is to support album box-set artwork.

For the title formatting issue, read from #1536 (comment) onwards. It is used when the user sets the wildcard formatting option for artwork.

As you will see from that, I changed the code to avoid instantiating track objects, as you suggested, and that was when I discovered the existing wildcard artwork format processing was broken in a N&C scan.

So yes there are two issues here now and perhaps they could be split into 2 PRs. the second, being a fix, should come first if we do this.

  1. Introduce box set artwork handling
  2. Fix N&C wildcard artwork handling

#1607 I hadn't looked at, it's a different issue (but might be affected by the changes here, I'll have a look)

Rethinking the artwork scan might be worth it - building a temporary table containing the paths to new/changed/deleted artwork in the library during the initial scan, perhaps? I'll have a think.

But maybe addressing the specific points in your review today might be good enough? I'll work through those now.

Signed-off-by: darrell-k <darrell@darrell.org.uk>
Signed-off-by: darrell-k <darrell@darrell.org.uk>
Signed-off-by: darrell-k <darrell@darrell.org.uk>
Signed-off-by: darrell-k <darrell@darrell.org.uk>
@darrell-k

darrell-k commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

I've just pushed a change which saves artwork paths in a new database table during the file discovery phase and then uses this table rather than rescanning the disk in Slim::Music::Artwork::findStandaloneArtwork.

It's not complete yet (I need to look at the variable artwork names because that's still doing an existence check on the disk, and maybe other stuff) but you should be able to run the performance test for a n&c scan without an artwork template in advanced/formatting.

If this turns out to be a useful change, there may be a better way of finding the image files than what I'm doing here.

@michaelherger

Copy link
Copy Markdown
Member

@darrell-k - please, pretty really please open an issue describing the artwork/box set problem. I've spent hours trying to understand and testing what you've been suggesting here. But it's so convoluted, with mixed in other solutions, I don't even know any more what we're trying to solve. Let's have a conscious description of the problem and a potential solution before we create and/or review more changes.

@darrell-k

Copy link
Copy Markdown
Contributor Author

@michaelherger the functional requirements haven't changed from #1513 . I raised this PR because you were unhappy with the LLM-generated code there and hinted that you would like me to take a look.

However, I've had a look around and there doesn't seem to be a concise description of the requirements for that, its the usual long forum thread(s).

Perhaps @mikeysas / @audiomuze could help by creating an issue describing the objectives. I could then add the extra things that came to light during development/testing.

In the meantime, I'd be grateful if you could tell me if yesterday's changes have mitigated the performance problems with a NAS scan that you identified.

@michaelherger

Copy link
Copy Markdown
Member

#1513 is a draft pull request without description, other than a link to some random forum post. I can't spend clicking around and reading endless discussion just to figure out what users consider a "box set". So please.

https://github.com/LMS-Community/slimserver/issues/new?template=BLANK_ISSUE

Define what a box set is. Describe what does work in LMS, and what doesn't. Explain what needs to be fixed. Feel free to suggest an approach to fixing it. Once we agree on this, we can go and implement things. And that PR will point to that issue it fixes, and everybody knows what we're looking for in the PR. Let's just have a little structure. Not too much, just a little.

I haven't run the tests yet, sorry. I got distracted trying to understand this PR...

@darrell-k

Copy link
Copy Markdown
Contributor Author

#1513 is a draft pull request without description, other than a link to some random forum post. I can't spend clicking around and reading endless discussion just to figure out what users consider a "box set". So please.

Yes, I said the same above, but asked if the users who were discussing / testing it before could do it. I think it's better to get this from the users requesting the feature. If I were to do it myself, the issue would end up describing my understanding of the requirements based on the coding I have done here, which might not be complete.

Of course I will then comment on the issue based on my findings during analysis etc.

@mikeysas

mikeysas commented Aug 1, 2026

Copy link
Copy Markdown

@michaelherger / @darrell-k,

I captured the original requirements for this a while back with #1430 . The core concept there was to support varying artwork for tracks and separate album cover artwork.

There are three use cases that we have identified:

  1. Box Sets - a multi disc collection in a single release where each disc contains unique artwork (and often a disc subtitle) and the box set itself has a unique cover artwork.
  2. Multi-Album Compilation release that contain multiple original albums on one or more discs where a single disc may contain more than one original album and/or an original album may cross two discs. The compilation has a unique cover artwork and the booklet contains each of the original album covers. This is essentially the same as a Box Set, but I am differentiating that varying artwork at the track level does not align by Disc # like my definition of Box Set. Compilations like this are common with Jazz reissues on CD. I use the Grouping Tag to group the Original Albums.
  3. Digitally downloaded music that comes with unique artwork per track and an overall album cover art as a jpg file. It was a user asking about this use case in the forum that inspired my original enhancement request when I realized the solution would also help the Box Set / Multi-Album Compilation releases.

When I originally submitted that issue, I was thinking the track artwork would have to be embedded in the files and then the album cover would come from cover.jpg / folder.jpg logic. @audiomuze added the requirements with PR #1513 to support scanning track for level artwork from .jpg file names that matched disc#, disc subtitles and grouping tags so users don’t have to embed their artwork in files.

That is the history here as I recall this. Does this cover what you need @michaelherger or I can update #1430 or create a new issue if you prefer?

@mikeysas

mikeysas commented Aug 3, 2026

Copy link
Copy Markdown

Updated Requirements compiled in #1430 (comment)

@michaelherger

Copy link
Copy Markdown
Member

Can we use #1430 to discuss the feature before continuing the code work? I actually believe a lot of this can already be handled with custom file name formats. We "only" need a mechanism to detach the album artwork from the track artwork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants