diff --git a/vrobbler/apps/scrobbles/constants.py b/vrobbler/apps/scrobbles/constants.py index ec699f6..b26b9a9 100644 --- a/vrobbler/apps/scrobbles/constants.py +++ b/vrobbler/apps/scrobbles/constants.py @@ -14,6 +14,10 @@ PLAY_AGAIN_MEDIA = { "boardgames": "BoardGame", } +MEDIA_END_PADDING_SECONDS = { + "Video": 1800, # 30 min + "Track": 1, # 1 second +} EXCLUDE_FROM_NOW_PLAYING = ("GeoLocation",) diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index 7efc96a..b79a667 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -1,12 +1,11 @@ import calendar import datetime -from decimal import Decimal import logging +from decimal import Decimal from typing import Iterable, Optional from uuid import uuid4 import pendulum - from boardgames.models import BoardGame from books.koreader import process_koreader_sqlite_file from books.models import Book @@ -43,6 +42,8 @@ from videogames.models import VideoGame from videos.models import Series, Video from webpages.models import WebPage +from vrobbler.apps.scrobbles.constants import MEDIA_END_PADDING_SECONDS + logger = logging.getLogger(__name__) User = get_user_model() BNULL = {"blank": True, "null": True} @@ -686,23 +687,42 @@ class Scrobble(TimeStampedModel): return percent + @property + def probably_still_in_progress(self) -> bool: + """Add our start time to our media run time to get when we expect to + + Audio tracks should be given a second or two of grace, videos should + be given closer to 30 minutes, because the odds of watching it back to + back are very slim. + + """ + is_in_progress = False + padding_seconds = MEDIA_END_PADDING_SECONDS.get(self.media_type) + if not padding_seconds: + return is_in_progress + + expected_end = self.timestamp + datetime.timedelta( + seconds=self.media_obj.run_time_seconds + ) + expected_end_padded = expected_end + datetime.timedelta( + seconds=padding_seconds + ) + # Take our start time, add our media length and an extra 30 min (1800s) is it still in the future? keep going + is_in_progress = expected_end_padded > pendulum.now() + logger.info( + "[scrobbling] checking if we're probably still playing", + extra={ + "media_id": self.media_obj.id, + "scrobble_id": self.id, + "media_type": self.media_type, + "probably_still_in_progress": is_in_progress, + }, + ) + return is_in_progress + @property def can_be_updated(self) -> bool: updatable = True - probably_still_watching = False - if self.media_type == self.MediaType.VIDEO: - probably_still_watching = ( - pendulum.now() - self.timestamp - ).seconds < 1800 # 30 min - logger.info( - "[scrobbling] checking for long played video", - extra={ - "media_id": self.media_obj.id, - "scrobble_id": self.id, - "media_type": self.media_type, - "probably_still_watching": probably_still_watching, - }, - ) if self.media_obj.__class__.__name__ in LONG_PLAY_MEDIA.values(): logger.info( @@ -714,11 +734,7 @@ class Scrobble(TimeStampedModel): }, ) updatable = False - if ( - updatable - and self.percent_played >= 100 - and not probably_still_watching - ): + if updatable and self.percent_played >= 100: logger.info( f"[scrobbling] cannot be updated, existing scrobble is 100% played", extra={ @@ -739,6 +755,9 @@ class Scrobble(TimeStampedModel): ) updatable = False + if self.probably_still_in_progress: + updatable = True + return updatable @property