import re from common.connectors.graphql import GraphQLException from common.connectors.graphql import obo_graphql as graphql from common.schemas.ingestion import ( ProductArtist, ProductInfo, ProjectArtist, TrackArtist, ) from lambdacommon.common_config import logger from src.constants import LABEL_PARTICIPANT_ID_CONFLICT, RetryException from src.schemas import ArtistInfo, ArtistResult SPOTIFY_URI_PREFIX = "spotify:artist:" def process_artist( artist_info: ArtistInfo, vendor_id: int, subaccount_id: int | None = None, ) -> ArtistResult: """Get or create an artist and a related label participant for passed vendor and subaccount.""" logger.info( f"Started processing artist '{artist_info.name}', " f"vendor_id={vendor_id}, subaccount_id={subaccount_id}" ) get_artist_result = graphql.get_artist_by_name(artist_info.name, vendor_id) if get_artist_result: artist_id = get_artist_result.id logger.info(f"Artist name='{artist_info.name}' already exists. Id={artist_id}.") else: create_artist_result = graphql.create_artist( artist_info.name, vendor_id, subaccount_id ) artist_id = create_artist_result.id logger.info(f"Artist name='{artist_info.name}' was created. Id={artist_id}.") try: label_participant_result = graphql.get_or_create_label_participant( artist_name=artist_info.name, vendor_id=vendor_id, subaccount_id=subaccount_id, spotify_id=artist_info.spotify_id, apple_id=artist_info.apple_id, ) logger.info( f"Label participant name='{artist_info.name}' was got or created. " f"UUID={label_participant_result.uuid}." ) except GraphQLException as exc: if re.match(LABEL_PARTICIPANT_ID_CONFLICT, str(exc)): raise RetryException("Label Participant id generation conflict") from exc raise return ArtistResult( artist_id=artist_id, label_participant_uuid=label_participant_result.uuid, ) def _add_artist_info( artist: ProjectArtist | ProductArtist | TrackArtist, name_to_artist_info: dict[str, ArtistInfo], ) -> dict[str, ArtistInfo]: """Extract artist data from an artist instance and put it into the common collection in the universal ArtistInfo type. """ if artist and artist.name not in name_to_artist_info: name_to_artist_info[artist.name] = ArtistInfo( name=artist.name, # create label_participant mutation requires a spotify_id without the prefix spotify_id=artist.spotify_uri.removeprefix(SPOTIFY_URI_PREFIX) if artist.spotify_uri else None, apple_id=artist.apple_id, ) return name_to_artist_info def get_artists_info(product_info: ProductInfo) -> list[ArtistInfo]: """Get combined list of artists from project, product and tracks packed in the universal ArtistInfo type.""" name_to_artist_info: dict[str, ArtistInfo] = {} _add_artist_info(product_info.project.artist, name_to_artist_info) for product_artist in product_info.product.display_artists or []: _add_artist_info(product_artist, name_to_artist_info) for track in product_info.tracks or []: for track_artist in track.display_artists or []: _add_artist_info(track_artist, name_to_artist_info) return list(name_to_artist_info.values())