Pārlūkot izejas kodu

Fix Mopidy resuming messing things up

Colin Powell 2 gadi atpakaļ
vecāks
revīzija
6cdcf4ff6f

+ 30 - 19
vrobbler/apps/scrobbles/models.py

@@ -78,8 +78,7 @@ class Scrobble(TimeStampedModel):
     def __str__(self):
         return f"Scrobble of {self.media_obj} {self.timestamp.year}-{self.timestamp.month}"
 
-    @property
-    def resumable(self):
+    def resumable(self, playback_ticks):
         """Check if a scrobble is not finished or beyond the configured resume limit.
 
         The idea here is to check whether a scrobble should be resumed, or a new
@@ -98,6 +97,10 @@ class Scrobble(TimeStampedModel):
         beyond_resume_limit = False
         now = timezone.now()
 
+        if self.playback_position_ticks == playback_ticks:
+            # shortcircut in the case where we've resumed a track at the same playback ticks
+            return True
+
         if self.video:
             diff = timedelta(seconds=Video.RESUME_LIMIT)
             percent_for_completion = Video.COMPLETION_PERCENT
@@ -140,7 +143,9 @@ class Scrobble(TimeStampedModel):
             .order_by('-modified')
             .first()
         )
-        if scrobble and scrobble.resumable:
+        if scrobble and scrobble.resumable(
+            scrobble_data['playback_position_ticks']
+        ):
             logger.info(
                 f"Found existing scrobble for video {video}, updating",
                 {"scrobble_data": scrobble_data},
@@ -169,7 +174,9 @@ class Scrobble(TimeStampedModel):
             .order_by('-modified')
             .first()
         )
-        if scrobble and scrobble.resumable:
+        if scrobble and scrobble.resumable(
+            scrobble_data['playback_position_ticks']
+        ):
             logger.debug(
                 f"Found existing scrobble for track {track}, updating",
                 {"scrobble_data": scrobble_data},
@@ -195,7 +202,9 @@ class Scrobble(TimeStampedModel):
             .order_by('-modified')
             .first()
         )
-        if scrobble and scrobble.resumable:
+        if scrobble and scrobble.resumable(
+            scrobble_data['playback_position_ticks']
+        ):
             logger.debug(
                 f"Found existing scrobble for podcast {episode}, updating",
                 {"scrobble_data": scrobble_data},
@@ -220,7 +229,9 @@ class Scrobble(TimeStampedModel):
             .order_by('-modified')
             .first()
         )
-        if scrobble and scrobble.resumable:
+        if scrobble and scrobble.resumable(
+            scrobble_data['playback_position_ticks']
+        ):
             logger.debug(
                 f"Found existing scrobble for sport event {event}, updating",
                 {"scrobble_data": scrobble_data},
@@ -236,30 +247,25 @@ class Scrobble(TimeStampedModel):
         return cls.create(scrobble_data)
 
     @classmethod
-    def update(cls, scrobble: "Scrobble", scrobble_data: dict):
+    def update(cls, scrobble: "Scrobble", scrobble_data: dict) -> "Scrobble":
         # Status is a field we get from Mopidy, which refuses to poll us
         scrobble_status = scrobble_data.pop('mopidy_status', None)
         if not scrobble_status:
             scrobble_status = scrobble_data.pop('jellyfin_status', None)
         if not scrobble_status:
-            logger.warning(
-                f"No status update found in message, not scrobbling"
-            )
-            return
+            scrobble_status = 'resumed'
 
         logger.debug(f"Scrobbling to {scrobble} with status {scrobble_status}")
         scrobble.update_ticks(scrobble_data)
 
         # On stop, stop progress and send it to the check for completion
         if scrobble_status == "stopped":
-            return scrobble.stop()
-
+            scrobble.stop()
         # On pause, set is_paused and stop scrobbling
         if scrobble_status == "paused":
-            return scrobble.pause()
-
+            scrobble.pause()
         if scrobble_status == "resumed":
-            return scrobble.resume()
+            scrobble.resume()
 
         for key, value in scrobble_data.items():
             setattr(scrobble, key, value)
@@ -287,7 +293,7 @@ class Scrobble(TimeStampedModel):
         check_scrobble_for_finish(self)
 
     def pause(self) -> None:
-        if self.is_paused:
+        if self.is_paused and not self.played_to_completion:
             logger.warning("Scrobble already paused")
             return
         self.is_paused = True
@@ -295,10 +301,15 @@ class Scrobble(TimeStampedModel):
         check_scrobble_for_finish(self)
 
     def resume(self) -> None:
-        if self.is_paused or not self.in_progress:
+        if self.is_paused or not self.played_to_completion:
             self.is_paused = False
             self.in_progress = True
-            return self.save(update_fields=["is_paused", "in_progress"])
+            return self.save(
+                update_fields=[
+                    "is_paused",
+                    "in_progress",
+                ]
+            )
 
     def update_ticks(self, data) -> None:
         self.playback_position_ticks = data.get("playback_position_ticks")

+ 5 - 8
vrobbler/apps/scrobbles/scrobblers.py

@@ -86,15 +86,12 @@ def mopidy_scrobble_track(
         "mopidy_status": data_dict.get("status"),
     }
 
-    scrobble = None
+    # Jellyfin MB ids suck, so always overwrite with Mopidy if they're offering
+    track.musicbrainz_id = data_dict.get("musicbrainz_track_id")
+    track.save()
+
+    scrobble = Scrobble.create_or_update_for_track(track, user_id, mopidy_data)
 
-    if track:
-        # Jellyfin MB ids suck, so always overwrite with Mopidy if they're offering
-        track.musicbrainz_id = data_dict.get("musicbrainz_track_id")
-        track.save()
-        scrobble = Scrobble.create_or_update_for_track(
-            track, user_id, mopidy_data
-        )
     return scrobble
 
 

+ 3 - 0
vrobbler/apps/scrobbles/utils.py

@@ -76,6 +76,9 @@ def check_scrobble_for_finish(scrobble: "Scrobble") -> None:
             settings, "PODCAST_COMPLETION_PERCENT", 25
         )
     if scrobble.percent_played >= completion_percent:
+        logger.debug(
+            f"Beyond completion percent {completion_percent}, finishing scrobble"
+        )
         scrobble.in_progress = False
         scrobble.is_paused = False
         scrobble.played_to_completion = True

+ 2 - 6
vrobbler/apps/scrobbles/views.py

@@ -148,9 +148,7 @@ def jellyfin_websocket(request):
     if not scrobble:
         return Response({}, status=status.HTTP_400_BAD_REQUEST)
 
-    return Response(
-        {'scrobble_id': scrobble.id}, status=status.HTTP_201_CREATED
-    )
+    return Response({'scrobble_id': scrobble.id}, status=status.HTTP_200_OK)
 
 
 @csrf_exempt
@@ -171,6 +169,4 @@ def mopidy_websocket(request):
     if not scrobble:
         return Response({}, status=status.HTTP_400_BAD_REQUEST)
 
-    return Response(
-        {'scrobble_id': scrobble.id}, status=status.HTTP_201_CREATED
-    )
+    return Response({'scrobble_id': scrobble.id}, status=status.HTTP_200_OK)