from aiohttp import web from aiohttp_apispec import docs, querystring_schema from apollo_utils.service.clients.aiohttp.utils.response import dump_response_schema from datetime import date, timedelta from typing import List, Optional from server.constants import BASE_API_PREFIX from server.constants.charts import ChartBreakdown from server.constants.delphi.chart import ChartAnalyticsGroupBy from server.schemas.charts.tracks import TracksPositions from server.utils.charts import get_chart_id from server.utils.delphi.converters import str_to_date from server.utils.delphi.misc import fix_position_list router = web.RouteTableDef() def get_tracks_positions_response( start_date: Optional[date] = None, end_date: Optional[date] = None, in_chart: int = 0, min_position: Optional[int] = None, max_position: Optional[int] = None, item_list: List[dict] = None, ): return web.json_response( { "start_date": start_date.isoformat() if start_date else None, "end_date": end_date.isoformat() if end_date else None, "in_chart": in_chart, "peak_position": min_position, "min_position": max_position, "items": item_list or [], } ) @router.get(BASE_API_PREFIX + "/charts/tracks/positions/") @docs( tags=["positions", "tracks", "spotify", "apple"], summary="Get Spotify or Apple track positions for dates range.", description="Returns track positions over time.", ) @querystring_schema(TracksPositions.Request) @dump_response_schema(TracksPositions.Response) async def get_tracks_positions(request: web.Request) -> web.Response: api = request.app["delphi_java_api"] params = request["querystring"] dsp, country_code, chart_breakdown, start_date, end_date, with_null, force_dates = ( params["dsp"], params["country_code"], params["chart_breakdown"], params["start_date"], params["end_date"], params["with_null"], params["force_dates"], ) result = await api.get_charts_analytics( dsp=dsp.value, chart_id=get_chart_id(dsp=dsp, chart_breakdown=chart_breakdown, country_code=country_code), start_date=start_date or date(1900, 1, 1), end_date=end_date or (date.today() + timedelta(weeks=1)), isrc_list=[params["isrc"]], metrics=["positions"], group_by=ChartAnalyticsGroupBy.ISRC, ) if not result: return get_tracks_positions_response() result = result[0] position_list = result.get("metrics", {}).get("positions", []) min_date, max_date = str_to_date(result["min_date"]), str_to_date(result["max_date"]) if force_dates and start_date and end_date and position_list: position_list = fix_position_list(position_list, min_date, max_date, start_date, end_date) else: start_date, end_date = min_date, max_date in_chart = 0 item_list = [] for index, position in enumerate(position_list): current_date = start_date + timedelta(days=index) if position is None: if not with_null or (chart_breakdown == ChartBreakdown.WEEKLY and current_date.weekday() != 3): continue else: in_chart += 1 item_list.append({"date": current_date.isoformat(), "position": position}) return get_tracks_positions_response( start_date, end_date, in_chart, result["min_position"], result["max_position"], item_list )