from apollo_utils.core.constants.dsp import DSP from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union from server.cache.base import get_cache, get_value_by_key_template from server.config import DELPHI_CURRENT_PLAYLISTS_BY_TRACK_TTL from server.constants import cache_keys from server.constants.playlists.delphi.by_api.track_positions_playlists import TrackPositionsPlaylists, \ TrackPositionsPlaylistsApolloToDelphiProcessedFieldsSortByMapping from server.constants.playlists.v0.misc import StreamsTypeRequest from server.scenarios.playlists.by_track.extended.common import get_track_playlists_extended from server.utils.filter import apply_filter_processors from server.utils.mappers.core.getters import getter from server.utils.mappers.playlists.misc import map_streams_metrics from server.utils.pagination import multikeysort from server.utils.playlists.common.categories import check_item_category_id from server.utils.playlists.common.dates import get_item_is_recent, get_min_added_date from server.utils.playlists.common.mappers import map_fields_by_dict_values from server.utils.playlists.common.streams import current_streams_are_not_zero from server.utils.playlists.common.streams_type import get_streams_type, get_streams_type_request_from_str from server.utils.processor import processor from server.utils.processor.core import Processor from server.utils.search import check_item_by_search def _get_current_playlists_by_track_ago_filter_processors( recent_adds_only: bool, search: str, keep_zero_streams: bool, category_id: int = None ) -> Iterable[Union[Callable, Processor]]: """Get additional filter processors Args: recent_adds_only: Bool value to filter playlists that are recently added search: search for a specific item keep_zero_streams: keep items with zero streams Returns: List of processors """ processors = [] if recent_adds_only: processors.append( processor( get_item_is_recent, track_in_playlist_date_key="last_added_date_time", date_to_compare=get_min_added_date(recent_adds_only), ) ) if search: processors.append(processor(check_item_by_search, search_in=["playlist.name"], search=search, occurrence=all)) if not keep_zero_streams: processors.append(processor(current_streams_are_not_zero, current_streams_key="current_streams")) if category_id: processors.append( processor( check_item_category_id, item_category_id_key="playlist.owner.owner_category.owner_category_id", category_id=category_id, ) ) return processors async def _current_playlists_by_track_map_streams_and_filter_items_ago( playlists: [Dict[str, Any]], keep_zero_streams: bool, recent_adds_only: bool, search: str, streams_type: StreamsTypeRequest, streams_country_code: str, category_id: Optional[int] = None, ) -> Tuple[List[Any], List[Dict[str, Any]], Any]: """Get Track in playlists items, Categories, Streams Type of passed list of track in playlist items Args: playlists: List of track in playlist items keep_zero_streams: Bool value to keep items with zero or None streams streams_type: Preferable streams type TRACK or PLAYLIST to be mapped to "current_streams" and "prev_streams" keys of an original track in playlist item. Will be calculated based on list of items if streams type PRIORITY passed streams_country_code: Streams country code category_id: Playlist category filter Returns: Track in Playlists, Categories, Streams Type """ result = [] categories = set() filters = _get_current_playlists_by_track_ago_filter_processors( recent_adds_only, search, keep_zero_streams, category_id ) for item in playlists["items"]: map_streams_metrics(item, streams_country_code, streams_type, return_current_streams=True) if all(apply_filter_processors(filters, item)): categories.add(getter(item, key="playlist.owner.owner_category.owner_category_id")) result.append(item) categories = [i for i in playlists["categories"] if i["owner_category_id"] in categories] return result, categories, streams_type.value async def _get_current_playlists_dsp_by_track_ago_processed_data( dsp: DSP, isrc: str, markets_list: Optional[List[str]] = None, streams_market: Optional[Union[str, None]] = None, streams_type: StreamsTypeRequest = StreamsTypeRequest.PRIORITY, ) -> Tuple[Dict[str, Any], StreamsTypeRequest]: """Get cached Track In Playlists with streams_type data or make a call and calculate streams_type Args: dsp: Playlist DSP Filter isrc: ISRC markets_list: Playlist country code filter. streams_market: Streams country code list. streams_type: Type of requested streams. Returns: Track In Playlist & Categories, Streams Type """ default_cache_key_kwargs = { "dsp": dsp, "isrc": isrc, "markets_list": markets_list, "streams_market": streams_market, } cache_client = get_cache() cache_value, cache_key = await get_value_by_key_template( cache_key_template=cache_keys.V3_BASE_CURRENT_TRACK_IN_PLAYLIST_EXTENDED, kwargs=default_cache_key_kwargs, str_to_date=False, cache_client=cache_client, ) if cache_value: streams_type = ( get_streams_type_request_from_str(cache_value.pop("streams_type")) if streams_type == StreamsTypeRequest.PRIORITY else streams_type ) return cache_value, streams_type playlists_by_track = await get_track_playlists_extended( dsp=dsp, isrc=isrc, delphi_include=[ TrackPositionsPlaylists.INCLUDE.PLAYLISTS, TrackPositionsPlaylists.INCLUDE.STREAMS_FOR_PERIOD, TrackPositionsPlaylists.INCLUDE.NUM_TRACKS, TrackPositionsPlaylists.INCLUDE.META_OWNER_CATEGORIES, TrackPositionsPlaylists.INCLUDE.PLAYLIST_DATES, ], country_code=markets_list, streams_country_code=[streams_market], ) streams_type = await get_streams_type(playlists_by_track["items"], streams_type, streams_market) playlists_by_track["streams_type"] = streams_type await cache_client.set(cache_key, DELPHI_CURRENT_PLAYLISTS_BY_TRACK_TTL, playlists_by_track) return playlists_by_track, streams_type async def get_current_playlists_dsp_by_track_ago( dsp: DSP, isrc: str, markets_list: Optional[List[str]] = None, streams_market: Optional[Union[str, None]] = None, search: Optional[str] = None, category_id: Optional[int] = None, recent_adds_only: Optional[bool] = False, order_by: Optional[List[str]] = None, keep_zero_streams: bool = True, streams_type: StreamsTypeRequest = StreamsTypeRequest.PRIORITY, ) -> Dict[str, List[Dict[str, Any]]]: """Get Dict of current track in playlists items with categories that are presented in list of items and a streams_type value that points to "current_streams" and "prev_streams" fields to describe whether its Track or Playlist streams (AGO Scenario) Args: dsp: Playlist DSP filter. isrc: ISRC. markets_list: Playlist country code filter. streams_market: Streams country code list. search: Search str part of text presented in playlist name. category_id: Playlist category filter. recent_adds_only: Bool value to filter playlists that are recently added order_by: Items order by provided on apollo side only keep_zero_streams: Bool value whether to keep items with zero or None streams streams_type: Type of requested streams. Returns: Track in playlists, Categories, Streams Type { "items": List of track in playlists "categories": categories present in track in playlists items "streams_type": str value that describes streams if its Track or Playlists streams mapped in current_streams and prev_streams item keys. } """ playlists_by_track, streams_type = await _get_current_playlists_dsp_by_track_ago_processed_data( dsp=dsp, isrc=isrc, markets_list=markets_list, streams_market=streams_market, streams_type=streams_type, ) items, categories, streams_type = await _current_playlists_by_track_map_streams_and_filter_items_ago( playlists=playlists_by_track, keep_zero_streams=keep_zero_streams, recent_adds_only=recent_adds_only, search=search, streams_type=streams_type, streams_country_code=streams_market, category_id=category_id, ) if order_by: items = multikeysort( items, map_fields_by_dict_values(order_by, TrackPositionsPlaylistsApolloToDelphiProcessedFieldsSortByMapping), ) return {"items": items, "categories": categories, "streams_type": streams_type}