Skip to content

Commit b73d48a

Browse files
committed
Bring back album_for_id, track_for_id
Restore album_for_id and track_for_id functions in metadata_plugins to support data source-specific lookups. These functions accept both an ID and data_source parameter, enabling plugins like mbsync and missing to retrieve metadata from the correct source. Update mbsync and missing plugins to use the restored functions with explicit data_source parameters. Add data_source validation to prevent lookups when the source is not specified. Add get_metadata_source helper function to retrieve plugins by their data_source name, cached for performance.
1 parent 497e97f commit b73d48a

File tree

4 files changed

+69
-10
lines changed

4 files changed

+69
-10
lines changed

beets/metadata_plugins.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from beets.util import cached_classproperty
2020
from beets.util.id_extractors import extract_release_id
2121

22-
from .plugins import BeetsPlugin, find_plugins, notify_info_yielded
22+
from .plugins import BeetsPlugin, find_plugins, notify_info_yielded, send
2323

2424
if TYPE_CHECKING:
2525
from collections.abc import Iterable, Sequence
@@ -34,6 +34,14 @@ def find_metadata_source_plugins() -> list[MetadataSourcePlugin]:
3434
return [p for p in find_plugins() if hasattr(p, "data_source")] # type: ignore[misc]
3535

3636

37+
@cache
38+
def get_metadata_source(name: str) -> MetadataSourcePlugin | None:
39+
"""Get metadata source plugin by name."""
40+
name = name.lower()
41+
plugins = find_metadata_source_plugins()
42+
return next((p for p in plugins if p.data_source.lower() == name), None)
43+
44+
3745
@notify_info_yielded("albuminfo_received")
3846
def candidates(*args, **kwargs) -> Iterable[AlbumInfo]:
3947
"""Return matching album candidates from all metadata source plugins."""
@@ -62,6 +70,28 @@ def tracks_for_ids(ids: Sequence[str]) -> Iterable[TrackInfo]:
6270
yield from plugin.tracks_for_ids(ids)
6371

6472

73+
def album_for_id(_id: str, data_source: str) -> AlbumInfo | None:
74+
"""Get AlbumInfo object for the given ID and data source."""
75+
if (plugin := get_metadata_source(data_source)) and (
76+
info := plugin.album_for_id(_id)
77+
):
78+
send("albuminfo_received", info=info)
79+
return info
80+
81+
return None
82+
83+
84+
def track_for_id(_id: str, data_source: str) -> TrackInfo | None:
85+
"""Get TrackInfo object for the given ID and data source."""
86+
if (plugin := get_metadata_source(data_source)) and (
87+
info := plugin.track_for_id(_id)
88+
):
89+
send("trackinfo_received", info=info)
90+
return info
91+
92+
return None
93+
94+
6595
@cache
6696
def get_penalty(data_source: str | None) -> float:
6797
"""Get the penalty value for the given data source."""

beetsplug/mbsync.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,25 @@ def singletons(self, lib, query, move, pretend, write):
7272
query.
7373
"""
7474
for item in lib.items(query + ["singleton:true"]):
75-
if not item.mb_trackid:
75+
if not (track_id := item.mb_trackid):
7676
self._log.info(
7777
"Skipping singleton with no mb_trackid: {}", item
7878
)
7979
continue
8080

81+
if not (data_source := item.get("data_source")):
82+
self._log.info(
83+
"Skipping singleton without data source: {}", item
84+
)
85+
continue
86+
8187
if not (
82-
track_info := metadata_plugins.track_for_id(item.mb_trackid)
88+
track_info := metadata_plugins.track_for_id(
89+
track_id, data_source
90+
)
8391
):
8492
self._log.info(
85-
"Recording ID not found: {0.mb_trackid} for track {0}", item
93+
"Recording ID not found: {} for track {}", track_id, item
8694
)
8795
continue
8896

@@ -97,15 +105,24 @@ def albums(self, lib, query, move, pretend, write):
97105
"""
98106
# Process matching albums.
99107
for album in lib.albums(query):
100-
if not album.mb_albumid:
108+
if not (album_id := album.mb_albumid):
101109
self._log.info("Skipping album with no mb_albumid: {}", album)
102110
continue
103111

104112
if not (
105-
album_info := metadata_plugins.album_for_id(album.mb_albumid)
113+
data_source := album.get("data_source")
114+
or album.items()[0].get("data_source")
115+
):
116+
self._log.info("Skipping album without data source: {}", album)
117+
continue
118+
119+
if not (
120+
album_info := metadata_plugins.album_for_id(
121+
album_id, data_source
122+
)
106123
):
107124
self._log.info(
108-
"Release ID {0.mb_albumid} not found for album {0}", album
125+
"Release ID {} not found for album {}", album_id, album
109126
)
110127
continue
111128

beetsplug/missing.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,17 @@ def _missing(self, album: Album) -> Iterator[Item]:
220220
if len(album.items()) == album.albumtotal:
221221
return
222222

223-
item_mbids = {x.mb_trackid for x in album.items()}
224223
# fetch missing items
225224
# TODO: Implement caching that without breaking other stuff
226-
if album_info := metadata_plugins.album_for_id(album.mb_albumid):
225+
if (
226+
data_source := album.get("data_source")
227+
or album.items()[0].get("data_source")
228+
) and (
229+
album_info := metadata_plugins.album_for_id(
230+
album.mb_albumid, data_source
231+
)
232+
):
233+
item_mbids = {x.mb_trackid for x in album.items()}
227234
for track_info in album_info.tracks:
228235
if track_info.track_id not in item_mbids:
229236
self._log.debug(

test/plugins/test_mbsync.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,15 @@ def test_update_library(self):
4545
album="old album",
4646
mb_albumid="album id",
4747
mb_trackid="track id",
48+
data_source="data_source",
4849
)
4950
self.lib.add_album([album_item])
5051

51-
singleton = Item(title="old title", mb_trackid="singleton id")
52+
singleton = Item(
53+
title="old title",
54+
mb_trackid="singleton id",
55+
data_source="data_source",
56+
)
5257
self.lib.add(singleton)
5358

5459
self.run_command("mbsync")

0 commit comments

Comments
 (0)