Cambiada la estructura de la api

No era muy util como estaba antes, por lo que siplifique los modelos y
proceso levemente lo que entrega musicbrainz
This commit is contained in:
Daniel Cortes
2020-05-22 06:28:39 -04:00
parent 3568abfbc7
commit a37d51b120
4 changed files with 293 additions and 39 deletions

217
fetcher/medium.py Normal file
View File

@@ -0,0 +1,217 @@
import math
import fetcher.musicbrainz as mb
from utils import pretty_print_json
def get_artist(mbid):
mb_artist = mb.get_artist_by_mbid(mbid)
if 'error' in mb_artist:
return mb_artist
artist = {
'id': mb_artist.get('id'),
'name': mb_artist.get('name'),
'sort_name': mb_artist.get('sort_name'),
'disambiguation': mb_artist.get('disambiguation'),
'type': mb_artist.get('type'),
'country': mb_artist.get('country')
}
return artist
def get_disc(mbid):
mb_disc = mb.get_release_group_by_mbid(mbid)
if 'error' in mb_disc:
return mb_disc
disc = {
'id': mb_disc.get('id'),
'title': mb_disc.get('title'),
'disambiguation': mb_disc.get('disambiguation'),
'first_release_date': mb_disc.get('first_release_date'),
'primary_type': mb_disc.get('primary_type'),
'cover_art': get_cover_art_disc(mb_disc.get('id'))
}
if len(mb_disc.get('secondary_types', [])) > 0:
disc['secondary_type'] = mb_disc['secondary_types'][0]
return disc
def get_discs_of_artist(mbid, limit, page):
mb_discs = mb.browse_release_groups(params={'artist': mbid}, limit=limit, offset=limit * (page - 1))
if 'error' in mb_discs:
return mb_discs
response = {
'total': mb_discs.get('release_group_count', 0),
'current_page': page,
'last_page': math.ceil(mb_discs.get('release_group_count', 0) / limit),
'per_page': limit,
'discs': [],
}
for mb_disc in mb_discs['release_groups']:
disc = {
'id': mb_disc.get('id'),
'title': mb_disc.get('title'),
'disambiguation': mb_disc.get('disambiguation'),
'first_release_date': mb_disc.get('first_release_date'),
'primary_type': mb_disc.get('primary_type'),
'cover_art': get_cover_art_disc(mb_disc.get('id'))
}
if len(mb_disc.get('secondary_types', [])) > 0:
disc['secondary_type'] = mb_disc['secondary_types'][0]
response['discs'].append(disc)
return response
def get_release(mbid):
mb_release = mb.get_release_by_mbid(mbid)
if 'error' in mb_release:
return mb_release
release = {
'id': mb_release.get('id'),
'title': mb_release.get('title'),
'disambiguation': mb_release.get('disambiguation'),
'status': mb_release.get('status'),
'country': mb_release.get('country'),
'date': mb_release.get('date'),
'cover_art': get_cover_art_release(mb_release.get('id'))
}
return release
def get_releases_of_disc(mbid, limit, page):
mb_releases = mb.browse_releases(params={'release-group': mbid}, limit=limit, offset=limit * (page - 1))
response = {
'total': mb_releases.get('release_count', 0),
'current_page': page,
'last_page': math.ceil(mb_releases.get('release_count', 0) / limit),
'per_page': limit,
'releases': [],
}
for mb_release in mb_releases['releases']:
release = {
'id': mb_release.get('id'),
'title': mb_release.get('title'),
'disambiguation': mb_release.get('disambiguation'),
'status': mb_release.get('status'),
'country': mb_release.get('country'),
'date': mb_release.get('date'),
'cover_art': get_cover_art_release(mb_release.get('id'))
}
response['releases'].append(release)
return response
def get_recording(mbid):
mb_recording = mb.get_recording_by_mbid(mbid)
if 'error' in mb_recording:
return mb_recording
recording = {
'id': mb_recording.get('id'),
'title': mb_recording.get('title'),
'disambiguation': mb_recording.get('disambiguation'),
'video': mb_recording.get('video'),
'length': mb_recording.get('length')
}
return recording
def get_recordings_of_release(mbid, limit, page):
mb_recordings = mb.browse_recordings(params={'release': mbid}, limit=limit, offset=limit * (page - 1))
if 'error' in mb_recordings:
return mb_recordings
response = {
'total': mb_recordings.get('release_count', 0),
'current_page': page,
'last_page': math.ceil(mb_recordings.get('release_count', 0) / limit),
'per_page': limit,
'recordings': [],
}
for mb_recording in mb_recordings['recordings']:
recording = {
'id': mb_recording.get('id'),
'title': mb_recording.get('title'),
'disambiguation': mb_recording.get('disambiguation'),
'video': mb_recording.get('video'),
'length': mb_recording.get('length')
}
response['recordings'].append(recording)
return response
def get_cover_art_disc(mbid):
covers = mb.get_release_group_cover_art(mbid)
if 'error' in covers:
return covers
def build(cover):
return {
'image': cover.get('image'),
'1200': cover.get('thumbnails', {}).get('1200'),
'500': cover.get('thumbnails', {}).get('500'),
'250': cover.get('thumbnails', {}).get('250'),
'large': cover.get('thumbnails', {}).get('large'),
'small': cover.get('thumbnails', {}).get('small'),
}
if len(covers.get('images', [])) == 1:
return build(covers.get('images')[0])
only_aproved_front = [x for x in covers.get('images') if x.get('approved', False) and x.get('front', False) and not x.get('back', False)]
only_aproved = [x for x in covers.get('images') if x.get('approved', False)]
if len(only_aproved_front) > 0:
return build(only_aproved_front[0])
elif len(only_aproved) > 0:
return build(only_aproved[0])
else:
return build(covers.get('images')[0])
def get_cover_art_release(mbid):
covers = mb.get_release_cover_art(mbid)
if 'error' in covers:
return covers
def build(cover):
return {
'image': cover.get('image'),
'1200': cover.get('thumbnails', {}).get('1200'),
'500': cover.get('thumbnails', {}).get('500'),
'250': cover.get('thumbnails', {}).get('250'),
'large': cover.get('thumbnails', {}).get('large'),
'small': cover.get('thumbnails', {}).get('small'),
}
if len(covers.get('images', [])) == 1:
return build(covers.get('images')[0])
only_aproved_front = [x for x in covers.get('images', []) if x.get('approved', False) and x.get('front', False) and not x.get('back', False)]
only_aproved = [x for x in covers.get('images', []) if x.get('approved', False)]
if len(only_aproved_front) > 0:
return build(only_aproved_front[0])
elif len(only_aproved) > 0:
return build(only_aproved[0])
else:
return build(covers.get('images')[0])

View File

@@ -3,7 +3,7 @@ import requests
from ratelimit import limits, sleep_and_retry from ratelimit import limits, sleep_and_retry
from urllib.parse import quote, urlencode from urllib.parse import quote, urlencode
from utils import replace_key, sanitize_keys from utils import replace_key, sanitize_keys, pretty_print_json
from utils.cache import Cache as cache from utils.cache import Cache as cache
_headers = {'accept': 'application/json', 'user-agent': 'MusicList/1.0 (danielcortes.xyz)'} _headers = {'accept': 'application/json', 'user-agent': 'MusicList/1.0 (danielcortes.xyz)'}
@@ -16,7 +16,7 @@ _log.addHandler(logging.NullHandler())
@sleep_and_retry @sleep_and_retry
@limits(calls=1, period=1) @limits(calls=1, period=1)
def _do_request(url, allow_redirects=True): def _do_request(url, host=_mb_host):
"""Does a request to a path and returns the dictionary representing the json response """Does a request to a path and returns the dictionary representing the json response
If the response is 200 it will return the full dictionary of the json that the response If the response is 200 it will return the full dictionary of the json that the response
@@ -42,20 +42,25 @@ def _do_request(url, allow_redirects=True):
raise ValueError('URL cant be empty') raise ValueError('URL cant be empty')
_log.info(f'Doing request to "{url}" with headers {_headers}') _log.info(f'Doing request to "{url}" with headers {_headers}')
r = requests.get(url, headers=_headers, allow_redirects=allow_redirects) r = requests.get(url, headers=_headers)
_log.info(f'Request returned with status code {r.status_code}') _log.info(f'Request returned with status code {r.status_code}')
if r.status_code == 200: if r.status_code == 200:
response = r.json(object_hook=sanitize_keys) response = r.json(object_hook=sanitize_keys)
elif r.status_code == 307: elif r.status_code == 500:
response = {'link': r.headers['location']} response = {'status': r.status_code, 'error': f'Error del servidor'}
elif host == _ca_host:
if r.status_code == 400:
response = {'status': r.status_code, 'error': f'El mbid es invalido'}
elif r.status_code == 404: elif r.status_code == 404:
response = {'status': r.status_code, 'error': f'No encontrado'} response = {'status': r.status_code, 'error': f'No encontrado'}
elif r.status_code == 400: elif r.status_code == 405:
response = {'status': r.status_code, 'error': f'Query erronea'} response = {'status': r.status_code, 'error': f'Metodo erroneo'}
elif r.status_code == 503:
response = {'status': r.status_code, 'error': f'Rate limit exedido'}
else: else:
response = {'status': r.status_code, 'error': f'Error desconocido de musicbrainz'} response = {'status': r.status_code, 'error': r.json()['error']}
return response return response
@@ -132,24 +137,20 @@ def _browse(entity_type, params, includes=None, limit=25, offset=0):
return _do_request(f'{_mb_host}/{entity_type}?{_query}') return _do_request(f'{_mb_host}/{entity_type}?{_query}')
def _ca(entity_type, mbid, size=None): def _ca(entity_type, mbid):
"""Gets the url of the cover art of a release or release-group """Gets the url of the cover art of a release or release-group
:param str entity_type: Type of the entity, could be release or release-group :param str entity_type: Type of the entity, could be release or release-group
:param str mbid: MBID of the entity of whom is the cover art :param str mbid: MBID of the entity of whom is the cover art
:param int size: Optional size of the cover art, could be 250, 500 or 1200
any other value will be ignored
:return: The url of the cover art :return: The url of the cover art
""" """
_log.info(f'Obtaining the cover art of the entity with type {entity_type} and mbid {mbid} with size {size}') _log.info(f'Obtaining the cover art of the entity with type {entity_type} and mbid {mbid}')
_url = f'{_ca_host}/{entity_type}/{mbid}/front' _url = f'{_ca_host}/{entity_type}/{mbid}'
if size in (250, 500, 1200):
_url += f'-{size}'
return _do_request(_url, allow_redirects=False) return _do_request(_url, host=_ca_host)
@cache @cache
@@ -321,24 +322,22 @@ def browse_release_groups(params, includes=None, limit=25, offset=0):
@cache @cache
def get_release_cover_art(mbid, size=None): def get_release_cover_art(mbid):
"""Gets the url of the cover art of a release """Gets the url of the cover art of a release
:param str mbid: MBID of the release of whom is the cover art :param str mbid: MBID of the release of whom is the cover art
:param int size: Optional size of the cover art, could be 250, 500 or 1200
:return: dictionary with the response :return: dictionary with the response
""" """
return _ca('release', mbid, size) return _ca('release', mbid)
@cache @cache
def get_release_group_cover_art(mbid, size=None): def get_release_group_cover_art(mbid):
"""Gets the url of the cover art of a release group """Gets the url of the cover art of a release group
:param str mbid: MBID of the release group of whom is the cover art :param str mbid: MBID of the release group of whom is the cover art
:param int size: Optional size of the cover art, could be 250, 500 or 1200
:return: dictionary with the response :return: dictionary with the response
""" """
return _ca('release-group', mbid, size) return _ca('release-group', mbid)

View File

@@ -2,23 +2,15 @@ from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('get/artist/<mbid>/', views.get_artist_by_mbid), path('get/artist/<mbid>/', views.get_artist),
path('get/release-group/<mbid>/', views.get_release_group_by_mbid), path('get/artist/<mbid>/discs/', views.get_discs_of_artist),
path('get/release/<mbid>/', views.get_release_by_mbid),
path('get/recording/<mbid>/', views.get_recording_by_mbid),
path('search/artist/', views.search_artist), path('get/disc/<mbid>/', views.get_disc),
path('search/release-group/', views.search_release_group), path('get/disc/<mbid>/releases/', views.get_releases_of_disc),
path('search/release/', views.search_release),
path('search/recording/', views.search_recording),
path('browse/artist/', views.browse_artists), path('get/release/<mbid>/', views.get_release),
path('browse/release-group/', views.browse_release_groups), path('get/release/<mbid>/recordings/', views.get_recordings_of_release),
path('browse/release/', views.browse_releases),
path('browse/recording/', views.browse_recordings),
path('coverart/release-group/<mbid>/<int:size>/', views.get_release_group_cover_art),
path('coverart/release-group/<mbid>/', views.get_release_group_cover_art), path('coverart/release-group/<mbid>/', views.get_release_group_cover_art),
path('coverart/release/<mbid>/<int:size>', views.get_release_cover_art),
path('coverart/release/<mbid>/', views.get_release_group_cover_art), path('coverart/release/<mbid>/', views.get_release_group_cover_art),
] ]

View File

@@ -1,7 +1,8 @@
import logging
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.response import Response from rest_framework.response import Response
from . import musicbrainz as mb from . import musicbrainz as mb, medium
def _get_by_mbid(request, entity_type, mbid): def _get_by_mbid(request, entity_type, mbid):
@@ -70,6 +71,51 @@ def _browse(request, entity_type):
return Response(response) return Response(response)
@api_view(['GET'])
def get_artist(request, mbid):
return Response(medium.get_artist(mbid))
@api_view(['GET'])
def get_disc(request, mbid):
return Response(medium.get_disc(mbid))
@api_view(['GET'])
def get_discs_of_artist(request, mbid):
limit = int(request.GET.get('per_page', 10))
page = int(request.GET.get('page', 1))
return Response(medium.get_discs_of_artist(mbid, limit, page))
@api_view(['GET'])
def get_release(request, mbid):
return Response(medium.get_release(mbid))
@api_view(['GET'])
def get_releases_of_disc(request, mbid):
limit = int(request.GET.get('per_page', 10))
page = int(request.GET.get('page', 1))
return Response(medium.get_releases_of_disc(mbid, limit, page))
@api_view(['GET'])
def get_recording(request, mbid):
return Response(medium.get_recording(mbid))
@api_view(['GET'])
def get_recordings_of_release(request, mbid):
limit = int(request.GET.get('per_page', 100))
page = int(request.GET.get('page', 1))
return Response(medium.get_recordings_of_release(mbid, limit, page))
@api_view(['GET']) @api_view(['GET'])
def get_artist_by_mbid(request, mbid): return _get_by_mbid(request, 'artist', mbid) def get_artist_by_mbid(request, mbid): return _get_by_mbid(request, 'artist', mbid)