"""Interface to the ows-sound-recordings service.""" from flask import g from owsrequest import request from backend.constants import error from backend.constants import header from backend.constants import services from backend.exceptions import RequestError ISRC_REQUEST_BATCH_SIZE = 50 def get_track_matches(params): """Get fingerprint-based matches for tracks.""" headers = {} if g.request_context.profile_type: headers.update(**{header.ORCHARD_PROFILE_TYPE: g.request_context.profile_type}) if g.request_context.roles: headers.update(**{header.ORCHARD_ROLES: ','.join(g.request_context.roles)}) response = request.get( service_name=services.OWS_SOUND_RECORDINGS, path='/sound_recordings/cr', params=params, headers=headers ) if response.status_code == 404: return [] elif response.status_code != 200: raise RequestError( f'Failed to get fingerprint matches for {params}. ' f'Error: {response.text}', error_code=error.OWS_SOUND_RECORDINGS_ERROR, http_status=response.status_code, ) return response.json() def get_formatted_sound_recording_matches(product_id): """Format get_track_matches response into a dict keyed by track id.""" params = { 'product_id': product_id, 'include_transfer_to_content': True } matches = get_track_matches(params) return parse_sound_recording_matches(matches, product_id) def parse_sound_recording_matches(matches, product_id): """Parse get_track_matches response.""" parsed = {} for sound_recording in matches: parsed_matches = parse_asset_array(sound_recording.get('assets'), product_id) if parsed_matches: parsed[parsed_matches['tuid']] = parsed_matches return parsed def parse_asset_array(assets, product_id): """Parse asset array.""" product_track = {} matched_tracks = [] for asset in assets: tracks = asset.get('tracks', []) if not tracks: continue for track in tracks: if track.get('product_id') == product_id: product_track = track elif track.get('release_status') == 'in_content': matched_tracks.append(track) if not product_track or not product_track.get('tuid'): return None return { 'tuid': product_track.get('tuid'), 'isrc': product_track.get('isrc'), 'matched_tracks': matched_tracks } def parse_track_isrc_matches(matches, product_id, tuids): """Parse get_track_matches response.""" result = { 'osrs_to_tracks': {}, 'tuids_to_osr_ids': {tuid: None for tuid in tuids} } for sound_recording in matches: if not sound_recording or 'assets' not in sound_recording or not sound_recording['assets']: continue current_osr_id = sound_recording.get('id') if not current_osr_id: continue if current_osr_id not in result['osrs_to_tracks']: result['osrs_to_tracks'][current_osr_id] = [] for asset in sound_recording['assets']: if not asset or 'tracks' not in asset or not asset['tracks']: continue for track in asset['tracks']: if not _validate_osr_track(track): continue if track['product_id'] != product_id and track['release_status'] == 'in_content': result['osrs_to_tracks'][current_osr_id].append(track) elif track['tuid'] in result['tuids_to_osr_ids']: result['tuids_to_osr_ids'][track['tuid']] = current_osr_id return result def _validate_osr_track(track): """Validate osr track data.""" if not track.get('release_status'): return False if not track.get('product_id'): return False if not track.get('isrc'): return False if not track.get('tuid'): return False return True def get_formatted_isrc_matches(product_id, track_isrcs, tuids): """Get list of ISRC-based track matches as a formatted response.""" matches = [] for batch in split_isrc_list(track_isrcs): filtered_batch = [i for i in batch if i] if filtered_batch: params = { 'track_isrcs': ','.join(filtered_batch), 'include_transfer_to_content': True } matches += get_track_matches(params) return parse_track_isrc_matches(matches, product_id, tuids) def split_isrc_list(track_isrcs): """Split list into chunks of size ISRC_REQUEST_BATCH_SIZE.""" for i in range(0, len(track_isrcs), ISRC_REQUEST_BATCH_SIZE): yield track_isrcs[i:i + ISRC_REQUEST_BATCH_SIZE]