diff --git a/vrobbler/apps/music/admin.py b/vrobbler/apps/music/admin.py index d55cf1b..a3ebead 100644 --- a/vrobbler/apps/music/admin.py +++ b/vrobbler/apps/music/admin.py @@ -11,7 +11,7 @@ class AlbumAdmin(admin.ModelAdmin): list_display = ( "name", "year", - "primary_artist", + "album_artist", "theaudiodb_genre", "theaudiodb_mood", "musicbrainz_id", diff --git a/vrobbler/apps/music/constants.py b/vrobbler/apps/music/constants.py index 379ca06..3158902 100644 --- a/vrobbler/apps/music/constants.py +++ b/vrobbler/apps/music/constants.py @@ -1,3 +1,9 @@ +VARIOUS_ARTIST_DICT = { + "name": "Various Artists", + "theaudiodb_id": "113641", + "musicbrainz_id": "89ad4ac3-39f7-470e-963a-56509c546377", +} + JELLYFIN_POST_KEYS = { "ITEM_TYPE": "ItemType", "RUN_TIME": "RunTime", diff --git a/vrobbler/apps/music/migrations/0021_album_album_artist.py b/vrobbler/apps/music/migrations/0021_album_album_artist.py new file mode 100644 index 0000000..3dc0ff4 --- /dev/null +++ b/vrobbler/apps/music/migrations/0021_album_album_artist.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.5 on 2023-03-15 16:22 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("music", "0020_album_bandcamp_id_artist_bandcamp_id"), + ] + + operations = [ + migrations.AddField( + model_name="album", + name="album_artist", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="albums", + to="music.artist", + ), + ), + ] diff --git a/vrobbler/apps/music/migrations/0022_artist_theaudiodb_id.py b/vrobbler/apps/music/migrations/0022_artist_theaudiodb_id.py new file mode 100644 index 0000000..37a9a0b --- /dev/null +++ b/vrobbler/apps/music/migrations/0022_artist_theaudiodb_id.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.5 on 2023-03-15 16:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("music", "0021_album_album_artist"), + ] + + operations = [ + migrations.AddField( + model_name="artist", + name="theaudiodb_id", + field=models.CharField( + blank=True, max_length=255, null=True, unique=True + ), + ), + ] diff --git a/vrobbler/apps/music/models.py b/vrobbler/apps/music/models.py index 4d8f0db..018d77f 100644 --- a/vrobbler/apps/music/models.py +++ b/vrobbler/apps/music/models.py @@ -1,4 +1,3 @@ -import requests import logging from tempfile import NamedTemporaryFile from typing import Dict, Optional @@ -6,19 +5,17 @@ from urllib.request import urlopen from uuid import uuid4 import musicbrainzngs +import requests from django.conf import settings from django.core.files.base import ContentFile, 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 music.allmusic import get_allmusic_slug, scrape_data_from_allmusic +from music.bandcamp import get_bandcamp_slug +from music.theaudiodb import lookup_album_from_tadb, lookup_artist_from_tadb from scrobbles.mixins import ScrobblableMixin -from music.theaudiodb import lookup_artist_from_tadb, lookup_album_from_tadb -from vrobbler.apps.music.allmusic import ( - get_allmusic_slug, - scrape_data_from_allmusic, -) -from vrobbler.apps.music.bandcamp import get_bandcamp_slug logger = logging.getLogger(__name__) BNULL = {"blank": True, "null": True} @@ -28,6 +25,7 @@ class Artist(TimeStampedModel): uuid = models.UUIDField(default=uuid4, editable=False, **BNULL) name = models.CharField(max_length=255) biography = models.TextField(**BNULL) + theaudiodb_id = models.CharField(max_length=255, unique=True, **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) @@ -129,6 +127,9 @@ class Artist(TimeStampedModel): class Album(TimeStampedModel): uuid = models.UUIDField(default=uuid4, editable=False, **BNULL) name = models.CharField(max_length=255) + album_artist = models.ForeignKey( + Artist, related_name="albums", on_delete=models.DO_NOTHING, **BNULL + ) artists = models.ManyToManyField(Artist) year = models.IntegerField(**BNULL) musicbrainz_id = models.CharField(max_length=255, unique=True, **BNULL) @@ -175,9 +176,17 @@ class Album(TimeStampedModel): .order_by("-scrobble_count") ) - @property - def primary_artist(self): - return self.artists.first() + def fix_album_artist(self): + from music.utils import get_or_create_various_artists + + multiple_artists = self.artists.count() > 1 + if not self.album_artist: + if multiple_artists: + self.album_artist = get_or_create_various_artists() + else: + self.album_artist = self.artists.first() + + self.save(update_fields=["album_artist"]) def scrape_allmusic(self, force=False) -> None: if not self.allmusic_id or force: diff --git a/vrobbler/apps/music/utils.py b/vrobbler/apps/music/utils.py index 53ffc7e..c5d5211 100644 --- a/vrobbler/apps/music/utils.py +++ b/vrobbler/apps/music/utils.py @@ -7,6 +7,7 @@ from music.musicbrainz import ( lookup_artist_from_mb, lookup_track_from_mb, ) +from music.constants import VARIOUS_ARTIST_DICT logger = logging.getLogger(__name__) @@ -50,7 +51,7 @@ def get_or_create_album( logger.debug(f"Looking up album {name} and mbid: {mbid}") - album = Album.objects.filter(artist=artist, name=name).first() + album = Album.objects.filter(album_artist=artist, name=name).first() if not album and name: album = Album.objects.create(name=name, musicbrainz_id=mbid) @@ -102,3 +103,11 @@ def get_or_create_track( ) return track + + +def get_or_create_various_artists(): + artist = Artist.objects.filter(name="Various Artists").first() + if not artist: + artist = Artist.objects.create(**VARIOUS_ARTIST_DICT) + logger.info("Created Various Artists placeholder") + return artist