1717from __future__ import annotations
1818
1919from importlib import import_module
20- from typing import TYPE_CHECKING
21-
22- from beets import config , logging
2320
2421# Parts of external interface.
25- from beets .util import unique_list
2622from beets .util .deprecation import deprecate_for_maintainers , deprecate_imports
2723
2824from .hooks import AlbumInfo , AlbumMatch , TrackInfo , TrackMatch
2925from .match import Proposal , Recommendation , tag_album , tag_item
3026
31- if TYPE_CHECKING :
32- from collections .abc import Sequence
33-
34- from beets .library import Album , Item , LibModel
35-
3627
3728def __getattr__ (name : str ):
3829 if name == "current_metadata" :
@@ -53,282 +44,6 @@ def __getattr__(name: str):
5344 "Recommendation" ,
5445 "TrackInfo" ,
5546 "TrackMatch" ,
56- "apply_album_metadata" ,
57- "apply_item_metadata" ,
58- "apply_metadata" ,
5947 "tag_album" ,
6048 "tag_item" ,
6149]
62-
63- # Global logger.
64- log = logging .getLogger ("beets" )
65-
66- # Metadata fields that are already hardcoded, or where the tag name changes.
67- SPECIAL_FIELDS = {
68- "album" : (
69- "va" ,
70- "releasegroup_id" ,
71- "artist_id" ,
72- "artists_ids" ,
73- "album_id" ,
74- "mediums" ,
75- "tracks" ,
76- "year" ,
77- "month" ,
78- "day" ,
79- "artist" ,
80- "artists" ,
81- "artist_credit" ,
82- "artists_credit" ,
83- "artist_sort" ,
84- "artists_sort" ,
85- "data_url" ,
86- ),
87- "track" : (
88- "track_alt" ,
89- "artist_id" ,
90- "artists_ids" ,
91- "release_track_id" ,
92- "medium" ,
93- "index" ,
94- "medium_index" ,
95- "title" ,
96- "artist_credit" ,
97- "artists_credit" ,
98- "artist_sort" ,
99- "artists_sort" ,
100- "artist" ,
101- "artists" ,
102- "track_id" ,
103- "medium_total" ,
104- "data_url" ,
105- "length" ,
106- ),
107- }
108-
109-
110- # Additional utilities for the main interface.
111-
112-
113- def _apply_metadata (
114- info : AlbumInfo | TrackInfo ,
115- db_obj : Album | Item ,
116- null_fields : bool = True ,
117- ):
118- """Set the db_obj's metadata to match the info."""
119- key = "album" if isinstance (info , AlbumInfo ) else "track"
120- special_fields = set (SPECIAL_FIELDS [key ])
121- nullable_fields = set (config ["overwrite_null" ][key ].as_str_seq ())
122-
123- for field , value in info .items ():
124- # We only overwrite fields that are not already hardcoded.
125- if field in special_fields :
126- continue
127-
128- # Don't overwrite fields with empty values unless the
129- # field is explicitly allowed to be overwritten.
130- if null_fields and value is None and field not in nullable_fields :
131- continue
132-
133- db_obj [field ] = value
134-
135-
136- def correct_list_fields (m : LibModel ) -> None :
137- """Synchronise single and list values for the list fields that we use.
138-
139- That is, ensure the same value in the single field and the first element
140- in the list.
141-
142- For context, the value we set as, say, ``mb_artistid`` is simply ignored:
143- Under the current :class:`MediaFile` implementation, fields ``albumtype``,
144- ``mb_artistid`` and ``mb_albumartistid`` are mapped to the first element of
145- ``albumtypes``, ``mb_artistids`` and ``mb_albumartistids`` respectively.
146-
147- This means setting ``mb_artistid`` has no effect. However, beets
148- functionality still assumes that ``mb_artistid`` is independent and stores
149- its value in the database. If ``mb_artistid`` != ``mb_artistids[0]``,
150- ``beet write`` command thinks that ``mb_artistid`` is modified and tries to
151- update the field in the file. Of course nothing happens, so the same diff
152- is shown every time the command is run.
153-
154- We can avoid this issue by ensuring that ``mb_artistid`` has the same value
155- as ``mb_artistids[0]``, and that's what this function does.
156-
157- Note: :class:`Album` model does not have ``mb_artistids`` and
158- ``mb_albumartistids`` fields therefore we need to check for their presence.
159- """
160-
161- def ensure_first_value (single_field : str , list_field : str ) -> None :
162- """Ensure the first ``list_field`` item is equal to ``single_field``."""
163- single_val , list_val = getattr (m , single_field ), getattr (m , list_field )
164- if single_val :
165- setattr (m , list_field , unique_list ([single_val , * list_val ]))
166- elif list_val :
167- setattr (m , single_field , list_val [0 ])
168-
169- ensure_first_value ("albumtype" , "albumtypes" )
170-
171- if hasattr (m , "mb_artistids" ):
172- ensure_first_value ("mb_artistid" , "mb_artistids" )
173-
174- if hasattr (m , "mb_albumartistids" ):
175- ensure_first_value ("mb_albumartistid" , "mb_albumartistids" )
176-
177- if hasattr (m , "artists_sort" ):
178- ensure_first_value ("artist_sort" , "artists_sort" )
179-
180- if hasattr (m , "artists_credit" ):
181- ensure_first_value ("artist_credit" , "artists_credit" )
182-
183- if hasattr (m , "albumartists_credit" ):
184- ensure_first_value ("albumartist_credit" , "albumartists_credit" )
185-
186- if hasattr (m , "artists" ):
187- ensure_first_value ("artist" , "artists" )
188-
189- if hasattr (m , "albumartists_sort" ):
190- ensure_first_value ("albumartist_sort" , "albumartists_sort" )
191-
192-
193- def apply_item_metadata (item : Item , track_info : TrackInfo ):
194- """Set an item's metadata from its matched TrackInfo object."""
195- item .artist = track_info .artist
196- item .artists = track_info .artists
197- item .artist_sort = track_info .artist_sort
198- item .artists_sort = track_info .artists_sort
199- item .artist_credit = track_info .artist_credit
200- item .artists_credit = track_info .artists_credit
201- item .title = track_info .title
202- item .mb_trackid = track_info .track_id
203- item .mb_releasetrackid = track_info .release_track_id
204- if track_info .artist_id :
205- item .mb_artistid = track_info .artist_id
206- if track_info .artists_ids :
207- item .mb_artistids = track_info .artists_ids
208-
209- _apply_metadata (track_info , item )
210- correct_list_fields (item )
211-
212- # At the moment, the other metadata is left intact (including album
213- # and track number). Perhaps these should be emptied?
214-
215-
216- def apply_album_metadata (album_info : AlbumInfo , album : Album ):
217- """Set the album's metadata to match the AlbumInfo object."""
218- _apply_metadata (album_info , album , null_fields = False )
219- correct_list_fields (album )
220-
221-
222- def apply_metadata (
223- album_info : AlbumInfo , item_info_pairs : list [tuple [Item , TrackInfo ]]
224- ):
225- """Set items metadata to match corresponding tagged info."""
226- for item , track_info in item_info_pairs :
227- # Artist or artist credit.
228- if config ["artist_credit" ]:
229- item .artist = (
230- track_info .artist_credit
231- or track_info .artist
232- or album_info .artist_credit
233- or album_info .artist
234- )
235- item .artists = (
236- track_info .artists_credit
237- or track_info .artists
238- or album_info .artists_credit
239- or album_info .artists
240- )
241- item .albumartist = album_info .artist_credit or album_info .artist
242- item .albumartists = album_info .artists_credit or album_info .artists
243- else :
244- item .artist = track_info .artist or album_info .artist
245- item .artists = track_info .artists or album_info .artists
246- item .albumartist = album_info .artist
247- item .albumartists = album_info .artists
248-
249- # Album.
250- item .album = album_info .album
251-
252- # Artist sort and credit names.
253- item .artist_sort = track_info .artist_sort or album_info .artist_sort
254- item .artists_sort = track_info .artists_sort or album_info .artists_sort
255- item .artist_credit = (
256- track_info .artist_credit or album_info .artist_credit
257- )
258- item .artists_credit = (
259- track_info .artists_credit or album_info .artists_credit
260- )
261- item .albumartist_sort = album_info .artist_sort
262- item .albumartists_sort = album_info .artists_sort
263- item .albumartist_credit = album_info .artist_credit
264- item .albumartists_credit = album_info .artists_credit
265-
266- # Release date.
267- for prefix in "" , "original_" :
268- if config ["original_date" ] and not prefix :
269- # Ignore specific release date.
270- continue
271-
272- for suffix in "year" , "month" , "day" :
273- key = f"{ prefix } { suffix } "
274- value = getattr (album_info , key ) or 0
275-
276- # If we don't even have a year, apply nothing.
277- if suffix == "year" and not value :
278- break
279-
280- # Otherwise, set the fetched value (or 0 for the month
281- # and day if not available).
282- item [key ] = value
283-
284- # If we're using original release date for both fields,
285- # also set item.year = info.original_year, etc.
286- if config ["original_date" ]:
287- item [suffix ] = value
288-
289- # Title.
290- item .title = track_info .title
291-
292- if config ["per_disc_numbering" ]:
293- # We want to let the track number be zero, but if the medium index
294- # is not provided we need to fall back to the overall index.
295- if track_info .medium_index is not None :
296- item .track = track_info .medium_index
297- else :
298- item .track = track_info .index
299- item .tracktotal = track_info .medium_total or len (album_info .tracks )
300- else :
301- item .track = track_info .index
302- item .tracktotal = len (album_info .tracks )
303-
304- # Disc and disc count.
305- item .disc = track_info .medium
306- item .disctotal = album_info .mediums
307-
308- # MusicBrainz IDs.
309- item .mb_trackid = track_info .track_id
310- item .mb_releasetrackid = track_info .release_track_id or item .mb_trackid
311-
312- item .mb_albumid = album_info .album_id
313- item .mb_releasegroupid = album_info .releasegroup_id
314-
315- item .mb_albumartistid = album_info .artist_id
316- item .mb_albumartistids = album_info .artists_ids or (
317- [ai ] if (ai := item .mb_albumartistid ) else []
318- )
319-
320- item .mb_artistid = track_info .artist_id or item .mb_albumartistid
321- item .mb_artistids = track_info .artists_ids or (
322- [iai ] if (iai := item .mb_artistid ) else []
323- )
324-
325- # Compilation flag.
326- item .comp = album_info .va
327-
328- # Track alt.
329- item .track_alt = track_info .track_alt
330-
331- _apply_metadata (album_info , item )
332- _apply_metadata (track_info , item )
333-
334- correct_list_fields (item )
0 commit comments