lastgenre: Early validate genres, new debug option

- Revert/fix last.fm fetcher methods to validate genres.

  - In past versions (<=2.2) _resolve_genres which included whitelist
    checks ran instantly after fetching last.fm tags which made sure the
    next stage is hit when nothing worthwhile was found (e.g fallback
    album -> artist).

  - Bring back this behavior but don't run a full _resolve_genres but a
    quick valid (whitelist) check only!

- Introduce an extended config/CLI option that allows to really log what
  each stage fetches (prior to validation/whitelist filtering).

  - Since this potentially is verbose especially with VA albums (a lot
    of artist tag fetches) for performance and debug log clutter reasons
    this is disabled by default.

- Clarify final last.fm tags debug log message to "valid last.fm genres"
This commit is contained in:
J0J0 Todos 2025-03-28 07:51:48 +01:00
parent c57e5a1fb8
commit 702ddf493e

View file

@ -104,6 +104,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
"separator": ", ",
"prefer_specific": False,
"title_case": True,
"extended_debug": False,
}
)
self.setup()
@ -241,7 +242,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
# c14n only adds allowed genres but we may have had forbidden genres in
# the original tags list
valid_tags = [x for x in tags if self._is_valid(x)]
valid_tags = self._filter_valid_genres(tags)
return valid_tags[: self.config["count"].get(int)]
def fetch_genre(self, lastfm_obj):
@ -251,6 +252,10 @@ class LastGenrePlugin(plugins.BeetsPlugin):
min_weight = self.config["min_weight"].get(int)
return self._tags_for(lastfm_obj, min_weight)
def _filter_valid_genres(self, genres: list[str]) -> list[str]:
"""Filter list of genres, only keep valid."""
return [x for x in genres if self._is_valid(x)]
def _is_valid(self, genre: str) -> bool:
"""Check if the genre is valid.
@ -281,26 +286,35 @@ class LastGenrePlugin(plugins.BeetsPlugin):
args = [a.replace("\u2010", "-") for a in args]
self._genre_cache[key] = self.fetch_genre(method(*args))
return self._genre_cache[key]
genre = self._genre_cache[key]
if self.config["extended_debug"]:
self._log.debug(f"last.fm (unfiltered) {entity} tags: {genre}")
return genre
def fetch_album_genre(self, obj):
"""Return the album genre for this Item or Album."""
return self._last_lookup(
"album", LASTFM.get_album, obj.albumartist, obj.album
return self._filter_valid_genres(
self._last_lookup(
"album", LASTFM.get_album, obj.albumartist, obj.album
)
)
def fetch_album_artist_genre(self, obj):
"""Return the album artist genre for this Item or Album."""
return self._last_lookup("artist", LASTFM.get_artist, obj.albumartist)
return self._filter_valid_genres(
self._last_lookup("artist", LASTFM.get_artist, obj.albumartist)
)
def fetch_artist_genre(self, item):
"""Returns the track artist genre for this Item."""
return self._last_lookup("artist", LASTFM.get_artist, item.artist)
return self._filter_valid_genres(
self._last_lookup("artist", LASTFM.get_artist, item.artist)
)
def fetch_track_genre(self, obj):
"""Returns the track genre for this Item."""
return self._last_lookup(
"track", LASTFM.get_track, obj.artist, obj.title
return self._filter_valid_genres(
self._last_lookup("track", LASTFM.get_track, obj.artist, obj.title)
)
# Main processing: _get_genre() and helpers.
@ -330,7 +344,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
self, old: list[str], new: list[str]
) -> list[str]:
"""Combine old and new genres and process via _resolve_genres."""
self._log.debug(f"fetched last.fm tags: {new}")
self._log.debug(f"valid last.fm tags: {new}")
self._log.debug(f"existing genres taken into account: {old}")
combined = old + new
return self._resolve_genres(combined)
@ -489,6 +503,13 @@ class LastGenrePlugin(plugins.BeetsPlugin):
dest="album",
help="match albums instead of items (default)",
)
lastgenre_cmd.parser.add_option(
"-d",
"--debug",
action="store_true",
dest="extended_debug",
help="extended last.fm debug logging",
)
lastgenre_cmd.parser.set_defaults(album=True)
def lastgenre_func(lib, opts, args):