Fix proper scrobbling of podcasts
This commit is contained in:
@ -13,8 +13,9 @@ class ScrobbleAdmin(admin.ModelAdmin):
|
|||||||
"source",
|
"source",
|
||||||
"playback_position",
|
"playback_position",
|
||||||
"in_progress",
|
"in_progress",
|
||||||
|
"is_paused",
|
||||||
)
|
)
|
||||||
list_filter = ("in_progress", "source", "track__artist")
|
list_filter = ("is_paused", "in_progress", "source", "track__artist")
|
||||||
ordering = ("-timestamp",)
|
ordering = ("-timestamp",)
|
||||||
|
|
||||||
def media_name(self, obj):
|
def media_name(self, obj):
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from django.utils import timezone
|
|||||||
from django_extensions.db.models import TimeStampedModel
|
from django_extensions.db.models import TimeStampedModel
|
||||||
from music.models import Track
|
from music.models import Track
|
||||||
from podcasts.models import Episode
|
from podcasts.models import Episode
|
||||||
|
from scrobbles.utils import check_scrobble_for_finish
|
||||||
from videos.models import Video
|
from videos.models import Video
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -180,6 +181,13 @@ class Scrobble(TimeStampedModel):
|
|||||||
mopidy_status = scrobble_data.pop('status', None)
|
mopidy_status = scrobble_data.pop('status', None)
|
||||||
scrobble_is_stale = False
|
scrobble_is_stale = False
|
||||||
|
|
||||||
|
if scrobble:
|
||||||
|
logger.debug(f"Updating scrobble ticks")
|
||||||
|
scrobble.playback_position_ticks = scrobble_data.get(
|
||||||
|
"playback_position_ticks"
|
||||||
|
)
|
||||||
|
scrobble.save(update_fields=['playback_position_ticks'])
|
||||||
|
|
||||||
if mopidy_status == "stopped":
|
if mopidy_status == "stopped":
|
||||||
logger.info(f"Mopidy sent a message to stop {scrobble}")
|
logger.info(f"Mopidy sent a message to stop {scrobble}")
|
||||||
if not scrobble:
|
if not scrobble:
|
||||||
@ -190,7 +198,37 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
# Mopidy finished a play, scrobble away
|
# Mopidy finished a play, scrobble away
|
||||||
scrobble.in_progress = False
|
scrobble.in_progress = False
|
||||||
scrobble.save(update_fields=['in_progress'])
|
scrobble.played_to_completion = True
|
||||||
|
scrobble.save(
|
||||||
|
update_fields=['in_progress', 'played_to_completion']
|
||||||
|
)
|
||||||
|
return scrobble
|
||||||
|
|
||||||
|
if mopidy_status == "paused":
|
||||||
|
logger.info(f"Mopidy sent a message to pause {scrobble}")
|
||||||
|
if not scrobble:
|
||||||
|
logger.info("Message to pause while not started, ignoring")
|
||||||
|
return
|
||||||
|
if scrobble.is_paused:
|
||||||
|
logger.info("Message to pause while paused, ignoring")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Mopidy finished a play, scrobble away
|
||||||
|
scrobble.is_paused = True
|
||||||
|
scrobble.save(update_fields=["is_paused"])
|
||||||
|
scrobble = check_scrobble_for_finish(scrobble)
|
||||||
|
return scrobble
|
||||||
|
|
||||||
|
if mopidy_status == "resumed":
|
||||||
|
logger.info(f"Mopidy sent a message to resume {scrobble}")
|
||||||
|
if not scrobble:
|
||||||
|
logger.info("Message to resume while not started, ignoring")
|
||||||
|
return
|
||||||
|
if not scrobble.is_paused:
|
||||||
|
logger.info("Message to resume while not paused, resuming")
|
||||||
|
# Mopidy finished a play, scrobble away
|
||||||
|
scrobble.is_paused = False
|
||||||
|
scrobble.save(update_fields=["is_paused"])
|
||||||
return scrobble
|
return scrobble
|
||||||
|
|
||||||
if scrobble and not mopidy_status:
|
if scrobble and not mopidy_status:
|
||||||
@ -218,16 +256,6 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
# If we hit our completion threshold, save it and get ready
|
# If we hit our completion threshold, save it and get ready
|
||||||
# to scrobble again if we re-watch this.
|
# to scrobble again if we re-watch this.
|
||||||
if scrobble.percent_played >= getattr(
|
scrobble = check_scrobble_for_finish(scrobble)
|
||||||
settings, "PERCENT_FOR_COMPLETION", 95
|
|
||||||
):
|
|
||||||
scrobble.in_progress = False
|
|
||||||
scrobble.playback_position_ticks = scrobble.media_run_time_ticks
|
|
||||||
scrobble.save()
|
|
||||||
|
|
||||||
if scrobble.percent_played % 5 == 0:
|
|
||||||
if getattr(settings, "KEEP_DETAILED_SCROBBLE_LOGS", False):
|
|
||||||
scrobble.scrobble_log += f"\n{str(scrobble.timestamp)} - {scrobble.playback_position} - {str(scrobble.playback_position_ticks)} - {str(scrobble.percent_played)}%"
|
|
||||||
scrobble.save(update_fields=['scrobble_log'])
|
|
||||||
|
|
||||||
return scrobble
|
return scrobble
|
||||||
|
|||||||
@ -10,7 +10,9 @@ from scrobbles.utils import parse_mopidy_uri
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def scrobble_podcast(data_dict: dict, user_id: Optional[int]) -> Scrobble:
|
def mopidy_scrobble_podcast(
|
||||||
|
data_dict: dict, user_id: Optional[int]
|
||||||
|
) -> Scrobble:
|
||||||
mopidy_uri = data_dict.get("mopidy_uri", "")
|
mopidy_uri = data_dict.get("mopidy_uri", "")
|
||||||
parsed_data = parse_mopidy_uri(mopidy_uri)
|
parsed_data = parse_mopidy_uri(mopidy_uri)
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ def scrobble_podcast(data_dict: dict, user_id: Optional[int]) -> Scrobble:
|
|||||||
mopidy_data = {
|
mopidy_data = {
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"timestamp": timezone.now(),
|
"timestamp": timezone.now(),
|
||||||
|
"playback_position_ticks": data_dict.get("playback_time_ticks"),
|
||||||
"source": "Mopidy",
|
"source": "Mopidy",
|
||||||
"status": data_dict.get("status"),
|
"status": data_dict.get("status"),
|
||||||
}
|
}
|
||||||
@ -49,7 +52,7 @@ def scrobble_podcast(data_dict: dict, user_id: Optional[int]) -> Scrobble:
|
|||||||
return scrobble
|
return scrobble
|
||||||
|
|
||||||
|
|
||||||
def scrobble_track(
|
def mopidy_scrobble_track(
|
||||||
data_dict: dict, user_id: Optional[int]
|
data_dict: dict, user_id: Optional[int]
|
||||||
) -> Optional[Scrobble]:
|
) -> Optional[Scrobble]:
|
||||||
artist_dict = {
|
artist_dict = {
|
||||||
@ -74,6 +77,7 @@ def scrobble_track(
|
|||||||
mopidy_data = {
|
mopidy_data = {
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"timestamp": timezone.now(),
|
"timestamp": timezone.now(),
|
||||||
|
"playback_position_ticks": data_dict.get("playback_time_ticks"),
|
||||||
"source": "Mopidy",
|
"source": "Mopidy",
|
||||||
"status": data_dict.get("status"),
|
"status": data_dict.get("status"),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from typing import Any
|
|||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from dateutil.parser import ParserError, parse
|
from dateutil.parser import ParserError, parse
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -57,3 +58,34 @@ def parse_mopidy_uri(uri: str) -> dict:
|
|||||||
'podcast_name': podcast_str,
|
'podcast_name': podcast_str,
|
||||||
'pub_date': pub_date,
|
'pub_date': pub_date,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_scrobble_for_finish(scrobble: "Scrobble") -> None:
|
||||||
|
completion_percent = getattr(settings, "MUSIC_COMPLETION_PERCENT", 90)
|
||||||
|
if scrobble.podcast_episode:
|
||||||
|
completion_percent = getattr(
|
||||||
|
settings, "PODCAST_COMPLETION_PERCENT", 25
|
||||||
|
)
|
||||||
|
logger.debug(f"Completion set to {completion_percent}")
|
||||||
|
|
||||||
|
if scrobble.percent_played >= completion_percent:
|
||||||
|
logger.debug(
|
||||||
|
f"{scrobble} meets completion goal of {completion_percent}, finishing"
|
||||||
|
)
|
||||||
|
scrobble.in_progress = False
|
||||||
|
scrobble.is_paused = False
|
||||||
|
scrobble.playback_position_ticks = scrobble.media_obj.run_time_ticks
|
||||||
|
scrobble.save(
|
||||||
|
update_fields=[
|
||||||
|
"in_progress",
|
||||||
|
"is_paused",
|
||||||
|
"playback_position_ticks",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
if scrobble.percent_played % 5 == 0:
|
||||||
|
if getattr(settings, "KEEP_DETAILED_SCROBBLE_LOGS", False):
|
||||||
|
scrobble.scrobble_log += f"\n{str(scrobble.timestamp)} - {scrobble.playback_position} - {str(scrobble.playback_position_ticks)} - {str(scrobble.percent_played)}%"
|
||||||
|
scrobble.save(update_fields=['scrobble_log'])
|
||||||
|
|
||||||
|
return scrobble
|
||||||
|
|||||||
@ -27,7 +27,7 @@ from vrobbler.apps.music.aggregators import (
|
|||||||
top_tracks,
|
top_tracks,
|
||||||
week_of_scrobbles,
|
week_of_scrobbles,
|
||||||
)
|
)
|
||||||
from scrobbles.scrobblers import scrobble_podcast, scrobble_track
|
from scrobbles.scrobblers import mopidy_scrobble_podcast, mopidy_scrobble_track
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -191,9 +191,9 @@ def mopidy_websocket(request):
|
|||||||
logger.debug(f"{json_data}")
|
logger.debug(f"{json_data}")
|
||||||
|
|
||||||
if 'podcast' in data_dict.get('mopidy_uri'):
|
if 'podcast' in data_dict.get('mopidy_uri'):
|
||||||
scrobble = scrobble_podcast(data_dict, request.user.id)
|
scrobble = mopidy_scrobble_podcast(data_dict, request.user.id)
|
||||||
else:
|
else:
|
||||||
scrobble = scrobble_track(data_dict, request.user.id)
|
scrobble = mopidy_scrobble_track(data_dict, request.user.id)
|
||||||
|
|
||||||
if not scrobble:
|
if not scrobble:
|
||||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|||||||
@ -37,6 +37,11 @@ KEEP_DETAILED_SCROBBLE_LOGS = os.getenv(
|
|||||||
"VROBBLER_KEEP_DETAILED_SCROBBLE_LOGS", False
|
"VROBBLER_KEEP_DETAILED_SCROBBLE_LOGS", False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PODCAST_COMPLETION_PERCENT = os.getenv(
|
||||||
|
"VROBBLER_PODCAST_COMPLETION_PERCENT", 25
|
||||||
|
)
|
||||||
|
MUSIC_COMPLETION_PERCENT = os.getenv("VROBBLER_MUSIC_COMPLETION_PERCENT", 90)
|
||||||
|
|
||||||
# Should we cull old in-progress scrobbles that are beyond the wait period for resuming?
|
# Should we cull old in-progress scrobbles that are beyond the wait period for resuming?
|
||||||
DELETE_STALE_SCROBBLES = os.getenv("VROBBLER_DELETE_STALE_SCROBBLES", True)
|
DELETE_STALE_SCROBBLES = os.getenv("VROBBLER_DELETE_STALE_SCROBBLES", True)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user