from datetime import date from typing import List, Optional, Tuple from server import config from server.constants.delphi.streams.include import INNER_FIELDS_MAPPING from server.constants.delphi.tiktok import TiktokTrackAnalyticsBreakdown def resolve_streams_include(include_list: Optional[List[str]]) -> Optional[List[str]]: """Resolve inner include types for streams endpoint.""" if not include_list: return include_list resolved = [] inner_fields = INNER_FIELDS_MAPPING.keys() for include in include_list: if include in inner_fields: resolved.extend(list(INNER_FIELDS_MAPPING[include])) else: resolved.append(include) return list(set(resolved)) def nullable_min(*args): """Min of several arguments with possible None values within.""" values = [i for i in args if i is not None] if not values: return None return min(values) def nullable_max(*args): """Max of several arguments with possible None values within.""" values = [i for i in args if i is not None] if not values: return None return max(values) def fix_position_list( values: List[int or None], response_min_date: date, response_max_date: date, result_min_date: date, result_max_date: date, ) -> List[int or None]: """Add some None values to a list (grouped by day values). Args: values: List of day values. response_min_date: Min date of the current response. response_max_date: Max date of the current response. result_min_date: Min date of a common result. result_max_date: Max date of a common result. Returns: Modified list. """ return ( [None] * (response_min_date - result_min_date).days + values + [None] * (result_max_date - response_max_date).days ) def update_breakdowns_for_totals(breakdowns_list: List[str]) -> List[str]: """Replace not supported breakdowns with other to use that breakdown results for calculating totals. Args: breakdowns_list: Original breakdowns list. Returns: Updated breakdowns list. """ breakdowns_list = list(breakdowns_list) if TiktokTrackAnalyticsBreakdown.TOTALS in breakdowns_list: breakdowns_list.remove(TiktokTrackAnalyticsBreakdown.TOTALS) if TiktokTrackAnalyticsBreakdown.COUNTRY_TOTALS not in breakdowns_list: breakdowns_list.append(TiktokTrackAnalyticsBreakdown.COUNTRY_TOTALS) return breakdowns_list async def request_related_isrc(original_isrc_list: List[str], field_name: str, *args, **kwargs): """Request related ISRC list. Args: original_isrc_list: ISRC list. """ if not kwargs.get("related_isrcs", True): return original_isrc_list client = args[0] if config.TIKTOK_MERGE_ISRC_ONLY_FIRST: original_isrc_list = [original_isrc_list[0]] response = await client.get_tracks(isrc=original_isrc_list, include="related_isrcs", group_by="isrc") result = list(set(j for i in response if i["related_isrcs"] for j in i["related_isrcs"])) return result or original_isrc_list def fill_skipped_dates( result: dict, items_key: str, request_dates: Tuple[date, date], request_dates_iso: Tuple[str, str] = None ) -> dict: """Add null(s) for skipped items in the both ends.""" response_dates = date.fromisoformat(result["start_date"]), date.fromisoformat(result["end_date"]) if request_dates == response_dates: return result if response_dates[0] < request_dates[0]: # first requested date > latest available result[items_key] = [None] * ((request_dates[1] - request_dates[0]).days + 1) else: items = result[items_key] result[items_key] = ( [None] * (response_dates[0] - request_dates[0]).days + items + [None] * (request_dates[1] - response_dates[1]).days ) result["start_date"], result["end_date"] = request_dates_iso or [d.isoformat() for d in request_dates] return result