import logging import math import sentry_sdk from apollo_main_db.apollo.models import StarredContent from apollo_main_db.apple.models import AppleMusicSong from apollo_main_db.spotify.models import SpotifyTrack2 from sentry_sdk.utils import BadDsn from dsp import DigitalServiceProvider from config import Config from db import session_scope logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) SPOTIFY_TRACK_URI = 'spotify:track:' config = Config() try: sentry_sdk.init(dsn=config.SENTRY_DSN) except BadDsn: pass def get_starred_tracks(session): """Get starred tracks with empty isrc.""" return session.query( StarredContent, ).filter( StarredContent.isrc.is_(None) ) def get_vendors_ids(query) -> tuple: """Group tracks ids by vendor. Arguments: query: StarredContent query obj. Returns: tuple: Apple and Spotify list of ids. """ apple_ids, spotify_ids = [], [] uris = [q.uri for q in query] for uri in uris: if not uri.startswith(SPOTIFY_TRACK_URI): apple_ids.append(str(uri)) continue clear_id = uri.replace(SPOTIFY_TRACK_URI, '') spotify_ids.append(str(clear_id)) return apple_ids, spotify_ids def get_spotify_isrcs(session, ids): """Find Spotify ISRC values in DB.""" query = session.query( SpotifyTrack2.id, SpotifyTrack2.isrc ).filter( SpotifyTrack2.id.in_(ids) ).group_by( SpotifyTrack2.id ) return {str(q.id): q.isrc for q in query} def get_apple_isrcs(session, ids): """Find Apple ISRC values in DB.""" query = session.query( AppleMusicSong.id, AppleMusicSong.isrc ).filter( AppleMusicSong.id.in_(ids) ).group_by( AppleMusicSong.id ) return {str(q.id): q.isrc for q in query} def save_isrc_values(session, logger, query, spotify_isrcs=None, apple_isrcs=None, apple_ids=None, spotify_ids=None) -> tuple: """Append ISRC values to already exists records in StarredContent table. Arguments: session: DB session object. logger: Logger object. query: StarredContent query. Keyword Arguments: spotify_isrcs (dict): key-value dict with ids and isrcs for Spotify tracks (default: {}). apple_isrcs (dict): key-value dict with ids and isrcs for Apple tracks (default: {}). apple_ids (list): List of Apple ids values (default: []). spotify_ids (list): List of Spotify ids values (default: []). Returns: tuple: Lists of missing Apple and Spotify ISRCs. """ if spotify_ids is None: spotify_ids = [] if apple_ids is None: apple_ids = [] if apple_isrcs is None: apple_isrcs = {} if spotify_isrcs is None: spotify_isrcs = {} bulk_size = 300.0 steps_num = math.ceil(query.count() / bulk_size) for counter in range(1, steps_num + 1): offset = int((counter - 1) * bulk_size) limit = int(counter * bulk_size) logger.info(f"Step {counter}/{steps_num}") _query = query.offset(offset).limit(limit) for q in _query: is_spotify = q.uri.startswith(SPOTIFY_TRACK_URI) _id = q.uri.replace(SPOTIFY_TRACK_URI, "") if is_spotify else q.uri isrc = spotify_isrcs.get(_id) if is_spotify else apple_isrcs.get(_id) if not isrc: continue q.isrc = isrc session.add(q) if is_spotify and spotify_ids: spotify_ids.remove(_id) elif apple_ids and not is_spotify: apple_ids.remove(_id) session.commit() _spotify_ids = [id for id in spotify_ids if id not in ['', 'foo', None]] _apple_ids = [id for id in apple_ids if id not in ['', 'foo', None]] return _apple_ids, _spotify_ids def main() -> None: """Script entry point.""" logger.info('Start') dsp = DigitalServiceProvider(config=config, logger=logger) with session_scope(config) as session: no_isrc_starred_tracks = get_starred_tracks(session) apple_ids, spotify_ids = get_vendors_ids(no_isrc_starred_tracks) spotify_isrcs = get_spotify_isrcs(session, spotify_ids) apple_isrcs = get_apple_isrcs(session, apple_ids) apple_ids, spotify_ids = save_isrc_values( session, logger, query=no_isrc_starred_tracks, spotify_isrcs=spotify_isrcs, apple_isrcs=apple_isrcs, apple_ids=apple_ids, spotify_ids=spotify_ids) missing_spotify_isrcs, missing_apple_isrcs = {}, {} if spotify_ids: logger.info(f'Looking for missing Spotify ISRC values in DSP:') missing_spotify_isrcs = dsp.get_isrc_for_spotify_tracks(spotify_ids) if apple_ids: logger.info(f'Looking for missing Apple ISRC values in DSP:') missing_apple_isrcs = dsp.get_isrc_for_apple_tracks(apple_ids) if missing_apple_isrcs or missing_spotify_isrcs: logger.info(f'Apple IDs num: {len(apple_ids)}') logger.info(f'Spotify IDs num: {len(spotify_ids)}') missing_isrc_tracks = get_starred_tracks(session) apple_ids, spotify_ids = save_isrc_values( session, logger, query=missing_isrc_tracks, spotify_isrcs=missing_spotify_isrcs, apple_isrcs=missing_apple_isrcs, apple_ids=apple_ids, spotify_ids=spotify_ids) logger.info(f'Missing Apple ISRCs num: {len(apple_ids)}') logger.info(f'Missing Spotify ISRCs num: {len(spotify_ids)}') logger.info(f'Done!') if __name__ == '__main__': main()