import logging from django.conf import settings from django.http import HttpResponse from django.shortcuts import render, redirect from rest_framework import status from rest_framework.decorators import api_view, renderer_classes from rest_framework.response import Response from core_images.consts import DEFAULT_RESOLUTION, DEFAULT_STOREFRONT from core_images.image_types import is_placeholder from core_images.services.apple_music.service import get_apple_music_service from core_images.services.internal_data.service import ( get_internal_data_service, ) from core_images.services.scuba.service import get_scuba_service from core_images.services.spotify.service import get_spotify_service from core_images.tasks import invalidate_cloudfront_by_ids_task from core_images.utils import fix_url from .headers import get_image_type_headers, get_cache_headers from .image_url_redirect_renderer import ImageUrlRedirectRenderer logger = logging.getLogger(__name__) @api_view(["GET"]) def health(request): return Response(status=status.HTTP_200_OK) @api_view(["GET"]) def login(request): next_url = "{scheme}://{host}{path}".format( scheme=request.scheme, host=request._get_raw_host(), path=request.GET.get("next"), ) redirect_url = f"{settings.ATLAS_LOGIN_URL}?next={next_url}" return redirect(redirect_url) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def album_by_gras_product_id(request, gras_product_id): """ Fetch current cover image by its GRAS product id from SCUBA. If the fallback ID is provided, then the fallback image would be requested and provided if exists. """ fallback_spotify_id = request.GET.get("fallback_spotify_id") resolution = request.GET.get("resolution") spotify_service = get_spotify_service() scuba_service = get_scuba_service() eurl = scuba_service.product_image( gras_product_id=gras_product_id, resolution=resolution or DEFAULT_RESOLUTION, with_placeholders="with_placeholders" in request.GET, ) if eurl.is_right: return Response( status=status.HTTP_307_TEMPORARY_REDIRECT, headers={ "Location": eurl.value, **get_image_type_headers(eurl.value), **get_cache_headers(eurl.is_cached), }, ) elif fallback_spotify_id: fallback_eurl = spotify_service.album_image_url( album_id=fallback_spotify_id, resolution=resolution or DEFAULT_RESOLUTION, ) if fallback_eurl.is_right: return Response( status=status.HTTP_307_TEMPORARY_REDIRECT, headers={ "Location": fallback_eurl.value, **get_image_type_headers(fallback_eurl.value), **get_cache_headers(eurl.is_cached), }, ) resp = HttpResponse( eurl.value, content_type="text/plain", status=status.HTTP_404_NOT_FOUND ) for k, v in get_cache_headers(eurl.is_cached).items(): resp[k] = v return resp @api_view(["GET"]) def album_by_gras_product_ids(request, gras_product_ids): """Fetch current cover images by GRAS product ids from SCUBA.""" scuba_service = get_scuba_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurls = scuba_service.product_images( gras_product_ids=gras_product_ids, resolution=resolution, with_placeholders="with_placeholders" in request.GET, ) if eurls.is_right: return Response( eurls.value, headers=get_cache_headers(eurls.is_cached), ) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurls.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def album_by_spotify_id(request, spotify_id): """ Fetch the current cover image for an album in Spotify by a Spotify album ID. """ spotify_service = get_spotify_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurl = spotify_service.album_image_url( album_id=spotify_id, resolution=resolution, ) if eurl.is_right: return Response( status=status.HTTP_307_TEMPORARY_REDIRECT, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def album_by_spotify_track_id(request, spotify_track_id): """ Fetch the current cover image for an album in Spotify by a Spotify track ID. """ spotify_service = get_spotify_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurl = spotify_service.track_image_url( track_id=spotify_track_id, resolution=resolution, ) if eurl.is_right: return Response( status=status.HTTP_307_TEMPORARY_REDIRECT, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def artist_by_gras_participant_id(request, gras_participant_id): """ Fetch artist image by its GRAS id from SCUBA. """ fallback_spotify_id = request.GET.get("fallback_spotify_id") resolution = request.GET.get("resolution") spotify_service = get_spotify_service() scuba_service = get_scuba_service() internal_data_service = get_internal_data_service() eurl = scuba_service.artist_image( gras_artist_id=gras_participant_id, resolution=resolution or DEFAULT_RESOLUTION, with_placeholders="with_placeholders" in request.GET, ) if eurl.is_right and not is_placeholder(eurl.value): if internal_data_service.safe_delete_fallback( gras_participant_id, resolution ).is_right: invalidate_cloudfront_by_ids_task.delay( [gras_participant_id, gras_participant_id.replace("GRAS_", "")] ) return Response( status=status.HTTP_302_FOUND, headers={ "Location": eurl.value, **get_image_type_headers(eurl.value), **get_cache_headers(eurl.is_cached), }, ) elif ( fallback_eurl := internal_data_service.get_fallback_url( gras_participant_id ) ) and fallback_eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": fallback_eurl.value, **get_image_type_headers(fallback_eurl.value), **get_cache_headers(fallback_eurl.is_cached), }, ) elif fallback_spotify_id: fallback_eurl = spotify_service.artist_image_url( artist_id=fallback_spotify_id, resolution=resolution or DEFAULT_RESOLUTION, ) if fallback_eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": fallback_eurl.value, **get_image_type_headers(eurl.value), **get_cache_headers(eurl.is_cached), }, ) elif eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": eurl.value, **get_image_type_headers(eurl.value), **get_cache_headers(eurl.is_cached), }, ) return Response(status=status.HTTP_404_NOT_FOUND, headers={}) @api_view(["GET"]) def artist_by_gras_participant_ids(request, gras_participant_ids): """Fetch artists images by GRAS id from SCUBA.""" scuba_service = get_scuba_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurls = scuba_service.artist_images( gras_artist_ids=gras_participant_ids, resolution=resolution, with_placeholders="with_placeholders" in request.GET, ) if eurls.is_right: return Response( eurls.value, headers=get_cache_headers(eurls.is_cached), ) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurls.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def artist_by_spotify_id(request, spotify_id): """ Fetch a photo for an artist identified by Spotify artist ID. """ spotify_service = get_spotify_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurl = spotify_service.artist_image_url(spotify_id, resolution) if eurl.is_right: return Response( status=status.HTTP_307_TEMPORARY_REDIRECT, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def playlist_by_spotify_id(request, playlist_id): """ Fetch the current cover image for a Spotify playlist by its Spotify playlist ID. Spotify’s API allows for the possibility of multiple images representing a playlist. If this is the case, this endpoint arbitrarily chooses the first image returned. """ spotify_service = get_spotify_service() resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) eurl = spotify_service.playlist_image_url(playlist_id, resolution) if eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": fix_url(eurl.value), **get_cache_headers(eurl.is_cached, eurl.no_edge_cache), }, ) else: return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def playlist_by_apple_music_id(request, playlist_id): """ Fetch the current cover image for an Apple Music playlist by its Apple Music playlist ID. Apple Music playlist IDs typically begin with the literal string "pl." and this endpoint is not expected to return a valid result if the client strips that part of the ID out. """ resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) storefront = request.GET.get("storefront", DEFAULT_STOREFRONT) service = get_apple_music_service() eurl = service.playlist_artwork_url(playlist_id, resolution, storefront) if eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: logger.warning(eurl.value) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def album_by_apple_music_id(request, album_id): resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) storefront = request.GET.get("storefront", DEFAULT_STOREFRONT) service = get_apple_music_service() eurl = service.album_artwork_url(album_id, resolution, storefront) if eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: logger.warning(eurl.value) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def album_by_apple_track_id(request, track_id): resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) storefront = request.GET.get("storefront", DEFAULT_STOREFRONT) service = get_apple_music_service() eurl = service.track_artwork_url(track_id, resolution, storefront) if eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": eurl.value, **get_cache_headers(eurl.is_cached), }, ) else: logger.warning(eurl.value) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) @api_view(["GET"]) @renderer_classes([ImageUrlRedirectRenderer]) def label_by_label_id(request, label_id): resolution = request.GET.get("resolution", DEFAULT_RESOLUTION) service = get_internal_data_service() eurl = service.label_image_url(label_id, resolution) if eurl.is_right: return Response( status=status.HTTP_302_FOUND, headers={ "Location": fix_url(eurl.value), **get_cache_headers(eurl.is_cached), }, ) else: logger.warning(eurl.value) return Response( status=status.HTTP_404_NOT_FOUND, headers=get_cache_headers(eurl.is_cached), ) def docs(request): return render(request, "swagger_ui.html", {"schema_url": "schema"}) def schema(request): with open(settings.SCHEMA_PATH, "r") as f: return HttpResponse(f.read(), content_type="application/x-yaml")