From 6a192d0bdb48ba64fd1236df43c13a215c211c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Sat, 15 Feb 2025 16:33:36 +0000 Subject: [PATCH] albums_for_id -> album_for_id and return a single candidate instead of an iterator --- beets/autotag/hooks.py | 30 ++++++++---------------------- beets/autotag/match.py | 12 +++++------- beets/plugins.py | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index 3fa80c6f3..81cfd7bb2 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -602,8 +602,7 @@ def album_for_mbid(release_id: str) -> AlbumInfo | None: if the ID is not found. """ try: - album = mb.album_for_id(release_id) - if album: + if album := mb.album_for_id(release_id): plugins.send("albuminfo_received", info=album) return album except mb.MusicBrainzAPIError as exc: @@ -616,8 +615,7 @@ def track_for_mbid(recording_id: str) -> TrackInfo | None: if the ID is not found. """ try: - track = mb.track_for_id(recording_id) - if track: + if track := mb.track_for_id(recording_id): plugins.send("trackinfo_received", info=track) return track except mb.MusicBrainzAPIError as exc: @@ -625,26 +623,14 @@ def track_for_mbid(recording_id: str) -> TrackInfo | None: return None -def albums_for_id(album_id: str) -> Iterable[AlbumInfo]: - """Get a list of albums for an ID.""" - a = album_for_mbid(album_id) - if a: - yield a - for a in plugins.album_for_id(album_id): - if a: - plugins.send("albuminfo_received", info=a) - yield a +def album_for_id(_id: str) -> AlbumInfo | None: + """Get AlbumInfo object for the given ID string.""" + return album_for_mbid(_id) or plugins.album_for_id(_id) -def tracks_for_id(track_id: str) -> Iterable[TrackInfo]: - """Get a list of tracks for an ID.""" - t = track_for_mbid(track_id) - if t: - yield t - for t in plugins.track_for_id(track_id): - if t: - plugins.send("trackinfo_received", info=t) - yield t +def track_for_id(_id: str) -> TrackInfo | None: + """Get TrackInfo object for the given ID string.""" + return track_for_mbid(_id) or plugins.track_for_id(_id) def invoke_mb(call_func: Callable, *args): diff --git a/beets/autotag/match.py b/beets/autotag/match.py index a7121fd34..bc30ccea2 100644 --- a/beets/autotag/match.py +++ b/beets/autotag/match.py @@ -510,8 +510,8 @@ def tag_album( if search_ids: for search_id in search_ids: log.debug("Searching for album ID: {0}", search_id) - for album_info_for_id in hooks.albums_for_id(search_id): - _add_candidate(items, candidates, album_info_for_id) + if info := hooks.album_for_id(search_id): + _add_candidate(items, candidates, info) # Use existing metadata or text search. else: @@ -590,11 +590,9 @@ def tag_item( if trackids: for trackid in trackids: log.debug("Searching for track ID: {0}", trackid) - for track_info in hooks.tracks_for_id(trackid): - dist = track_distance(item, track_info, incl_artist=True) - candidates[track_info.track_id] = hooks.TrackMatch( - dist, track_info - ) + if info := hooks.track_for_id(trackid): + dist = track_distance(item, info, incl_artist=True) + candidates[info.track_id] = hooks.TrackMatch(dist, info) # If this is a good match, then don't keep searching. rec = _recommendation(_sort_candidates(candidates.values())) if ( diff --git a/beets/plugins.py b/beets/plugins.py index 299c41815..2ca98649e 100644 --- a/beets/plugins.py +++ b/beets/plugins.py @@ -14,18 +14,25 @@ """Support for beets plugins.""" +from __future__ import annotations + import abc import inspect import re import traceback from collections import defaultdict from functools import wraps +from typing import TYPE_CHECKING import mediafile import beets from beets import logging +if TYPE_CHECKING: + from beets.autotag.hooks import AlbumInfo, TrackInfo + + PLUGIN_NAMESPACE = "beetsplug" # Plugins using the Last.fm API can share the same API key. @@ -290,7 +297,7 @@ def load_plugins(names=()): ) -_instances = {} +_instances: dict[type[BeetsPlugin], BeetsPlugin] = {} def find_plugins(): @@ -397,20 +404,30 @@ def item_candidates(item, artist, title): yield from plugin.item_candidates(item, artist, title) -def album_for_id(album_id): - """Get AlbumInfo objects for a given ID string.""" +def album_for_id(_id: str) -> AlbumInfo | None: + """Get AlbumInfo object for the given ID string. + + A single ID can yield just a single album, so we return the first match. + """ for plugin in find_plugins(): - album = plugin.album_for_id(album_id) - if album: - yield album + if info := plugin.album_for_id(_id): + send("albuminfo_received", info=info) + return info + + return None -def track_for_id(track_id): - """Get TrackInfo objects for a given ID string.""" +def track_for_id(_id: str) -> TrackInfo | None: + """Get TrackInfo object for the given ID string. + + A single ID can yield just a single track, so we return the first match. + """ for plugin in find_plugins(): - track = plugin.track_for_id(track_id) - if track: - yield track + if info := plugin.track_for_id(_id): + send("trackinfo_received", info=info) + return info + + return None def template_funcs():