From e47f4905e86a2a1b4d69ee06e4b98520ff26cd70 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Fri, 8 Mar 2024 12:45:45 -0500 Subject: [PATCH] [scrobbles] Radically simplify stopping ... may need to roll this back --- vrobbler/apps/music/models.py | 2 +- vrobbler/apps/scrobbles/models.py | 75 ++++++++++++++++++++++--------- vrobbler/apps/scrobbles/utils.py | 48 -------------------- 3 files changed, 55 insertions(+), 70 deletions(-) diff --git a/vrobbler/apps/music/models.py b/vrobbler/apps/music/models.py index b67f6ad..98f5e79 100644 --- a/vrobbler/apps/music/models.py +++ b/vrobbler/apps/music/models.py @@ -404,7 +404,7 @@ class Album(TimeStampedModel): class Track(ScrobblableMixin): - COMPLETION_PERCENT = getattr(settings, "MUSIC_COMPLETION_PERCENT", 95) + COMPLETION_PERCENT = getattr(settings, "MUSIC_COMPLETION_PERCENT", 99) class Opinion(models.IntegerChoices): DOWN = -1, "Thumbs down" diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index ac7b5c9..20060dc 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -32,10 +32,7 @@ from profiles.utils import ( ) from scrobbles.constants import LONG_PLAY_MEDIA from scrobbles.stats import build_charts -from scrobbles.utils import ( - check_scrobble_for_finish, - media_class_to_foreign_key, -) +from scrobbles.utils import media_class_to_foreign_key from sports.models import SportEvent from videogames import retroarch from videogames.models import VideoGame @@ -961,46 +958,60 @@ class Scrobble(TimeStampedModel): return [s.geo_location for s in past_scrobbles] def update(self, scrobble_data: dict) -> "Scrobble": - logger.info( - "[scrobbling] update", - extra={ - "scrobble_id": self.id, - "scrobble_data": scrobble_data, - "media_type": self.media_type, - }, - ) # 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 self.percent_played < 100: - # Only worry about ticks if we haven't gotten to the end - self.update_ticks(scrobble_data) + logger.info( + "[scrobbling] update called", + extra={ + "scrobble_id": self.id, + "scrobble_data": scrobble_data, + "media_type": self.media_type, + "scrobble_status": scrobble_status, + }, + ) + + # This is really expensive on the DB ... do we need to track this? + # if self.percent_played < 100: + # # Only worry about ticks if we haven't gotten to the end + # self.update_ticks(scrobble_data) + + if self.beyond_completion_percent: + scrobble_status = "stopped" - # On stop, stop progress and send it to the check for completion if scrobble_status == "stopped": self.stop() - # On pause, set is_paused and stop scrobbling if scrobble_status == "paused": self.pause() if scrobble_status == "resumed": self.resume() - check_scrobble_for_finish(self) - if scrobble_status != "resumed": scrobble_data["stop_timestamp"] = ( scrobble_data.pop("timestamp", None) or timezone.now() ) + # timestamp is should be more-or-less immutable scrobble_data.pop("timestamp", None) + update_fields = [] for key, value in scrobble_data.items(): setattr(self, key, value) update_fields.append(key) self.save(update_fields=update_fields) + logger.info( + "[scrobbling] update finished", + extra={ + "scrobble_id": self.id, + "scrobble_data": scrobble_data, + "scrobble_status": scrobble_status, + "media_type": self.media_type, + }, + ) + return self @classmethod @@ -1016,9 +1027,9 @@ class Scrobble(TimeStampedModel): def stop(self, force_finish=False) -> None: self.stop_timestamp = timezone.now() - if force_finish: - self.played_to_completion = True + self.played_to_completion = True self.in_progress = False + if not self.playback_position_seconds: self.playback_position_seconds = int( (self.stop_timestamp - self.timestamp).total_seconds() @@ -1110,3 +1121,25 @@ class Scrobble(TimeStampedModel): "scrobble_id": self.id, }, ) + + @property + def beyond_completion_percent(self) -> bool: + """Returns true if our media is beyond our completion percent, unless + our type is geolocation in which case we always return false + """ + beyond_completion = ( + self.percent_played >= self.media_obj.COMPLETION_PERCENT + ) + + if self.media_type == "GeoLocation": + logger.info( + f"[scrobbling] locations are ONLY completed when new one is created", + extra={ + "scrobble_id": self.id, + "media_type": self.media_type, + "beyond_completion": beyond_completion, + }, + ) + beyond_completion = False + + return beyond_completion diff --git a/vrobbler/apps/scrobbles/utils.py b/vrobbler/apps/scrobbles/utils.py index 7425c60..b706a28 100644 --- a/vrobbler/apps/scrobbles/utils.py +++ b/vrobbler/apps/scrobbles/utils.py @@ -88,54 +88,6 @@ def parse_mopidy_uri(uri: str) -> dict: } -def check_scrobble_for_finish( - scrobble: "Scrobble", force_to_100=False, force_finish=False -) -> None: - completion_percent = scrobble.media_obj.COMPLETION_PERCENT - - if scrobble.media_type == "GeoLocation" and not force_finish: - logger.info( - f"[scrobbling] not complete, locations are ONLY completed when new one is created, use force_finish", - extra={ - "scrobble_id": scrobble.id, - "media_type": scrobble.media_type, - }, - ) - return - - is_complete = False - if scrobble.percent_played >= completion_percent or force_finish: - is_complete = True - # A hack to fix overruns on time ... default to media taking as long as needed to finish - scrobble.playback_position_seconds = ( - scrobble.media_obj.run_time_seconds - ) - - scrobble.in_progress = False - scrobble.is_paused = False - scrobble.played_to_completion = True - - scrobble.save( - update_fields=[ - "in_progress", - "is_paused", - "played_to_completion", - "playback_position_seconds", - ] - ) - logger.info( - f"[scrobbling] checked for completion", - extra={ - "scrobble_id": scrobble.id, - "media_type": scrobble.media_type, - "percent_played": scrobble.percent_played, - "completion_percent": completion_percent, - "is_complete": is_complete, - "force_finish": force_finish, - }, - ) - - def get_scrobbles_for_media(media_obj, user: User) -> models.QuerySet: Scrobble = apps.get_model(app_label="scrobbles", model_name="Scrobble")