"""Helpers for track-level metadata in v38.""" from typing import Dict, List, Optional from soundrecording_utils.constants.ddex import constants from soundrecording_utils.ddex.utils.control_chars import remove_control_chars from soundrecording_utils.metadata.types import Track, TrackParticipation from .e import E # 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', remove_control_chars(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 ), ) 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. 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()) ]