@@ -104,6 +104,27 @@ class Track(TypedDict):
104104 extraartists : NotRequired [list [Artist ]]
105105 sub_tracks : NotRequired [list [Track ]]
106106
107+ class ArtistInfo (TypedDict ):
108+ artist : str
109+ artists : list [str ]
110+ artist_credit : str
111+ artists_credit : list [str ]
112+ artist_id : str
113+ artists_ids : list [str ]
114+
115+ class AlbumArtistInfo (TypedDict ):
116+ artist : str
117+ artists : list [str ]
118+ artist_credit : str
119+ artists_credit : list [str ]
120+ artist_id : str
121+ artists_ids : list [str ]
122+ albumartist : str
123+ albumartists : list [str ]
124+ albumartist_credit : str
125+ albumartists_credit : list [str ]
126+ albumartist_id : str
127+ albumartists_ids : list [str ]
107128
108129class DiscogsPlugin (MetadataSourcePlugin ):
109130 def __init__ (self ):
@@ -261,7 +282,6 @@ def track_for_id(self, track_id: str) -> TrackInfo | None:
261282 for track in album .tracks :
262283 if track .track_id == track_id :
263284 return track
264-
265285 return None
266286
267287 def get_albums (self , query : str ) -> Iterable [AlbumInfo ]:
@@ -346,6 +366,106 @@ def get_artist_with_anv(
346366 artist , artist_id = self .get_artist (artist_list , join_key = "join" )
347367 return self .strip_disambiguation (artist ), artist_id
348368
369+ def build_albumartistinfo (self , artists : list [Artist ]) -> AlbumArtistInfo :
370+ info = self .build_artistinfo (artists , album_artist = True )
371+ albumartist : AlbumArtistInfo = {
372+ ** info ,
373+ "albumartist" : info ["artist" ],
374+ "albumartist_id" : info ["artist_id" ],
375+ "albumartists" : info ["artists" ],
376+ "albumartists_ids" : info ["artists_ids" ],
377+ "albumartist_credit" : info ["artist_credit" ],
378+ "albumartists_credit" : info ["artists_credit" ],
379+ }
380+ return albumartist
381+
382+ def build_artistinfo (
383+ self ,
384+ given_artists : list [Artist ],
385+ info : ArtistInfo = {
386+ "artist" : "" ,
387+ "artist_id" : "" ,
388+ "artists" : [],
389+ "artists_ids" : [],
390+ "artist_credit" : "" ,
391+ "artists_credit" : [],
392+ },
393+ album_artist : bool = False
394+ ) -> ArtistInfo :
395+ """Iterates through a discogs result and builds
396+ up the artist fields. Does not contribute to
397+ artist_sort as Discogs does not define that.
398+
399+ :param artists: A list of Discogs Artist objects
400+
401+ :param album_artist: If building an album artist,
402+ we need to account for the album_artist anv parameter.
403+ :return an ArtistInfo dictionary.
404+ """
405+
406+ a_anv : bool = self .config ["anv" ]["album_artist" ].get (bool )
407+ ac_anv : bool = self .config ["anv" ]["artist_credit" ].get (bool )
408+ aa_anv : bool = self .config ["anv" ]["album_artist" ].get (bool )
409+ feat_str : str = self .config ["featured_string" ].get (str )
410+
411+ artist = ""
412+ artist_anv = ""
413+ artists : list [str ] = []
414+ artists_anv : list [str ] = []
415+
416+ # Iterate through building the artist strings
417+ for a in given_artists :
418+ # Get the artist name
419+ name = self .strip_disambiguation (a ["name" ])
420+ discogs_id = a ["id" ]
421+ anv = a .get ("anv" , name )
422+ join = a .get ("join" , "" )
423+ role = a .get ("role" , "" ).lower ()
424+
425+ # Check if the artist is Various
426+ if name .lower () == "various" :
427+ name = config ["va_name" ].as_str ()
428+
429+ if role and "featuring" in role :
430+ artist = self ._join_artist (artist , name , feat_str )
431+ artist_anv = self ._join_artist (artist , name , feat_str )
432+ else :
433+ artist = self ._join_artist (artist , name , join )
434+ artist_anv = self ._join_artist (artist , anv , join )
435+ artists .append (name )
436+ artists_anv .append (anv )
437+ # Only the first ID is set for the singular field
438+ if not info ["artist_id" ]:
439+ info ["artist_id" ] = discogs_id
440+ info ["artists_ids" ].append (discogs_id )
441+ # Assign fields as necessary
442+ if (a_anv and not album_artist ) or (aa_anv and album_artist ):
443+ info ["artist" ] = artist_anv
444+ info ["artists" ] = artists_anv
445+ else :
446+ info ["artist" ] = artist
447+ info ["artists" ] = artists
448+
449+ if ac_anv :
450+ info ["artist_credit" ] = artist_anv
451+ info ["artists_credit" ] = artists_anv
452+ else :
453+ info ["artist_credit" ] = artist
454+ info ["artists_credit" ] = artists
455+ return info
456+
457+ def _join_artist (self , base : str , artist : str , join : str ) -> str :
458+ # Expand the artist field
459+ if not base :
460+ base = artist
461+ else :
462+ if join :
463+ base += f" { join } "
464+ else :
465+ base += ", "
466+ base += artist
467+ return base
468+
349469 def get_album_info (self , result : Release ) -> AlbumInfo | None :
350470 """Returns an AlbumInfo object for a discogs Release object."""
351471 # Explicitly reload the `Release` fields, as they might not be yet
@@ -375,31 +495,23 @@ def get_album_info(self, result: Release) -> AlbumInfo | None:
375495 return None
376496
377497 artist_data = [a .data for a in result .artists ]
378- album_artist , album_artist_id = self . get_artist_with_anv ( artist_data )
379- album_artist_anv , _ = self .get_artist_with_anv (
380- artist_data , use_anv = True
381- )
382- artist_credit = album_artist_anv
498+ # Information for the album artist
499+ albumartist : AlbumArtistInfo = self .build_albumartistinfo ( artist_data )
500+
501+ # Information from the album artist artist, if it's being used for track artists
502+ track_albumartist : ArtistInfo = self . build_artistinfo ( artist_data )
383503
384504 album = re .sub (r" +" , " " , result .title )
385505 album_id = result .data ["id" ]
386506 # Use `.data` to access the tracklist directly instead of the
387507 # convenient `.tracklist` property, which will strip out useful artist
388508 # information and leave us with skeleton `Artist` objects that will
389509 # each make an API call just to get the same data back.
390- tracks = self .get_tracks (
391- result .data ["tracklist" ],
392- (album_artist , album_artist_anv , album_artist_id ),
393- )
510+ tracks = self .get_tracks (result .data ["tracklist" ], track_albumartist )
394511
395- # Assign ANV to the proper fields for tagging
396- if not self .config ["anv" ]["artist_credit" ]:
397- artist_credit = album_artist
398- if self .config ["anv" ]["album_artist" ]:
399- album_artist = album_artist_anv
400512
401513 # Extract information for the optional AlbumInfo fields, if possible.
402- va = result . data [ "artists" ][ 0 ]. get ( "name" , "" ). lower () == "various"
514+ va = albumartist [ "albumartist" ] == config [ "va_name" ]. as_str ()
403515 year = result .data .get ("year" )
404516 mediums = [t .medium for t in tracks ]
405517 country = result .data .get ("country" )
@@ -431,11 +543,7 @@ def get_album_info(self, result: Release) -> AlbumInfo | None:
431543 cover_art_url = self .select_cover_art (result )
432544
433545 # Additional cleanups
434- # (various artists name, catalog number, media, disambiguation).
435- if va :
436- va_name = config ["va_name" ].as_str ()
437- album_artist = va_name
438- artist_credit = va_name
546+ # (catalog number, media, disambiguation).
439547 if catalogno == "none" :
440548 catalogno = None
441549 # Explicitly set the `media` for the tracks, since it is expected by
@@ -458,9 +566,7 @@ def get_album_info(self, result: Release) -> AlbumInfo | None:
458566 return AlbumInfo (
459567 album = album ,
460568 album_id = album_id ,
461- artist = album_artist ,
462- artist_credit = artist_credit ,
463- artist_id = album_artist_id ,
569+ ** albumartist , # Unpacks values to satisfy the keyword arguments
464570 tracks = tracks ,
465571 albumtype = albumtype ,
466572 va = va ,
@@ -478,7 +584,7 @@ def get_album_info(self, result: Release) -> AlbumInfo | None:
478584 data_url = data_url ,
479585 discogs_albumid = discogs_albumid ,
480586 discogs_labelid = labelid ,
481- discogs_artistid = album_artist_id ,
587+ discogs_artistid = albumartist [ "albumartist_id" ] ,
482588 cover_art_url = cover_art_url ,
483589 )
484590
@@ -503,7 +609,7 @@ def format(self, classification: Iterable[str]) -> str | None:
503609 def _process_clean_tracklist (
504610 self ,
505611 clean_tracklist : list [Track ],
506- album_artist_data : tuple [ str , str , str | None ] ,
612+ albumartistinfo : ArtistInfo ,
507613 ) -> tuple [
508614 list [TrackInfo ],
509615 dict [int , str ],
@@ -531,7 +637,7 @@ def _process_clean_tracklist(
531637 divisions += next_divisions
532638 del next_divisions [:]
533639 track_info , medium , medium_index = self .get_track_info (
534- track , index , divisions , album_artist_data
640+ track , index , divisions , albumartistinfo
535641 )
536642 track_info .track_alt = track ["position" ]
537643 tracks .append (track_info )
@@ -565,7 +671,7 @@ def _process_clean_tracklist(
565671 def get_tracks (
566672 self ,
567673 tracklist : list [Track ],
568- album_artist_data : tuple [ str , str , str | None ] ,
674+ albumartistinfo : ArtistInfo ,
569675 ) -> list [TrackInfo ]:
570676 """Returns a list of TrackInfo objects for a discogs tracklist."""
571677 try :
@@ -578,7 +684,7 @@ def get_tracks(
578684 self ._log .error ("uncaught exception in coalesce_tracks: {}" , exc )
579685 clean_tracklist = tracklist
580686 processed = self ._process_clean_tracklist (
581- clean_tracklist , album_artist_data
687+ clean_tracklist , albumartistinfo
582688 )
583689 (
584690 tracks ,
@@ -754,16 +860,11 @@ def get_track_info(
754860 track : Track ,
755861 index : int ,
756862 divisions : list [str ],
757- album_artist_data : tuple [ str , str , str | None ],
863+ albumartistinfo : ArtistInfo
758864 ) -> tuple [TrackInfo , str | None , str | None ]:
759865 """Returns a TrackInfo object for a discogs track."""
760866
761- artist , artist_anv , artist_id = album_artist_data
762- artist_credit = artist_anv
763- if not self .config ["anv" ]["artist_credit" ]:
764- artist_credit = artist
765- if self .config ["anv" ]["artist" ]:
766- artist = artist_anv
867+ artistinfo = albumartistinfo .copy ()
767868
768869 title = track ["title" ]
769870 if self .config ["index_tracks" ]:
@@ -775,39 +876,19 @@ def get_track_info(
775876
776877 # If artists are found on the track, we will use those instead
777878 if artists := track .get ("artists" , []):
778- artist , artist_id = self .get_artist_with_anv (
779- artists , self .config ["anv" ]["artist" ]
780- )
781- artist_credit , _ = self .get_artist_with_anv (
782- artists , self .config ["anv" ]["artist_credit" ]
783- )
879+ artistinfo = self .build_artistinfo (artists )
880+
784881 length = self .get_track_length (track ["duration" ])
785882
786883 # Add featured artists
787884 if extraartists := track .get ("extraartists" , []):
788- featured_list = [
789- artist
790- for artist in extraartists
791- if "Featuring" in artist ["role" ]
792- ]
793- featured , _ = self .get_artist_with_anv (
794- featured_list , self .config ["anv" ]["artist" ]
795- )
796- featured_credit , _ = self .get_artist_with_anv (
797- featured_list , self .config ["anv" ]["artist_credit" ]
798- )
799- if featured :
800- artist += f" { self .config ['featured_string' ]} { featured } "
801- artist_credit += (
802- f" { self .config ['featured_string' ]} { featured_credit } "
803- )
885+ artistinfo = self .build_artistinfo (extraartists , artistinfo )
886+
804887 return (
805888 TrackInfo (
806889 title = title ,
807890 track_id = track_id ,
808- artist_credit = artist_credit ,
809- artist = artist ,
810- artist_id = artist_id ,
891+ ** artistinfo ,
811892 length = length ,
812893 index = index ,
813894 ),
0 commit comments