from datetime import date from aiohttp import web from aiohttp_apispec import docs, json_schema, response_schema, querystring_schema from typing import Any, Dict from server.artist.constants import EXTERNAL_LINKS_GROUPS from server.artist.decorators import Helper from server.artist.repositories import ArtistRepo from server.artist.helpers.discovery import ArtistDiscoveryHelper from server.artist.helpers.search_by_name import ArtistSearchByNameHelper from server.artist.schemas import ( VideosTiktokResponseSchema, VideosYoutubeResponseSchema, SpotifyTracksResponseSchema, SpotifyAlbumResponseSchema, SoundCloudTracksResponseSchema, ArtistExternalLinksResponseSchemaV4, ArtistSearchByNameRequestSchema, ArtistSearchByNameResponseSchema, ArtistDiscoveryRequestSchema, ArtistDiscoveryResponseSchema, ArtistDiscoveryResultsResponseSchema, ArtistDiscoveryCountRequestSchema, ArtistDiscoveryCountResponseSchema, ) from server.artist.tiktok.repositories import TiktokRepo from server.artist.utils import ImageService from server.artist.youtube.repositories import YoutubeRepo from server.artist.spotify.repositories import SpotifyRepo from server.artist.soundcloud.repositories import SoundCloudRepo from server.utils import ( group_external_links_v4, order_header_external_links, make_contry_obj_from_results, make_genres_obj_from_results, ) @docs(tags=["artist", "discovery"], description="Artist discovery") @json_schema(ArtistDiscoveryRequestSchema) @response_schema(ArtistDiscoveryResponseSchema) async def discovery(request: web.Request) -> web.Response: def form_response(results: list) -> web.Response: for result in results: result["country"] = make_contry_obj_from_results(result) result["genres"] = make_genres_obj_from_results(result) return web.json_response(ArtistDiscoveryResponseSchema().dump(results, many=True)) if not request.body_exists: return form_response([]) params: dict = await request.json() params = ArtistDiscoveryRequestSchema().load(params) results = await ArtistDiscoveryHelper.search(params) return form_response(results) @docs(tags=["artist", "search_by_name"], description="Artist search by name") @querystring_schema(ArtistSearchByNameRequestSchema) @response_schema(ArtistSearchByNameResponseSchema) async def search_by_name(request: web.Request) -> web.Response: def form_response(results: list) -> web.Response: return web.json_response(ArtistSearchByNameResponseSchema().dump(results, many=True)) params: dict = ArtistSearchByNameRequestSchema().load(request.rel_url.query) if not params: return form_response([]) results = await ArtistSearchByNameHelper.search(params) return form_response(results) @docs(tags=["artist", "discovery", "count"], description="Artist discovery total count") @json_schema(ArtistDiscoveryCountRequestSchema) @response_schema(ArtistDiscoveryCountResponseSchema) async def discovery_total_count(request: web.Request) -> web.Response: def form_response(total_count: int) -> web.Response: return web.json_response(ArtistDiscoveryCountResponseSchema().dump({"total_count": total_count})) params: dict = ArtistDiscoveryCountRequestSchema().load(await request.json()) result = await ArtistDiscoveryHelper.count(params) return form_response(total_count=result) @docs(tags=["artist", "discovery", "result"], description="Artist discovery result") @response_schema(ArtistDiscoveryResultsResponseSchema) @Helper.args_decompose() async def discovery_artist_result(request: web.Request, id: int) -> web.Response: def form_response(result: Dict[str, Any]) -> web.Response: result["country"] = make_contry_obj_from_results(result) result["genres"] = make_genres_obj_from_results(result) return web.json_response(ArtistDiscoveryResultsResponseSchema().dump(result)) result = await ArtistDiscoveryHelper.get(str(id)) if not result: return web.json_response(status=web.HTTPNotFound.status_code) return form_response(result) @docs(tags=["artist", "tracks", "spotify"], description="Related artist's spotify tracks") @response_schema(SpotifyTracksResponseSchema) @Helper.args_decompose() async def tracks_spotify(request: web.Request, id: str) -> web.Response: results: list = await SpotifyRepo.get_tracks(str(id)) # it's only chart-metric ID's are integer return web.json_response(SpotifyTracksResponseSchema().dump(results, many=True)) @docs(tags=["artist", "albums", "spotify"], description="Spotify artist albums") @response_schema(SpotifyAlbumResponseSchema) @Helper.args_decompose() async def albums_spotify(request: web.Request, id: int) -> web.Response: def form_response(results: list) -> web.Response: for result in results: result["artwork_url"] = ( ImageService.get_album_img_url(result.pop("spotify_album_id")) if "spotify_album_id" in result else None ) result["release_date"] = ( date.fromisoformat(result.pop("release_date")) if "release_date" in result else None ) return web.json_response(SpotifyAlbumResponseSchema().dump(results, many=True)) results: list = await SpotifyRepo.get_albums(str(id)) # it's only chart-metric ID's are integer return form_response(results) @docs(tags=["tiktok", "artist", "videos"], description="Tiktok artist videos") @response_schema(VideosTiktokResponseSchema) @Helper.args_decompose() async def artist_videos_tiktok(request: web.Request, id: int) -> web.Response: results = await TiktokRepo.get_artist_videos(str(id)) # it's only chart-metric ID's are integer return web.json_response(VideosTiktokResponseSchema().dump(results, many=True)) @docs(tags=["youtube", "artist", "videos"], description="Youtube artist videos") @response_schema(VideosYoutubeResponseSchema) @Helper.args_decompose() async def artist_videos_youtube(request: web.Request, id: int) -> web.Response: results = await YoutubeRepo.get_artist_videos(str(id)) # it's only chart-metric ID's are integer return web.json_response(VideosYoutubeResponseSchema().dump(results, many=True)) @docs(tags=["artist", "tracks", "soundcloud"], description="Related artist's soundcloud tracks") @response_schema(SoundCloudTracksResponseSchema) @Helper.args_decompose() async def tracks_soundcloud(request: web.Request, id: str) -> web.Response: results: list = await SoundCloudRepo.get_tracks(str(id)) # it's only chart-metric ID's are integer return web.json_response(SoundCloudTracksResponseSchema().dump(results, many=True)) # ================================= v4 views ================================= @docs(tags=["artist", "external_links"], description="artist external links") @response_schema(ArtistExternalLinksResponseSchemaV4) @Helper.args_decompose() async def external_links_v4(request: web.Request, id: int) -> web.Response: links = await ArtistRepo.get_external_links(str(id)) # it's only chart-metric ID's are integer results = group_external_links_v4(EXTERNAL_LINKS_GROUPS, links) results = order_header_external_links(results) return web.json_response(ArtistExternalLinksResponseSchemaV4().dump(results))