"""Helpers for track-level metadata.""" from typing import Dict from typing import List from typing import Optional from .e import E from ..constants import ddex as constants from soundrecording_utils.metadata.types import Track from soundrecording_utils.metadata.types import TrackParticipation # This mapping is deliberately incomplete. Only roles included in the keys # will be added in to the resulting DDEX as DisplayArtist nodes. _display_artist_lookup_table = { 'performer': 'MainArtist', 'featuring': 'FeaturedArtist', 'track_writer': 'Composer', 'producer': 'Producer', 'remixer': 'Remixer', } def generate_p_line(p_info: Optional[str]): """Generate DDEX for a PLine from the string.""" return E( 'PLine', E('PLineText', f'(P) {p_info}') ) def generate_display_artist_name( participations: List[TrackParticipation] ): """Format primary artist names into single tag.""" display_names = [ x.participant.name for x in participations if x.participated_as == 'performer' ] if len(display_names) == 0: result = '' elif len(display_names) == 1: result = display_names[0] elif len(participations) > 3: result = 'Various Artists' else: result = ' & '.join([ ', '.join(display_names[:-1]), display_names[-1] ]) return E( 'DisplayArtistName', result ) def _generate_display_artist( sequence_number: int, participations: List[TrackParticipation], ): return E( 'DisplayArtist', { 'SequenceNumber': f'{sequence_number}', }, E( 'PartyName', E('FullName', participations[0].participant.name), ), E( 'PartyId', { 'Namespace': constants.ORCHARD_PARTY_NAME, }, participations[0].participant.uuid, ), *( E( 'ArtistRole', _display_artist_lookup_table[participation.participated_as], ) for participation in participations ), # TODO: ResourceContributors # TODO: IndirectResourceContributors ) def generate_track_display_artists(track_metadata: Track): """Generate DisplayArtist nodes for a given Track.""" filtered_participations = [ participation for participation in track_metadata.participations if participation.participated_as in _display_artist_lookup_table ] # Note: As of Python 3.7 dict iteration order is the same as insertion. # We are assuming that GraphQL returns these correctly ordered, but that # is not currently the case. unique_participants: Dict[str, List[TrackParticipation]] = {} for participation in filtered_participations: participant_uuid = participation.participant.uuid if participant_uuid not in unique_participants: unique_participants[participant_uuid] = [] unique_participants[participant_uuid].append(participation) return [ _generate_display_artist(i + 1, participations) for (i, (uuid, participations)) in enumerate(unique_participants.items()) ]