Skip to content

"Classical Music by Conductor" ignores myClassicalGenres setting - hardcoded to 'Classical' #1565

Description

@RPerkins96

Bug: "Classical Music by Conductor" ignores user-configured myClassicalGenres setting — hardcoded to 'Classical'

I have verified this fix works locally on my installation. I am not familiar enough
with the project's contribution workflow to submit a formal pull request, and used Claude AI to with the bug report and suggest testing and possible side-effects. I am happy to assist with testing if needed.


Summary

The Classical Music by Conductor browse menu in ExtendedBrowseModes hardcodes
the genre filter to the literal string 'Classical', ignoring the user-configured
myClassicalGenres preference introduced in PR #1240. Tracks tagged with any
non-English classical genre (e.g. Classique, Klassik, Klassiek) do not appear
under their conductor in this menu, even when those genres are explicitly listed in
Settings → My Music → My classical genres.

This is an incomplete refactor from PR #1240, which wired myClassicalGenres into
Works scanning and Composer browsing but did not update the Conductor browse menu.


Environment

  • LMS Version: 9.1.0
  • OS: macOS 15.7.3
  • Plugin: ExtendedBrowseModes (built-in)
  • Setting: Settings → My Music → My classical genres = Classical, Klassik, Classique, Klassiek

Reproduction Steps

  1. Set My classical genres to include Classique (or any non-English classical genre)
  2. Tag a track with GENRE = Classique and CONDUCTOR = Michael Tilson Thomas
  3. Perform a full clear-and-rescan
  4. Navigate to My Music → Classical Music by Conductor
  5. Observe that Michael Tilson Thomas does not appear
  6. Change the same track's GENRE to Classical and rescan
  7. Observe that Michael Tilson Thomas now appears

Expected Behaviour

The Classical Music by Conductor genre filter should respect the user-defined
myClassicalGenres preference, consistent with how Works scanning and Composer
browsing already behave following PR #1240.

Actual Behaviour

The conductor filter hardcodes a check for the literal string 'Classical' and
ignores the user's configured genre list entirely.


Root Cause

In Slim/Plugin/ExtendedBrowseModes/Plugin.pm, the conductor menu item is defined
with a hardcoded genre_id:

# BEFORE (line ~37)
params  => { role_id => 'CONDUCTOR', genre_id => 'Classical' },

This string is passed through Libraries::valueToId(), which looks up the single
genre name 'Classical' in the database and returns its numeric ID. Any track tagged
with a genre not exactly matching 'Classical' is excluded, regardless of the
myClassicalGenres setting.

The infrastructure to fix this correctly already exists:

  • Libraries::valueToId() already handles comma-separated genre name strings —
    this is exactly how the AudioBooks genre list is processed (see Libraries.pm line 73)
  • $serverPrefs is already available in Plugin.pm (declared at line 23)
  • The myClassicalGenres preference already contains the user's full comma-separated
    genre list (e.g. 'Classical, Klassik, Classique, Klassiek')

Fix

File: Slim/Plugin/ExtendedBrowseModes/Plugin.pm

Change: One line — replace the hardcoded 'Classical' string with a dynamic
reference to the myClassicalGenres server preference:

# BEFORE
params  => { role_id => 'CONDUCTOR', genre_id => 'Classical' },

# AFTER
params  => { role_id => 'CONDUCTOR', genre_id => $serverPrefs->get('myClassicalGenres') },

valueToId() will then split the comma-separated preference value
(e.g. 'Classical, Klassik, Classique, Klassiek'), look up each genre name in the
database, and return their numeric IDs — exactly the same code path already used for
the AudioBooks virtual library.


Verification

The fix was verified by temporarily adding diagnostic code to Plugin.pm after
the $prefs->init() block.

Important: $prefs->init() only sets a preference value if no stored value
already exists on disk. Since ExtendedBrowseModes stores additionalMenuItems in
its preference file after first run, a $prefs->remove() call is required to force
re-initialization from the updated code. Without this step the dump will show the
old cached value 'Classical' and incorrectly suggest the fix has not taken effect.

Temporary diagnostic code added:

$prefs->remove('additionalMenuItems');  # force re-init from code, not disk cache

$prefs->init({ ... });                  # existing init block with fix applied

use Data::Dumper;
my $logger = logger('plugin.extendedbrowsemodes');
$logger->error("DEBUG: " . Data::Dumper::Dumper($prefs->get('additionalMenuItems')));

After restarting LMS, the server log at
~/Library/Logs/Squeezebox/server.log confirmed genre_id resolved correctly:

'params' => {
    'role_id' => 'CONDUCTOR',
    'genre_id' => 'Classical, Klassik, Classique, Klassiek'
}

All three temporary diagnostic lines were removed after verification. Conductors
tagged with Classique subsequently appeared correctly in the
Classical Music by Conductor browse menu.


Side Effects Analysis

The following scenarios were considered:

Users who have never configured myClassicalGenres — Not a problem. The
preference has a hardcoded default value in Prefs.pm line 200:

'myClassicalGenres' => $prefs->get("showComposerReleasesbyAlbumGenres") || "Classical, Klassik, Classique, Klassiek"

It will never be empty or undefined, so behaviour is identical to before for these users.

Users who have set myClassicalGenres to only 'Classical' — Identical
behaviour to before. No regression.

Users who have added extra genres such as 'Orchestral' or 'Opera' — The
conductor browse menu will include those genres, which is the correct and intended
behaviour of the myClassicalGenres preference.

The enabled => 0 default — The conductor menu item is disabled by default,
so the change only affects users who have explicitly enabled it. This is a small,
self-selected audience of classical music collectors — precisely the users most
likely to have non-English genre tags.

Existing installations — migration concern: This is the most significant
consideration. $prefs->init() does not overwrite stored preference values. Users
who already have the conductor menu configured will retain the old cached 'Classical'
value in their stored additionalMenuItems preference, and will not see the fix
until that preference is reset.

A blanket $prefs->remove('additionalMenuItems') on startup is not safe, as
additionalMenuItems contains all user-defined custom browse modes — not just the
conductor entry — and removing it would discard any user customizations. The correct
migration approach would be to surgically update only the genre_id field of the
conductor entry within the stored additionalMenuItems array, leaving all other
entries untouched. The maintainer is best placed to determine the appropriate
migration strategy.


Additional Notes

  • The myClassicalGenres preference is already registered in XMLBrowser.pm as a
    cache-invalidating preference (line 45), so changes to the genre list will
    automatically trigger a cache wipe and menu refresh — no additional wiring needed.
  • The same issue may affect other genre-filtered browse modes if users add custom
    menu items with hardcoded genre strings via the ExtendedBrowseModes UI, but that
    is a separate concern.
  • This fix completes the intent of PR Option to limit works scanning to classical #1240, which introduced myClassicalGenres
    but did not update the Conductor browse path.

Related

  • PR Option to limit works scanning to classical #1240Option to limit works scanning to classical (darrell-k)
  • Slim/Schema/Genre.pmisMyClassicalGenre(), myClassicalGenreIds()
  • Slim/Menu/BrowseLibrary/Releases.pm line 218 — existing correct usage of
    myClassicalGenreIds() for Works filtering
  • Slim/Plugin/ExtendedBrowseModes/Libraries.pm line 73 — existing correct usage
    of comma-separated genre names in valueToId() for AudioBooks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions