from collections import defaultdict from typing import List, Set from smelog.factory import BoundLogger from apollo_playlists_messages.clients.gate_api import GateApiClient from apollo_playlists_messages.config import FULL_APP_NAME from apollo_playlists_messages.constants import FavoriteEntityType, EventCode, MessageTypeEntitie, \ MESSAGE_TYPE_BY_EVENT_CODE_AND_ENTITY from apollo_playlists_messages.handlers.common.get_favorites import get_favorites_accounts from apollo_playlists_messages.handlers.common.parser import parse_event, _get_event_position from apollo_playlists_messages.utils.output import create_messages from apollo_playlists_messages.utils.playlist_id import (starred_id, synonym_top_country_code) def _get_message_type(entity: MessageTypeEntitie, event_code: EventCode): return MESSAGE_TYPE_BY_EVENT_CODE_AND_ENTITY[event_code][entity] def handler( events: List[dict], ignored_playlists: Set[str], gate_api: GateApiClient, logger: BoundLogger, event_code: EventCode ) -> List[dict]: # outcome messages = [] # parse income events dsp_to_isrc_to_track_id_to_playlist_id_to_meta = defaultdict(lambda: defaultdict(lambda: defaultdict(dict))) playlist_id_to_top_codes = {} playlist_starred_id_to_data, track_id_to_data, isrc_entered = {}, {}, set() for event in events: parse_event( event_code=event_code, event=event, dsp_to_isrc_to_track_id_to_playlist_id_to_meta=dsp_to_isrc_to_track_id_to_playlist_id_to_meta, playlist_id_to_top_codes=playlist_id_to_top_codes, playlist_starred_id_to_data=playlist_starred_id_to_data, track_id_to_data=track_id_to_data, isrc_entered=isrc_entered, ignored_playlist_self_ids=ignored_playlists, ) # parse users favorites and settings user_favorite_type_to_id_to_accounts, user_dsp_to_accounts, user_code_to_accounts = ( defaultdict(lambda: defaultdict(set)), defaultdict(set), defaultdict(set), ) user_account_to_devices = {} for favorite_ids, favorite_type in ( (isrc_entered, FavoriteEntityType.TRACK), (playlist_starred_id_to_data.keys(), FavoriteEntityType.PLAYLIST), ): get_favorites_accounts( ids=favorite_ids, entity_type=favorite_type, user_favorite_type_to_id_to_accounts=user_favorite_type_to_id_to_accounts, user_dsp_to_accounts=user_dsp_to_accounts, user_code_to_accounts=user_code_to_accounts, user_account_to_devices=user_account_to_devices, gate_api=gate_api, logger=logger, ) logger.info( f"{FULL_APP_NAME} detected {len(user_favorite_type_to_id_to_accounts[FavoriteEntityType.TRACK])} starred tracks" f", {len(user_favorite_type_to_id_to_accounts[FavoriteEntityType.PLAYLIST])} starred playlists,\n" f"{len(user_account_to_devices)} active accounts: {user_account_to_devices.keys()}\n" f"{len(user_code_to_accounts)} active settings markets: {user_code_to_accounts.keys()}\n" f"to send notifications for." ) # loop over income events to match them with users settings for dsp, isrc_to_track_id_to_playlist_id_to_meta in dsp_to_isrc_to_track_id_to_playlist_id_to_meta.items(): dsp_accounts = user_dsp_to_accounts.get(dsp) if not dsp_accounts: continue for isrc, track_id_to_playlist_id_to_meta in isrc_to_track_id_to_playlist_id_to_meta.items(): isrc_starred_accounts = dsp_accounts & user_favorite_type_to_id_to_accounts[FavoriteEntityType.TRACK].get( isrc, set() ) if not isrc_starred_accounts: continue for track_id, playlist_id_to_meta in track_id_to_playlist_id_to_meta.items(): track_data = track_id_to_data[track_id] for playlist_id, meta in playlist_id_to_meta.items(): playlist_starred_id = starred_id(playlist_id) message_data = dict( dsp=dsp, event_id=meta["event_id"], playlist_id=playlist_id, track=track_data, playlist=playlist_starred_id_to_data[playlist_starred_id], **_get_event_position(meta, event_code) ) playlist_starred_accounts = user_favorite_type_to_id_to_accounts[FavoriteEntityType.PLAYLIST].get( playlist_starred_id, set() ) isrc_starred_and_playlist_not_starred_accounts = isrc_starred_accounts - playlist_starred_accounts # create starred playlist entry messages isrc_starred_and_playlist_starred_accounts = isrc_starred_accounts & playlist_starred_accounts messages.extend( create_messages( account_ids=isrc_starred_and_playlist_starred_accounts, account_id_to_devices=user_account_to_devices, message_type=_get_message_type(MessageTypeEntitie.STARRED, event_code), country_code=playlist_id.code, data=message_data, logger=logger, ) ) # create top playlist entry messages top_codes = playlist_id_to_top_codes[playlist_id] for top_code in top_codes: top_code_entry_accounts = ( isrc_starred_and_playlist_not_starred_accounts & user_code_to_accounts.get(top_code, set()) ) messages.extend( create_messages( account_ids=top_code_entry_accounts, account_id_to_devices=user_account_to_devices, message_type=_get_message_type(MessageTypeEntitie.TOP, event_code), country_code=top_code, data=message_data, logger=logger, ) ) # create top playlists entry messages for 'global' if event contains 'us' top code synonym_top_code = synonym_top_country_code(playlist_id, top_code) if not synonym_top_code: continue synonym_top_entry_accounts = ( isrc_starred_and_playlist_not_starred_accounts & user_code_to_accounts.get(synonym_top_code, set()) - top_code_entry_accounts ) messages.extend( create_messages( account_ids=synonym_top_entry_accounts, account_id_to_devices=user_account_to_devices, message_type=_get_message_type(MessageTypeEntitie.TOP, event_code), country_code=synonym_top_code, data=message_data, logger=logger, ) ) return messages