Skip to content

Commit c77ea75

Browse files
committed
Migrate arranger -> arrangers
1 parent 60e196d commit c77ea75

File tree

13 files changed

+81
-44
lines changed

13 files changed

+81
-44
lines changed

beets/autotag/hooks.py

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,18 @@ class Info(AttrDict[Any]):
128128

129129
IGNORED_FIELDS: ClassVar[set[str]] = {"data_url"}
130130
MEDIA_FIELD_MAP: ClassVar[dict[str, str]] = {}
131+
LIST_BY_LEGACY_FIELD: ClassVar[dict[str, str]] = {"genre": "genres"}
131132

132133
@cached_classproperty
133134
def nullable_fields(cls) -> set[str]:
134135
"""Return fields that may be cleared when new metadata is applied."""
135136
return set(config["overwrite_null"][cls.type.lower()].as_str_seq())
136137

137138
def __setitem__(self, key: str, value: Any) -> None:
138-
# handle info.genre = "abc" and info["genre"] = "abc"
139-
if key == "genre":
140-
self["genres"] = self._get_list_from_string_value(
141-
"genre", "genres", value, self["genres"]
139+
# handle legacy info.str_field = "abc" and info["str_field"] = "abc"
140+
if list_field := self.LIST_BY_LEGACY_FIELD.get(key):
141+
self[list_field] = self._get_list_from_string_value(
142+
key, list_field, value, self[list_field]
142143
)
143144
else:
144145
super().__setitem__(key, value)
@@ -379,23 +380,13 @@ class TrackInfo(Info):
379380
"track_id": "mb_trackid",
380381
"medium_index": "track",
381382
}
382-
383-
def __setitem__(self, key: str, value: Any) -> None:
384-
# handle info.remixer = "abc" and info["remixer"] = "abc"
385-
if key == "remixer":
386-
self["remixers"] = self._get_list_from_string_value(
387-
"remixer", "remixers", value, self["remixers"]
388-
)
389-
elif key == "lyricist":
390-
self["lyricists"] = self._get_list_from_string_value(
391-
"lyricist", "lyricists", value, self["lyricists"]
392-
)
393-
elif key == "composer":
394-
self["composers"] = self._get_list_from_string_value(
395-
"composer", "composers", value, self["composers"]
396-
)
397-
else:
398-
super().__setitem__(key, value)
383+
LIST_BY_LEGACY_FIELD: ClassVar[dict[str, str]] = {
384+
**Info.LIST_BY_LEGACY_FIELD,
385+
"remixer": "remixers",
386+
"lyricist": "lyricists",
387+
"composer": "composers",
388+
"arranger": "arrangers",
389+
}
399390

400391
@property
401392
def id(self) -> str | None:
@@ -430,7 +421,7 @@ def raw_data(self) -> JSONDict:
430421
def __init__(
431422
self,
432423
*,
433-
arranger: str | None = None,
424+
arrangers: list[str] | None = None,
434425
bpm: str | None = None,
435426
composers: list[str] | None = None,
436427
composer_sort: str | None = None,
@@ -452,7 +443,7 @@ def __init__(
452443
work_disambig: str | None = None,
453444
**kwargs,
454445
) -> None:
455-
self.arranger = arranger
446+
self.arrangers = arrangers
456447
self.bpm = bpm
457448
self.composers = composers
458449
self.composer_sort = composer_sort

beets/library/library.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Library(dbcore.Database):
2626
(migrations.MultiRemixerFieldMigration, (Item,)),
2727
(migrations.MultiLyricistFieldMigration, (Item,)),
2828
(migrations.MultiComposerFieldMigration, (Item,)),
29+
(migrations.MultiArrangerFieldMigration, (Item,)),
2930
)
3031

3132
def __init__(

beets/library/migrations.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ class MultiComposerFieldMigration(MultiValueFieldMigration):
137137
list_field = "composers"
138138

139139

140+
class MultiArrangerFieldMigration(MultiValueFieldMigration):
141+
"""Backfill multi-value arrangers from legacy single-string arranger data."""
142+
143+
str_field = "arranger"
144+
list_field = "arrangers"
145+
146+
140147
class LyricsRow(NamedTuple):
141148
id: int
142149
lyrics: str

beets/library/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ class Item(LibModel):
662662
"work": types.STRING,
663663
"mb_workid": types.STRING,
664664
"work_disambig": types.STRING,
665-
"arranger": types.STRING,
665+
"arrangers": types.MULTI_VALUE_DSV,
666666
"grouping": types.STRING,
667667
"year": types.PaddedInt(4),
668668
"month": types.PaddedInt(2),

beets/test/_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def item(lib=None, **kwargs):
7878
genres=["the genre"],
7979
lyricists=["the lyricist"],
8080
composers=["the composer"],
81-
arranger="the arranger",
81+
arrangers=["the arranger"],
8282
grouping="the grouping",
8383
work="the work title",
8484
mb_workid="the work musicbrainz id",

beetsplug/musicbrainz.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,14 @@ def track_info(
399399
info.composers = composer
400400
info.composer_sort = ", ".join(composer_sort)
401401

402-
arranger = []
402+
arrangers = []
403403
for artist_relation in recording.get("artist-relations", ()):
404404
if "type" in artist_relation:
405405
type = artist_relation["type"]
406406
if type == "arranger":
407-
arranger.append(artist_relation["artist"]["name"])
408-
if arranger:
409-
info.arranger = ", ".join(arranger)
407+
arrangers.append(artist_relation["artist"]["name"])
408+
if arrangers:
409+
info.arrangers = arrangers
410410

411411
# Supplementary fields provided by plugins
412412
extra_trackdatas = plugins.send("mb_track_extract", data=recording)

docs/changelog.rst

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ New features
1818
- Query: Add ``has_cover_art`` computed field to query items by embedded cover
1919
art presence. Users can now search for tracks with or without embedded artwork
2020
using ``beet list has_cover_art:true`` or ``beet list has_cover_art:false``.
21-
- Store track remixers, lyricists, and composers in the multi-value
22-
``remixers``, ``lyricists``, and ``composers`` fields instead of the legacy
23-
single-value ``remixer``, ``lyricist``, and ``composer`` fields. Existing
24-
libraries are migrated automatically, and :doc:`plugins/musicbrainz` now
25-
preserves each MusicBrainz ``remixer``, ``lyricist``, and ``composer``
26-
relation as a separate value.
21+
- Store track remixers, lyricists, composers, and arrangers in the multi-value
22+
``remixers``, ``lyricists``, ``composers``, and ``arrangers`` fields instead
23+
of the legacy single-value ``remixer``, ``lyricist``, ``composer``, and
24+
``arranger`` fields. Existing libraries are migrated automatically, and
25+
:doc:`plugins/musicbrainz` now preserves each MusicBrainz ``remixer``,
26+
``lyricist``, ``composer``, and ``arranger`` relation as a separate value.
2727

2828
Bug fixes
2929
~~~~~~~~~
@@ -36,9 +36,13 @@ Bug fixes
3636
:doc:`plugins/listenbrainz`, :doc:`plugins/lastimport`, and
3737
:doc:`plugins/mpdstats` do not clash. :bug:`6469`
3838

39-
..
40-
For plugin developers
41-
~~~~~~~~~~~~~~~~~~~~~
39+
For plugin developers
40+
~~~~~~~~~~~~~~~~~~~~~
41+
42+
- If you maintain a metadata source plugin that populates any of ``arranger``,
43+
``composer``, ``lyricist``, ``remixer`` fields, update it to populate the
44+
respective multi-value fields instead (``arrangers``, ``composers``,
45+
``lyricists``, ``remixers``).
4246

4347
..
4448
Other changes

docs/reference/cli.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ artist sort name into the artist field for all your tracks, and ``beet modify
268268
title='$track $title'`` will add track numbers to their title metadata.
269269

270270
To adjust a multi-valued field, such as ``genres``, ``remixers``, ``lyricists``,
271-
or ``composers``, separate the values with |semicolon_space|. For example,
272-
``beet modify genres="rock; pop"``.
271+
``composers``, or ``arrangers``, separate the values with |semicolon_space|. For
272+
example, ``beet modify genres="rock; pop"``.
273273

274274
The ``-a`` option changes to querying album fields instead of track fields and
275275
also enables to operate on albums in addition to the individual tracks. Without

docs/reference/pathformat.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ These functions are built in to beets:
8080
then returns the next ``count`` items joined by ``join``.
8181

8282
This is especially useful for multi-valued fields like ``artists``,
83-
``genres``, ``remixers``, ``lyricists``, or ``composers`` where you may only
84-
want the first value or a limited number of values in a path.
83+
``genres``, ``remixers``, ``lyricists``, ``composers``, or ``arrangers`` where
84+
you may only want the first value or a limited number of values in a path.
8585

8686
Defaults:
8787

@@ -236,6 +236,7 @@ Ordinary metadata:
236236
- albumartist_credit
237237
- genre
238238
- genres: The track genres as a multi-valued field.
239+
- arrangers: The track arrangers as a multi-valued field.
239240
- composers: The track composers as a multi-valued field.
240241
- lyricists: The track lyricists as a multi-valued field.
241242
- remixers: The track remixers as a multi-valued field.

docs/reference/query.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ Recall that ``-a`` makes the ``list`` command show albums instead of individual
9696
tracks, so this command shows me all the releases I have from this year.
9797

9898
For multi-valued tags (such as ``artists``, ``albumartists``, ``remixers``,
99-
``lyricists``, or ``composers``), a regular expression search must be used to
100-
search for a single value within the multi-valued tag.
99+
``lyricists``, ``composers``, or ``arrangers``), a regular expression search
100+
must be used to search for a single value within the multi-valued tag.
101101

102102
Note that you can filter albums by querying tracks fields and vice versa:
103103

0 commit comments

Comments
 (0)