Skip to content

Commit 3f07caa

Browse files
committed
missing: clarify that only musicbrainz backend supports missing albums for artist
And give this functionality a small refactor.
1 parent 200e46d commit 3f07caa

File tree

2 files changed

+49
-57
lines changed

2 files changed

+49
-57
lines changed

beetsplug/missing.py

+33-45
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
from beets import config
2525
from beets.autotag import hooks
2626
from beets.dbcore import types
27-
from beets.library import Album, Item
27+
from beets.library import Album, Item, Library
2828
from beets.plugins import BeetsPlugin
2929
from beets.ui import Subcommand, decargs, print_
3030

31+
MB_ARTIST_QUERY = r"mb_albumartistid::^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$"
32+
3133

3234
def _missing_count(album):
3335
"""Return number of missing items in `album`."""
@@ -166,65 +168,51 @@ def _missing_tracks(self, lib, query):
166168
for item in self._missing(album):
167169
print_(format(item, fmt))
168170

169-
def _missing_albums(self, lib, query):
171+
def _missing_albums(self, lib: Library, query: list[str]) -> None:
170172
"""Print a listing of albums missing from each artist in the library
171173
matching query.
172174
"""
173-
total = self.config["total"].get()
174-
175-
albums = lib.albums(query)
176-
# build dict mapping artist to list of their albums in library
177-
albums_by_artist = defaultdict(list)
178-
for alb in albums:
179-
artist = (alb["albumartist"], alb["mb_albumartistid"])
180-
albums_by_artist[artist].append(alb)
175+
query.append(MB_ARTIST_QUERY)
176+
177+
# build dict mapping artist to set of their album ids in library
178+
album_ids_by_artist = defaultdict(set)
179+
for album in lib.albums(query):
180+
# TODO(@snejus): Some releases have different `albumartist` for the
181+
# same `mb_albumartistid`. Since we're grouping by the combination
182+
# of these two fields, we end up processing the same
183+
# `mb_albumartistid` multiple times: calling MusicBrainz API and
184+
# reporting the same set of missing albums. Instead, we should
185+
# group by `mb_albumartistid` field only.
186+
artist = (album["albumartist"], album["mb_albumartistid"])
187+
album_ids_by_artist[artist].add(album)
181188

182189
total_missing = 0
183-
184-
# build dict mapping artist to list of all albums
185-
for artist, albums in albums_by_artist.items():
186-
if artist[1] is None or artist[1] == "":
187-
albs_no_mbid = ["'" + a["album"] + "'" for a in albums]
188-
self._log.info(
189-
"No musicbrainz ID for artist '{}' found in album(s) {}; "
190-
"skipping",
191-
artist[0],
192-
", ".join(albs_no_mbid),
193-
)
194-
continue
195-
190+
calculating_total = self.config["total"].get()
191+
for (artist, artist_id), album_ids in album_ids_by_artist.items():
196192
try:
197-
resp = musicbrainzngs.browse_release_groups(artist=artist[1])
198-
release_groups = resp["release-group-list"]
193+
resp = musicbrainzngs.browse_release_groups(artist=artist_id)
199194
except MusicBrainzError as err:
200195
self._log.info(
201196
"Couldn't fetch info for artist '{}' ({}) - '{}'",
202-
artist[0],
203-
artist[1],
197+
artist,
198+
artist_id,
204199
err,
205200
)
206201
continue
207202

208-
missing = []
209-
present = []
210-
for rg in release_groups:
211-
missing.append(rg)
212-
for alb in albums:
213-
if alb["mb_releasegroupid"] == rg["id"]:
214-
missing.remove(rg)
215-
present.append(rg)
216-
break
217-
218-
total_missing += len(missing)
219-
if total:
220-
continue
221-
222-
missing_titles = {rg["title"] for rg in missing}
203+
missing_titles = [
204+
f"{artist} - {rg['title']}"
205+
for rg in resp["release-group-list"]
206+
if rg["id"] not in album_ids
207+
]
223208

224-
for release_title in missing_titles:
225-
print_("{} - {}".format(artist[0], release_title))
209+
if calculating_total:
210+
total_missing += len(missing_titles)
211+
else:
212+
for title in missing_titles:
213+
print(title)
226214

227-
if total:
215+
if calculating_total:
228216
print(total_missing)
229217

230218
def _missing(self, album: Album) -> Iterator[Item]:

docs/plugins/missing.rst

+16-12
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@ call to album data source.
88
Usage
99
-----
1010

11-
Add the ``missing`` plugin to your configuration (see :ref:`using-plugins`). By
12-
default, the ``beet missing`` command fetches album information from the origin
13-
data source and lists names of the **tracks** that are missing from your
14-
library. It can also list the names of albums that
15-
your library is missing from each artist.
16-
You can customize the output format, count
17-
the number of missing tracks per album, or total up the number of missing
18-
tracks over your whole library, using command-line switches::
11+
Add the ``missing`` plugin to your configuration (see :ref:`using-plugins`).
12+
The ``beet missing`` command fetches album information from the origin data
13+
source and lists names of the **tracks** that are missing from your library.
14+
15+
It can also list the names of missing **albums** for each artist, although this
16+
is limited to albums from the MusicBrainz data source only.
17+
18+
You can customize the output format, show missing counts instead of track
19+
titles, or display the total number of missing entities across your entire
20+
library::
1921

2022
-f FORMAT, --format=FORMAT
2123
print with custom FORMAT
2224
-c, --count count missing tracks per album
23-
-t, --total count total of missing tracks or albums
24-
-a, --album show missing albums for artist instead of tracks
25+
-t, --total count totals across the entire library
26+
-a, --album show missing albums for artist instead of tracks for album
27+
28+
…or by editing the corresponding configuration options.
2529

26-
…or by editing corresponding options.
30+
.. warning::
2731

28-
Note that ``-c`` is ignored when used with ``-a``.
32+
Option ``-c`` is ignored when used with ``-a``.
2933

3034
Configuration
3135
-------------

0 commit comments

Comments
 (0)