From cc8250426242b0f07a4923decd4cfb781caf60c5 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Thu, 16 Feb 2023 02:13:52 -0500 Subject: [PATCH] Fix scrobbling tracks with featured artists --- vrobbler/apps/music/utils.py | 19 ++++++++++------- vrobbler/apps/podcasts/models.py | 2 +- vrobbler/apps/scrobbles/models.py | 4 ++-- vrobbler/apps/scrobbles/musicbrainz.py | 21 +++++++++++++++++-- vrobbler/apps/scrobbles/scrobblers.py | 7 ------- vrobbler/apps/scrobbles/views.py | 29 ++++++++++++++++++-------- vrobbler/apps/sports/models.py | 6 +----- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/vrobbler/apps/music/utils.py b/vrobbler/apps/music/utils.py index f3df9e5..109f86e 100644 --- a/vrobbler/apps/music/utils.py +++ b/vrobbler/apps/music/utils.py @@ -2,7 +2,7 @@ import logging from scrobbles.musicbrainz import ( lookup_album_dict_from_mb, - lookup_artist_id_from_mb, + lookup_artist_from_mb, ) logger = logging.getLogger(__name__) @@ -12,16 +12,18 @@ from music.models import Artist, Album, Track def get_or_create_artist(name: str, mbid: str = None) -> Artist: + if 'feat.' in name: + name = name.split('feat.')[0] if mbid: - artist, artist_created = Artist.objects.get_or_create( - name=name, musicbrainz_id=mbid - ) + artist, created = Artist.objects.get_or_create(musicbrainz_id=mbid) else: - artist, artist_created = Artist.objects.get_or_create(name=name) + artist, created = Artist.objects.get_or_create(name=name) - if not mbid: - artist.musicbrainz_id = lookup_artist_id_from_mb(artist.name) - artist.save(update_fields=["musicbrainz_id"]) + if created or not mbid: + artist_dict = lookup_artist_from_mb(name) + artist.musicbrainz_id = artist_dict["id"] + artist.name = artist_dict["name"] + artist.save(update_fields=["musicbrainz_id", "name"]) return artist @@ -80,6 +82,7 @@ def get_or_create_track( title=title, artist=artist, album=album ).first() + # TODO Can we look up mbid for tracks? if not track: track = Track.objects.create( title=title, diff --git a/vrobbler/apps/podcasts/models.py b/vrobbler/apps/podcasts/models.py index 1a7ee02..9d84d5e 100644 --- a/vrobbler/apps/podcasts/models.py +++ b/vrobbler/apps/podcasts/models.py @@ -7,7 +7,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django_extensions.db.models import TimeStampedModel -from vrobbler.apps.scrobbles.mixins import ScrobblableMixin +from scrobbles.mixins import ScrobblableMixin logger = logging.getLogger(__name__) BNULL = {"blank": True, "null": True} diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index 05cfe47..b4c242a 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -8,11 +8,11 @@ from django.utils import timezone from django_extensions.db.models import TimeStampedModel from music.models import Artist, Track from podcasts.models import Episode +from profiles.utils import now_user_timezone +from scrobbles.lastfm import LastFM from scrobbles.utils import check_scrobble_for_finish from sports.models import SportEvent from videos.models import Series, Video -from vrobbler.apps.profiles.utils import now_user_timezone -from vrobbler.apps.scrobbles.lastfm import LastFM logger = logging.getLogger(__name__) User = get_user_model() diff --git a/vrobbler/apps/scrobbles/musicbrainz.py b/vrobbler/apps/scrobbles/musicbrainz.py index a7f15d6..f1ebc81 100644 --- a/vrobbler/apps/scrobbles/musicbrainz.py +++ b/vrobbler/apps/scrobbles/musicbrainz.py @@ -73,7 +73,7 @@ def lookup_album_dict_from_mb(release_name: str, artist_name: str) -> dict: } -def lookup_artist_id_from_mb(artist_name: str) -> str: +def lookup_artist_from_mb(artist_name: str) -> str: musicbrainzngs.set_useragent('vrobbler', '0.3.0') top_result = musicbrainzngs.search_artists(artist=artist_name)[ @@ -87,4 +87,21 @@ def lookup_artist_id_from_mb(artist_name: str) -> str: ) return "" - return top_result["id"] + return top_result + + +def lookup_track_from_mb(artist_name: str) -> str: + musicbrainzngs.set_useragent('vrobbler', '0.3.0') + + top_result = musicbrainzngs.search_recordings(artist=artist_name)[ + 'artist-list' + ][0] + score = int(top_result.get('ext:score')) + if score < 85: + logger.debug( + "Artist lookup score below 85 threshold", + extra={"result": top_result}, + ) + return "" + + return top_result diff --git a/vrobbler/apps/scrobbles/scrobblers.py b/vrobbler/apps/scrobbles/scrobblers.py index 3f34fc6..a0799ce 100644 --- a/vrobbler/apps/scrobbles/scrobblers.py +++ b/vrobbler/apps/scrobbles/scrobblers.py @@ -124,13 +124,6 @@ def jellyfin_scrobble_track( data_dict: dict, user_id: Optional[int] ) -> Optional[Scrobble]: - if not data_dict.get("Provider_musicbrainztrack", None): - # TODO we should be able to look up tracks via MB rather than error out - logger.error( - "No MBrainz Track ID received. This is likely because all metadata is bad, not scrobbling" - ) - return - null_position_on_progress = ( data_dict.get("PlaybackPosition") == "00:00:00" and data_dict.get("NotificationType") == "PlaybackProgress" diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index d497db2..1b323f4 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -13,6 +13,12 @@ from django.views.decorators.csrf import csrf_exempt from django.views.generic import FormView from django.views.generic.edit import CreateView from django.views.generic.list import ListView +from music.aggregators import ( + scrobble_counts, + top_artists, + top_tracks, + week_of_scrobbles, +) from rest_framework import status from rest_framework.decorators import ( api_view, @@ -26,9 +32,10 @@ from scrobbles.constants import ( JELLYFIN_AUDIO_ITEM_TYPES, JELLYFIN_VIDEO_ITEM_TYPES, ) +from scrobbles.export import export_scrobbles from scrobbles.forms import ExportScrobbleForm, ScrobbleForm from scrobbles.imdb import lookup_video_from_imdb -from scrobbles.models import AudioScrobblerTSVImport, Scrobble +from scrobbles.models import AudioScrobblerTSVImport, LastFmImport, Scrobble from scrobbles.scrobblers import ( jellyfin_scrobble_track, jellyfin_scrobble_video, @@ -41,16 +48,9 @@ from scrobbles.serializers import ( AudioScrobblerTSVImportSerializer, ScrobbleSerializer, ) +from scrobbles.tasks import process_lastfm_import from scrobbles.thesportsdb import lookup_event_from_thesportsdb -from vrobbler.apps.music.aggregators import ( - scrobble_counts, - top_artists, - top_tracks, - week_of_scrobbles, -) -from vrobbler.apps.scrobbles.export import export_scrobbles - logger = logging.getLogger(__name__) @@ -176,6 +176,17 @@ class AudioScrobblerImportCreateView( return HttpResponseRedirect(self.get_success_url()) +@permission_classes([IsAuthenticated]) +@api_view(['GET']) +def lastfm_import(request): + lfm_import = LastFmImport.objects.create(user=request.user) + + process_lastfm_import.delay(lfm_import.id) + + success_url = reverse_lazy('vrobbler-home') + return HttpResponseRedirect(success_url) + + @csrf_exempt @api_view(['GET']) def scrobble_endpoint(request): diff --git a/vrobbler/apps/sports/models.py b/vrobbler/apps/sports/models.py index a0baa61..8490ed7 100644 --- a/vrobbler/apps/sports/models.py +++ b/vrobbler/apps/sports/models.py @@ -7,12 +7,8 @@ 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 sqlalchemy import update from scrobbles.mixins import ScrobblableMixin -from vrobbler.apps.sports.utils import ( - get_players_from_event, - get_round_name_from_event, -) +from sports.utils import get_players_from_event, get_round_name_from_event logger = logging.getLogger(__name__) BNULL = {"blank": True, "null": True}