[music] Attempts to fix bad lookups from LastFM and Jellyfin

Broader issue was creating tracks without albums that were duplicates of
existing tracks because sometimes Jellyfin and LastFM do not have albums
sent with them.
This commit is contained in:
2025-04-06 22:28:32 -04:00
parent b2ee79b3ea
commit b0e9f13e11
8 changed files with 323 additions and 99 deletions

View File

@ -16,9 +16,8 @@ logger = logging.getLogger(__name__)
from music.models import Album, Artist, Track
def get_or_create_artist(name: str, mbid: str = None) -> Artist:
artist = None
def clean_artist_name(name: str) -> str:
"""Remove featured names from artist string."""
if "feat." in name.lower():
name = re.split("feat.", name, flags=re.IGNORECASE)[0].strip()
if "featuring" in name.lower():
@ -26,18 +25,44 @@ def get_or_create_artist(name: str, mbid: str = None) -> Artist:
if "&" in name.lower():
name = re.split("&", name, flags=re.IGNORECASE)[0].strip()
artist_dict = lookup_artist_from_mb(name)
mbid = mbid or artist_dict.get("id", None)
return name
if mbid:
# TODO These are depreacted, remove them eventually
def get_or_create_artist(name: str, mbid: str = "") -> Artist:
"""Get an Artist object from the database.
Check if an artist with this name or Musicbrainz ID already exists.
Otherwise, go lookup artist data from Musicbrainz and create one.
"""
artist = None
name = clean_artist_name(name)
# Check for name/mbid combo, just mbid and then just name
artist = Artist.objects.filter(name=name, mbid=mbid).first()
if not artist:
artist = Artist.objects.filter(musicbrainz_id=mbid).first()
if not artist:
artist = Artist.objects.filter(name=name).first()
# Does not exist, look it up from Musicbrainz
if not artist:
artist_dict = lookup_artist_from_mb(name)
mbid = mbid or artist_dict.get("id", "")
if mbid:
artist = Artist.objects.filter(musicbrainz_id=mbid).first()
if not artist:
artist = Artist.objects.create(name=name, musicbrainz_id=mbid)
# TODO maybe this should be spun off into an async task?
artist.fix_metadata()
return artist
# TODO These are depreacted, remove them eventually
def get_or_create_album(
name: str, artist: Artist, mbid: str = None
) -> Optional[Album]:
@ -90,6 +115,7 @@ def get_or_create_album(
return album
# TODO These are depreacted, remove them eventually
def get_or_create_track(post_data: dict, post_keys: dict) -> Track:
try:
track_run_time_seconds = int(
@ -107,16 +133,12 @@ def get_or_create_track(post_data: dict, post_keys: dict) -> Track:
track_title = post_data.get(post_keys.get("TRACK_TITLE"), "")
track_mb_id = post_data.get(post_keys.get("TRACK_MB_ID"), "")
artist = get_or_create_artist(
artist_name,
mbid=artist_mb_id,
)
artist = Artist.find_or_create(artist_name, artist_mb_id)
album = None
if album_mb_id:
album = get_or_create_album(
album_title,
artist=artist,
mbid=album_mb_id,
# We may get no album ID or title, in which case, skip
if album_mb_id or album_title:
album = Album.find_or_create(
album_title, str(artist.name), album_mb_id
)
track = None
@ -154,7 +176,7 @@ def get_or_create_track(post_data: dict, post_keys: dict) -> Track:
return track
def get_or_create_various_artists():
def get_or_create_various_artists() -> Artist:
artist = Artist.objects.filter(name="Various Artists").first()
if not artist:
artist = Artist.objects.create(**VARIOUS_ARTIST_DICT)