Browse Source

Fix lastfm importing

Colin Powell 2 years ago
parent
commit
20528b576b

+ 12 - 6
vrobbler/apps/music/utils.py

@@ -11,15 +11,21 @@ logger = logging.getLogger(__name__)
 from music.models import Artist, Album, Track
 
 
-def get_or_create_artist(name: str) -> Artist:
-    artist, artist_created = Artist.objects.get_or_create(name=name)
-    if artist_created:
+def get_or_create_artist(name: str, mbid: str = None) -> Artist:
+    if mbid:
+        artist, artist_created = Artist.objects.get_or_create(
+            name=name, musicbrainz_id=mbid
+        )
+    else:
+        artist, 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"])
     return artist
 
 
-def get_or_create_album(name: str, artist: Artist) -> Album:
+def get_or_create_album(name: str, artist: Artist, mbid: str = None) -> Album:
     album = None
     album_created = False
     albums = Album.objects.filter(name__iexact=name)
@@ -31,11 +37,11 @@ def get_or_create_album(name: str, artist: Artist) -> Album:
                 album = potential_album
     if not album:
         album_created = True
-        album = Album.objects.create(name=name)
+        album = Album.objects.create(name=name, musicbrainz_id=mbid)
         album.save()
         album.artists.add(artist)
 
-    if album_created:
+    if album_created or not mbid:
         album_dict = lookup_album_dict_from_mb(
             album.name, artist_name=artist.name
         )

+ 28 - 17
vrobbler/apps/scrobbles/lastfm.py

@@ -5,6 +5,7 @@ from datetime import datetime, timedelta
 import pylast
 import pytz
 from django.conf import settings
+from django.utils import timezone
 from music.utils import (
     get_or_create_album,
     get_or_create_artist,
@@ -71,8 +72,8 @@ class LastFM:
             ten_seconds_eariler = timestamp - timedelta(seconds=15)
             ten_seconds_later = timestamp + timedelta(seconds=15)
             existing = Scrobble.objects.filter(
-                created__gte=ten_seconds_eariler,
-                created__lte=ten_seconds_later,
+                timestamp__gte=ten_seconds_eariler,
+                timestamp__lte=ten_seconds_later,
                 track=track,
             ).first()
             if existing:
@@ -112,32 +113,42 @@ class LastFM:
     def get_last_scrobbles(self, time_from=None, time_to=None):
         """Given a user, Last.fm api key, and secret key, grab a list of scrobbled
         tracks"""
+        lfm_params = {}
         scrobbles = []
         if time_from:
-            time_from = int(time_from.timestamp())
+            lfm_params["time_from"] = int(time_from.timestamp())
         if time_to:
-            time_to = int(time_to.timestamp())
+            lfm_params["time_to"] = int(time_to.timestamp())
+
+        # if not time_from and not time_to:
+        lfm_params['limit'] = None
+
+        found_scrobbles = self.user.get_recent_tracks(**lfm_params)
 
-        if not time_from and not time_to:
-            found_scrobbles = self.user.get_recent_tracks(limit=None)
-        else:
-            found_scrobbles = self.user.get_recent_tracks(
-                time_from=time_from, time_to=time_to
-            )
         for scrobble in found_scrobbles:
-            run_time_ticks = scrobble.track.get_duration()
-            run_time = run_time_ticks / 1000
+            try:
+                run_time_ticks = scrobble.track.get_duration()
+                run_time = int(run_time_ticks / 1000)
+            except pylast.MalformedResponseError:
+                run_time_ticks = None
+                run_time = None
+                logger.warn(f"Track {scrobble.track} has no duration")
+
+            timestamp = datetime.utcfromtimestamp(
+                int(scrobble.timestamp)
+            ).replace(tzinfo=pytz.utc)
+            artist = scrobble.track.get_artist().name
+
+            logger.debug(f"{artist},{scrobble.track.title},{timestamp}")
             scrobbles.append(
                 {
-                    "artist": scrobble.track.get_artist().name,
+                    "artist": artist,
                     "album": scrobble.album,
                     "title": scrobble.track.title,
                     "mbid": scrobble.track.get_mbid(),
-                    "run_time": int(run_time),
+                    "run_time": run_time,
                     "run_time_ticks": run_time_ticks,
-                    "timestamp": datetime.utcfromtimestamp(
-                        int(scrobble.timestamp)
-                    ).replace(tzinfo=pytz.utc),
+                    "timestamp": timestamp,
                 }
             )
         return scrobbles

+ 5 - 2
vrobbler/apps/scrobbles/musicbrainz.py

@@ -62,9 +62,12 @@ def lookup_album_dict_from_mb(release_name: str, artist_name: str) -> dict:
             extra={"result": top_result},
         )
         return {}
-    print(top_result)
+    year = None
+    if top_result.get("date"):
+        year = parse(top_result["date"]).year
+
     return {
-        "year": parse(top_result["date"]).year,
+        "year": year,
         "mb_id": top_result["id"],
         "mb_group_id": top_result["release-group"]["id"],
     }

+ 45 - 48
vrobbler/apps/scrobbles/scrobblers.py

@@ -10,6 +10,11 @@ from scrobbles.models import Scrobble
 from scrobbles.utils import convert_to_seconds, parse_mopidy_uri
 from videos.models import Video
 from sports.models import SportEvent
+from vrobbler.apps.music.utils import (
+    get_or_create_album,
+    get_or_create_artist,
+    get_or_create_track,
+)
 
 logger = logging.getLogger(__name__)
 
@@ -57,23 +62,23 @@ def mopidy_scrobble_podcast(
 def mopidy_scrobble_track(
     data_dict: dict, user_id: Optional[int]
 ) -> Optional[Scrobble]:
-    artist_dict = {
-        "name": data_dict.get("artist", None),
-        "musicbrainz_id": data_dict.get("musicbrainz_artist_id", None),
-    }
-
-    album_dict = {
-        "name": data_dict.get("album"),
-        "musicbrainz_id": data_dict.get("musicbrainz_album_id"),
-    }
-
-    track_dict = {
-        "title": data_dict.get("name"),
-        "run_time_ticks": data_dict.get("run_time_ticks"),
-        "run_time": data_dict.get("run_time"),
-    }
-
-    track = Track.find_or_create(artist_dict, album_dict, track_dict)
+    artist = get_or_create_artist(
+        data_dict.get("artist"),
+        mbid=data_dict.get("musicbrainz_artist_id", None),
+    )
+    album = get_or_create_album(
+        data_dict.get("album"),
+        artist=artist,
+        mbid=data_dict.get("musicbrainz_album_id"),
+    )
+    track = get_or_create_track(
+        title=data_dict.get("name"),
+        mbid=data_dict.get("musicbrainz_track_id"),
+        artist=artist,
+        album=album,
+        run_time_ticks=data_dict.get("run_time_ticks"),
+        run_time=data_dict.get("run_time"),
+    )
 
     # Now we run off a scrobble
     mopidy_data = {
@@ -136,38 +141,30 @@ def jellyfin_scrobble_track(
         logger.error("No playback position tick from Jellyfin, aborting")
         return
 
-    artist_dict = {
-        'name': data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"], None),
-        'musicbrainz_id': data_dict.get(
-            JELLYFIN_POST_KEYS["ARTIST_MB_ID"], None
-        ),
-    }
-
-    album_dict = {
-        "name": data_dict.get(JELLYFIN_POST_KEYS["ALBUM_NAME"], None),
-        "musicbrainz_id": data_dict.get(JELLYFIN_POST_KEYS['ALBUM_MB_ID']),
-    }
-
-    # Convert ticks from Jellyfin from microseconds to nanoseconds
-    # Ain't nobody got time for nanoseconds
-    track_dict = {
-        "title": data_dict.get("Name", ""),
-        "run_time_ticks": data_dict.get(
-            JELLYFIN_POST_KEYS["RUN_TIME_TICKS"], None
-        )
-        // 10000,
-        "run_time": convert_to_seconds(
-            data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME"], None)
-        ),
-    }
-    track = Track.find_or_create(artist_dict, album_dict, track_dict)
+    artist = get_or_create_artist(
+        data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"]),
+        mbid=data_dict.get(JELLYFIN_POST_KEYS["ARTIST_MB_ID"]),
+    )
+    album = get_or_create_album(
+        data_dict.get(JELLYFIN_POST_KEYS["ALBUM_NAME"]),
+        artist=artist,
+        mbid=data_dict.get(JELLYFIN_POST_KEYS['ALBUM_MB_ID']),
+    )
 
-    # Prefer Mopidy MD IDs to Jellyfin, so skip if we already have one
-    if not track.musicbrainz_id:
-        track.musicbrainz_id = data_dict.get(
-            JELLYFIN_POST_KEYS["TRACK_MB_ID"], None
-        )
-        track.save()
+    run_time_ticks = (
+        data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME_TICKS"]) // 10000
+    )
+    run_time = convert_to_seconds(
+        data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME"])
+    )
+    track = get_or_create_track(
+        title=data_dict.get("Name"),
+        mbid=data_dict.get(JELLYFIN_POST_KEYS["TRACK_MB_ID"]),
+        artist=artist,
+        album=album,
+        run_time_ticks=run_time_ticks,
+        run_time=run_time,
+    )
 
     scrobble_dict = build_scrobble_dict(data_dict, user_id)