from datetime import date from typing import Any, Dict, Tuple from server.legacy.consumer_analytics.vendors.base import BaseVendor from server.legacy.core.constants import SPOTIFY, SPOTIFY_URI_PREFIX TRACKS_PER_COUNTRY_FIELDS = ("streams", "listeners", "shuffle_play") TRACKS_PER_COUNTRY_SOURCE_FIELDS = ( "album", "artist", "chart", "collection", "daily_mix", "discover_weekly", "other", "others_playlist", "play_queue", "radio", "release_radar", "search", "unknown", ) TRACKS_PER_COUNTRY_PACKED_FIELDS = {"source": TRACKS_PER_COUNTRY_SOURCE_FIELDS} class SpotifyVendor(BaseVendor): """Spotify vendor class for Consumer Analytics client.""" vendor = SPOTIFY @classmethod def parse_sources(cls, item: dict, keys: Tuple[tuple, dict], **kwargs) -> dict: """Parse streaming data. Args: item: Delphi streaming data. keys: Key fields. Returns: Dict with key data. """ flat_keys, packed_keys = keys data = {key: kwargs.get(key) or item.get(key, 0) for key in flat_keys} for key, fields in packed_keys.items(): for field in fields: data[cls.to_camel_case(field, key)] = item[key].get(field, 0) return data @classmethod def parse_date_item( cls, _date: date, date_item: Dict[str, Any], keys: Tuple[tuple, dict], **kwargs ) -> Dict[str, Any]: """Parse streams and source types data map for particular date from compact to full format. Args: _date: date key. date_item: data map to parse. keys: iterable of keys to get data from passed data map by. Returns: { "date": _date, "streams": number of streams, "listeners": number of listeners, "shuffle_play": number of streams by shuffle_play, "sourceAlbum": number of streams per album source, ... "sourceUnknown": number of streams per unknown source } """ result = {"date": _date, **cls.parse_sources(date_item, keys)} if kwargs.get("include_owner_categories"): result["ownerCategories"] = {"Unknown": 0} return result @staticmethod def get_data_item_keys(streams_only: bool = False) -> Tuple[tuple, dict]: """Return iterable of keys for date streams item. Returns: tuple of: tuple of flat fields keys, tuple of packed fields keys. """ if streams_only: return ("streams",), {} return TRACKS_PER_COUNTRY_FIELDS, TRACKS_PER_COUNTRY_PACKED_FIELDS @classmethod def convert_item_to_track_compat_v2(cls, streams_count: int, streams_info: dict) -> dict: source_info = streams_info["source"] return { "lst": streams_info.get("listeners", 0), "spl": streams_info["shuffle_play"], "str": streams_count, "src": [ source_info["album"], source_info["artist"], source_info["chart"], source_info["collection"], source_info.get("daily_mix", 0), source_info.get("discover_weekly", 0), source_info["other"], source_info["others_playlist"], source_info["play_queue"], source_info["radio"], source_info.get("release_radar", 0), source_info["search"], source_info.get("unknown", 0), ], } @classmethod def convert_item_to_track_compat_v1( cls, streams_count: int, streams_info: dict, item_date: date, item: dict ) -> dict: pass @staticmethod def generate_tracks_playlists_summary_result( data: Dict[str, Dict[str, int]], include_shuffle: bool, all_markets: bool = False, add_isrc: bool = False ) -> list: def get_item(_id, item): res = {"localStreams": item.get("l_st", 0), "globalStreams": item["g_st"], "daysStreamed": item["g_d"]} if include_shuffle: res.update( { "playlistUri": f"{SPOTIFY_URI_PREFIX}{_id}", "localShuffleStreams": item.get("l_sh", 0), "globalShuffleStreams": item["g_sh"], } ) else: res["playlistId"] = _id if add_isrc: res["isrc"] = item.get("isrc") return res return [get_item(playlist_id, stats_item) for playlist_id, stats_item in data.items()] @staticmethod def generate_tracks_playlists_per_day_item( streams_date: date or None, streams_item: Dict[str, int], include_shuffle: bool, market_field: str = "local" ) -> dict: item = {f"{market_field}Streams": streams_item.get("l_st", 0), "globalStreams": streams_item["g_st"]} if include_shuffle: item.update( { f"{market_field}ShuffleStreams": streams_item.get("l_sh", 0), "globalShuffleStreams": streams_item["g_sh"], } ) if streams_date: item["date"] = streams_date return item @classmethod def parse_streams_from_release_to_date_item(cls, market: str, streams_count: int, streams_info: dict) -> dict: streams_info["streams"] = streams_count return { "countryCode": market, "data": cls.parse_sources(streams_info, (("streams",), TRACKS_PER_COUNTRY_PACKED_FIELDS)), }