Add first pass at AudioDB fetching
This commit is contained in:
@ -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),
|
||||||
|
),
|
||||||
|
]
|
||||||
20
vrobbler/apps/music/migrations/0011_artist_thumbnail.py
Normal file
20
vrobbler/apps/music/migrations/0011_artist_thumbnail.py
Normal file
@ -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/'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -1,15 +1,18 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
from urllib.request import urlopen
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import musicbrainzngs
|
import musicbrainzngs
|
||||||
from django.conf import settings
|
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.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_extensions.db.models import TimeStampedModel
|
from django_extensions.db.models import TimeStampedModel
|
||||||
from scrobbles.mixins import ScrobblableMixin
|
from scrobbles.mixins import ScrobblableMixin
|
||||||
|
from scrobbles.theaudiodb import lookup_artist_from_tadb
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
BNULL = {"blank": True, "null": True}
|
BNULL = {"blank": True, "null": True}
|
||||||
@ -18,7 +21,11 @@ BNULL = {"blank": True, "null": True}
|
|||||||
class Artist(TimeStampedModel):
|
class Artist(TimeStampedModel):
|
||||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||||
name = models.CharField(max_length=255)
|
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)
|
musicbrainz_id = models.CharField(max_length=255, **BNULL)
|
||||||
|
thumbnail = models.ImageField(upload_to="artist/", **BNULL)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [['name', 'musicbrainz_id']]
|
unique_together = [['name', 'musicbrainz_id']]
|
||||||
@ -53,6 +60,22 @@ class Artist(TimeStampedModel):
|
|||||||
|
|
||||||
return ChartRecord.objects.filter(track__artist=self).order_by('-year')
|
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):
|
class Album(TimeStampedModel):
|
||||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||||
|
|||||||
@ -36,7 +36,7 @@ def get_or_create_artist(name: str, mbid: str = None) -> Artist:
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
f"Created artist {artist.name} ({artist.musicbrainz_id}) "
|
f"Created artist {artist.name} ({artist.musicbrainz_id}) "
|
||||||
)
|
)
|
||||||
# TODO Enrich artist with MB data
|
artist.fix_metadata()
|
||||||
|
|
||||||
return artist
|
return artist
|
||||||
|
|
||||||
|
|||||||
33
vrobbler/apps/scrobbles/theaudiodb.py
Normal file
33
vrobbler/apps/scrobbles/theaudiodb.py
Normal file
@ -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
|
||||||
@ -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
|
# Used to dump data coming from srobbling sources, helpful for building new inputs
|
||||||
DUMP_REQUEST_DATA = os.getenv("VROBBLER_DUMP_REQUEST_DATA", False)
|
DUMP_REQUEST_DATA = os.getenv("VROBBLER_DUMP_REQUEST_DATA", False)
|
||||||
|
|
||||||
|
|
||||||
THESPORTSDB_API_KEY = os.getenv("VROBBLER_THESPORTSDB_API_KEY", "2")
|
THESPORTSDB_API_KEY = os.getenv("VROBBLER_THESPORTSDB_API_KEY", "2")
|
||||||
THESPORTSDB_BASE_URL = os.getenv(
|
THEAUDIODB_API_KEY = os.getenv("VROBBLER_THEAUDIODB_API_KEY", "2")
|
||||||
"VROBBLER_THESPORTSDB_BASE_URL", "https://www.thesportsdb.com/api/v1/json/"
|
|
||||||
)
|
|
||||||
TMDB_API_KEY = os.getenv("VROBBLER_TMDB_API_KEY", "")
|
TMDB_API_KEY = os.getenv("VROBBLER_TMDB_API_KEY", "")
|
||||||
|
|
||||||
LASTFM_API_KEY = os.getenv("VROBBLER_LASTFM_API_KEY")
|
LASTFM_API_KEY = os.getenv("VROBBLER_LASTFM_API_KEY")
|
||||||
LASTFM_SECRET_KEY = os.getenv("VROBBLER_LASTFM_SECRET_KEY")
|
LASTFM_SECRET_KEY = os.getenv("VROBBLER_LASTFM_SECRET_KEY")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user