Agregada integracion a cache de recordings

Fue un leseo la parte de recordings_of_release, pero ya esta esa parte

Me faltan un par de recordings no mas :3
This commit is contained in:
Daniel Cortes
2020-06-10 04:06:04 -04:00
parent 65c77c679f
commit 2a639f557f
3 changed files with 97 additions and 33 deletions

View File

@@ -62,6 +62,37 @@ def load_release_group_cover_art(release_group):
_log.info('Cover art de release group %s almacenado en cache', mbid) _log.info('Cover art de release group %s almacenado en cache', mbid)
@django_rq.job
def load_entities_of_recording(recording):
"""Carga en cache una recording y sus releases
Este difiere del resto e intenta obtener su padre, release, porque cargar recording como tal
no da tanto valor como hacer lo contrario, se aprovecha mejor las requests usadas
"""
mbid = recording
if isinstance(recording, dict):
mbid = recording.get('id')
with get_redis_connection() as redis:
if f'recording:{mbid}' not in redis:
# La única forma de agregar en cache una recording es a través de su release
# por lo que si ya esta guardada, su release lo estará
return
offset = 0
while True:
releases = mb.browse_releases({'recording': mbid},
includes=['recordings', 'artists'],
limit=100, offset=offset)
for release in releases:
load_entities_of_release.delay(release.get('id'))
offset += 100
if offset > releases.get('release-count'):
break
@django_rq.job @django_rq.job
def load_entities_of_release(release): def load_entities_of_release(release):
"""Carga en cache una release y sus entidades relacionadas""" """Carga en cache una release y sus entidades relacionadas"""
@@ -94,6 +125,7 @@ def load_entities_of_release(release):
# o menos me lo voy a saltar, lo único que interesa de la track es su orden dentro de su # o menos me lo voy a saltar, lo único que interesa de la track es su orden dentro de su
# media # media
medias = release.get('media', []) medias = release.get('media', [])
redis.set(f'release:{mbid}:media:count', len(medias))
for raw_media in medias: for raw_media in medias:
media = { media = {
'format': raw_media.get('format'), 'format': raw_media.get('format'),
@@ -102,11 +134,12 @@ def load_entities_of_release(release):
} }
redis.zadd(f'release:{mbid}:media', {json.dumps(media): media['position']}) redis.zadd(f'release:{mbid}:media', {json.dumps(media): media['position']})
for track in raw_media.get('tracks', []): for track in raw_media.get('tracks', []):
recording_key = f'release:{mbid}:{media.get("position")}:recordings' recording_key = f'release:{mbid}:media:{media.get("position")}:recordings'
recording = track.get('recording') recording = track.get('recording')
redis.zadd(recording_key, {recording.get('id'): track.get("position")}) recording_id = recording.get('id')
redis.set(f'recording:{mbid}', json.dumps(recording)) redis.zadd(recording_key, {recording_id: track.get("position")})
redis.set(f'recording:{mbid}:release', mbid) redis.set(f'recording:{recording_id}', json.dumps(recording))
redis.set(f'recording:{recording_id}:release', mbid)
@django_rq.job @django_rq.job

View File

@@ -120,6 +120,18 @@ def map_release(mb_release, cover_art=None):
} }
def map_media(mb_media):
"""Transforma una instancia de media dentro de una release a una util para mis propósitos"""
media = {
'format': mb_media.get('format'),
'position': mb_media.get('position'),
'track_count': mb_media.get('track_count'),
'recordings': [track.get('recording') for track in mb_media.get('tracks')]
}
return media
def map_recording(mb_recording): def map_recording(mb_recording):
"""Mapea el modelo de recording entregado por musicbrainz a uno propio""" """Mapea el modelo de recording entregado por musicbrainz a uno propio"""
return { return {
@@ -341,32 +353,58 @@ def get_artist_of_release(mbid, limit, page):
def get_recording(mbid): def get_recording(mbid):
"""Obtiene una grabación incluyendo a su artista""" """Obtiene una grabación"""
mb_recording = mb.get_recording_by_mbid(mbid)
with get_redis_connection() as redis:
mb_recording = redis.get(f'recording:{mbid}')
if mb_recording is None: if mb_recording is None:
mb_recording = mb.get_recording_by_mbid(mbid) mb_recording = mb.get_recording_by_mbid(mbid)
else: else:
mb_recording = json.loads(mb_recording) mb_recording = json.loads(mb_recording)
if 'error' in mb_recording: if 'error' in mb_recording:
return mb_recording return mb_recording
recording = map_recording(mb_recording) jobs.load_entities_of_recording.delay(mbid)
return recording return map_recording(mb_recording)
def get_recordings_of_release(mbid, limit, page): def get_recordings_of_release(mbid):
"""Obtiene las grabaciones de una release incluyendo los creditos a su artista""" """Obtiene las grabaciones de una release
mb_recordings = mb.browse_recordings(params={'release': mbid}, includes=['artist-credits'],
limit=limit, offset=limit * (page - 1))
if 'error' in mb_recordings: Realmente no existen grabaciones para este caso de uso, si no, media, el cual representa
return mb_recordings los medios físicos en los que esta una grabación, asi que se entrega una lista de medias con sus
grabaciones acopladas, todo ordenado y con indexes de orden
"""
return { medias = []
'paginate': paginate(mb_recordings.get('recording_count', 0), limit, page),
'recordings': [map_recording(recording) for recording in mb_recordings['recordings']] with get_redis_connection() as redis:
} medias_key = f'release:{mbid}:media'
count = redis.get(f'{medias_key}:count')
if count and redis.zcard(medias_key) == int(count):
medias = [json.loads(media) for media in redis.zrange(medias_key, 0, -1)]
for media in medias:
recordings_key = f'{medias_key}:{media.get("position")}:recordings'
recordings_id = redis.zrange(recordings_key, 0, -1)
media['recordings'] = []
for recording_id in recordings_id:
media['recordings'].append(json.loads(redis.get(f'recording:{recording_id}')))
if len(medias) == 0:
# Si es que no habían medias cargadas en cache, puede ser que la release nunca se alla
# cargado.
jobs.load_entities_of_release.delay(mbid)
mb_release = mb.get_release_by_mbid(mbid, ['recordings'])
if 'error' in mb_release:
return mb_release
medias = [map_media(media) for media in mb_release.get('media', [])]
return {'medias': medias}
def get_release_of_recording(mbid, limit, page): def get_release_of_recording(mbid, limit, page):

View File

@@ -152,15 +152,8 @@ def search_recording(request):
@api_view(['GET']) @api_view(['GET'])
def get_recordings_of_release(request, mbid): def get_recordings_of_release(request, mbid):
""" Obtiene las recordings de una release dada su mbid """ Obtiene las recordings de una release dada su mbid"""
return Response(medium.get_recordings_of_release(mbid))
Como los datos son paginables la query puede contener per_page y page para definir cuantos
elementos mostrar por pagina y que pagina mostrar.
"""
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'])