From a0101bf1aebc6ec5c84a5e2b63515453b12758e2 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Sun, 26 Feb 2023 23:26:51 -0500 Subject: [PATCH] Add first pass at AudioDB fetching --- ...graphy_artist_theaudiodb_genre_and_more.py | 28 ++++++++++++++++ .../music/migrations/0011_artist_thumbnail.py | 20 +++++++++++ vrobbler/apps/music/models.py | 25 +++++++++++++- vrobbler/apps/music/utils.py | 2 +- vrobbler/apps/scrobbles/theaudiodb.py | 33 +++++++++++++++++++ vrobbler/settings.py | 6 +--- 6 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 vrobbler/apps/music/migrations/0010_artist_biography_artist_theaudiodb_genre_and_more.py create mode 100644 vrobbler/apps/music/migrations/0011_artist_thumbnail.py create mode 100644 vrobbler/apps/scrobbles/theaudiodb.py diff --git a/vrobbler/apps/music/migrations/0010_artist_biography_artist_theaudiodb_genre_and_more.py b/vrobbler/apps/music/migrations/0010_artist_biography_artist_theaudiodb_genre_and_more.py new file mode 100644 index 0000000..e2079bd --- /dev/null +++ b/vrobbler/apps/music/migrations/0010_artist_biography_artist_theaudiodb_genre_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.5 on 2023-02-27 03:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('music', '0009_alter_track_musicbrainz_id_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='artist', + name='biography', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='artist', + name='theaudiodb_genre', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='artist', + name='theaudiodb_mood', + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/vrobbler/apps/music/migrations/0011_artist_thumbnail.py b/vrobbler/apps/music/migrations/0011_artist_thumbnail.py new file mode 100644 index 0000000..ad2ec39 --- /dev/null +++ b/vrobbler/apps/music/migrations/0011_artist_thumbnail.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.5 on 2023-02-27 04:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('music', '0010_artist_biography_artist_theaudiodb_genre_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='artist', + name='thumbnail', + field=models.ImageField( + blank=True, null=True, upload_to='artist/' + ), + ), + ] diff --git a/vrobbler/apps/music/models.py b/vrobbler/apps/music/models.py index 44c7173..0e6b64b 100644 --- a/vrobbler/apps/music/models.py +++ b/vrobbler/apps/music/models.py @@ -1,15 +1,18 @@ import logging +from tempfile import NamedTemporaryFile from typing import Dict, Optional +from urllib.request import urlopen from uuid import uuid4 import musicbrainzngs from django.conf import settings -from django.core.files.base import ContentFile +from django.core.files.base import File from django.db import models from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django_extensions.db.models import TimeStampedModel from scrobbles.mixins import ScrobblableMixin +from scrobbles.theaudiodb import lookup_artist_from_tadb logger = logging.getLogger(__name__) BNULL = {"blank": True, "null": True} @@ -18,7 +21,11 @@ BNULL = {"blank": True, "null": True} class Artist(TimeStampedModel): uuid = models.UUIDField(default=uuid4, editable=False, **BNULL) name = models.CharField(max_length=255) + biography = models.TextField(**BNULL) + theaudiodb_genre = models.CharField(max_length=255, **BNULL) + theaudiodb_mood = models.CharField(max_length=255, **BNULL) musicbrainz_id = models.CharField(max_length=255, **BNULL) + thumbnail = models.ImageField(upload_to="artist/", **BNULL) class Meta: unique_together = [['name', 'musicbrainz_id']] @@ -53,6 +60,22 @@ class Artist(TimeStampedModel): return ChartRecord.objects.filter(track__artist=self).order_by('-year') + def fix_metadata(self): + tadb_info = lookup_artist_from_tadb(self.name) + if not tadb_info: + logger.warn(f"No response from TADB for artist {self.name}") + return + + self.biography = tadb_info['biography'] + self.theaudiodb_genre = tadb_info['genre'] + self.theaudiodb_mood = tadb_info['mood'] + + img_temp = NamedTemporaryFile(delete=True) + img_temp.write(urlopen(tadb_info['thumb_url']).read()) + img_temp.flush() + img_filename = f"{self.name}_{self.uuid}.jpg" + self.thumbnail.save(img_filename, File(img_temp)) + class Album(TimeStampedModel): uuid = models.UUIDField(default=uuid4, editable=False, **BNULL) diff --git a/vrobbler/apps/music/utils.py b/vrobbler/apps/music/utils.py index 26291f9..cb065eb 100644 --- a/vrobbler/apps/music/utils.py +++ b/vrobbler/apps/music/utils.py @@ -36,7 +36,7 @@ def get_or_create_artist(name: str, mbid: str = None) -> Artist: logger.debug( f"Created artist {artist.name} ({artist.musicbrainz_id}) " ) - # TODO Enrich artist with MB data + artist.fix_metadata() return artist diff --git a/vrobbler/apps/scrobbles/theaudiodb.py b/vrobbler/apps/scrobbles/theaudiodb.py new file mode 100644 index 0000000..533673d --- /dev/null +++ b/vrobbler/apps/scrobbles/theaudiodb.py @@ -0,0 +1,33 @@ +import json +import logging + +import requests +from django.conf import settings + +THEAUDIODB_API_KEY = getattr(settings, "THEAUDIODB_API_KEY") +SEARCH_URL = f"https://www.theaudiodb.com/api/v1/json/{THEAUDIODB_API_KEY}/search.php?s=" + +logger = logging.getLogger(__name__) + + +def lookup_artist_from_tadb(name: str) -> dict: + artist_info = {} + response = requests.get(SEARCH_URL + name) + + if response.status_code != 200: + logger.warn(f"Bad response from TADB: {response.status_code}") + return {} + + if not response.content: + logger.warn(f"Bad content from TADB: {response.content}") + return {} + + results = json.loads(response.content) + artist = results['artists'][0] + + artist_info['biography'] = artist['strBiographyEN'] + artist_info['genre'] = artist['strGenre'] + artist_info['mood'] = artist['strMood'] + artist_info['thumb_url'] = artist['strArtistThumb'] + + return artist_info diff --git a/vrobbler/settings.py b/vrobbler/settings.py index 8cacd55..0afbba5 100644 --- a/vrobbler/settings.py +++ b/vrobbler/settings.py @@ -51,13 +51,9 @@ DELETE_STALE_SCROBBLES = os.getenv("VROBBLER_DELETE_STALE_SCROBBLES", True) # Used to dump data coming from srobbling sources, helpful for building new inputs DUMP_REQUEST_DATA = os.getenv("VROBBLER_DUMP_REQUEST_DATA", False) - THESPORTSDB_API_KEY = os.getenv("VROBBLER_THESPORTSDB_API_KEY", "2") -THESPORTSDB_BASE_URL = os.getenv( - "VROBBLER_THESPORTSDB_BASE_URL", "https://www.thesportsdb.com/api/v1/json/" -) +THEAUDIODB_API_KEY = os.getenv("VROBBLER_THEAUDIODB_API_KEY", "2") TMDB_API_KEY = os.getenv("VROBBLER_TMDB_API_KEY", "") - LASTFM_API_KEY = os.getenv("VROBBLER_LASTFM_API_KEY") LASTFM_SECRET_KEY = os.getenv("VROBBLER_LASTFM_SECRET_KEY")