Add manual scrobbling by TheSportsDB ID

This commit is contained in:
2023-01-15 02:41:36 -05:00
parent 0378dfe6eb
commit c484905d11
8 changed files with 159 additions and 24 deletions

View File

@ -148,6 +148,25 @@ class Scrobble(TimeStampedModel):
scrobble, backoff, wait_period, scrobble_data
)
@classmethod
def create_or_update_for_sport_event(
cls, event: "SportEvent", user_id: int, jellyfin_data: dict
) -> "Scrobble":
jellyfin_data['sport_event_id'] = event.id
scrobble = (
cls.objects.filter(sport_event=event, user_id=user_id)
.order_by('-modified')
.first()
)
# Backoff is how long until we consider this a new scrobble
backoff = timezone.now() + timedelta(minutes=VIDEO_BACKOFF)
wait_period = timezone.now() + timedelta(days=VIDEO_WAIT_PERIOD)
return cls.update_or_create(
scrobble, backoff, wait_period, jellyfin_data
)
@classmethod
def update_or_create(
cls,

View File

@ -9,6 +9,7 @@ from podcasts.models import Episode
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
logger = logging.getLogger(__name__)
@ -104,18 +105,23 @@ def create_jellyfin_scrobble_dict(data_dict: dict, user_id: int) -> dict:
if data_dict.get("PlayedToCompletion"):
jellyfin_status = "stopped"
playback_position_ticks = data_dict.get("PlaybackPositionTicks") // 10000
if playback_position_ticks <= 0:
playback_position_ticks = None
playback_position_ticks = None
if data_dict.get("PlaybackPositionTicks"):
playback_position_ticks = (
data_dict.get("PlaybackPositionTicks") // 10000
)
if playback_position_ticks <= 0:
playback_position_ticks = None
playback_position = data_dict.get("PlaybackPosition")
if playback_position:
playback_position = convert_to_seconds(playback_position)
logger.debug(playback_position_ticks)
return {
"user_id": user_id,
"timestamp": parse(data_dict.get("UtcTimestamp")),
"playback_position_ticks": playback_position_ticks,
"playback_position": convert_to_seconds(
data_dict.get("PlaybackPosition")
),
"playback_position": playback_position,
"source": "Jellyfin",
"source_id": data_dict.get('MediaSourceId'),
"jellyfin_status": jellyfin_status,
@ -193,3 +199,18 @@ def manual_scrobble_video(data_dict: dict, user_id: Optional[int]):
scrobble_dict = create_jellyfin_scrobble_dict(data_dict, user_id)
return Scrobble.create_or_update_for_video(video, user_id, scrobble_dict)
def manual_scrobble_event(data_dict: dict, user_id: Optional[int]):
if not data_dict.get("Provider_thesportsdb", None):
logger.error(
"No TheSportsDB ID received. This is likely because all metadata is bad, not scrobbling"
)
return
event = SportEvent.find_or_create(data_dict)
scrobble_dict = create_jellyfin_scrobble_dict(data_dict, user_id)
return Scrobble.create_or_update_for_sport_event(
event, user_id, scrobble_dict
)

View File

@ -0,0 +1,44 @@
import logging
from dateutil.parser import parse
from django.conf import settings
from django.utils import timezone
from pysportsdb import TheSportsDbClient
from sports.models import SportEvent
logger = logging.getLogger(__name__)
API_KEY = getattr(settings, "THESPORTSDB_API_KEY", "2")
client = TheSportsDbClient(api_key=API_KEY)
def lookup_event_from_thesportsdb(event_id: str) -> dict:
event = client.lookup_event(event_id)['events'][0]
league = {} # client.lookup_league(league_id=event.get('idLeague'))
event_type = SportEvent.Type.GAME
run_time_seconds = 11700
run_time_ticks = run_time_seconds * 1000
data_dict = {
"ItemType": event_type,
"Name": event.get('strEventAlternate'),
"Start": parse(event.get('strTimestamp')),
"Provider_thesportsdb": event.get('idEvent'),
"RunTime": run_time_seconds,
"RunTimeTicks": run_time_ticks,
"LeagueId": event.get('idLeague'),
"LeagueName": event.get('strLeague'),
"HomeTeamId": event.get('idHomeTeam'),
"HomeTeamName": event.get('strHomeTeam'),
"AwayTeamId": event.get('idAwayTeam'),
"AwayTeamName": event.get('strAwayTeam'),
"RoundId": event.get('intRound'),
"PlaybackPositionTicks": None,
"PlaybackPosition": None,
"UtcTimestamp": timezone.now().strftime('%Y-%m-%d %H:%M:%S.%f%z'),
"IsPaused": False,
"PlayedToCompletion": False,
}
return data_dict

View File

@ -16,16 +16,19 @@ from scrobbles.constants import (
JELLYFIN_AUDIO_ITEM_TYPES,
JELLYFIN_VIDEO_ITEM_TYPES,
)
from scrobbles.forms import ScrobbleForm
from scrobbles.imdb import lookup_video_from_imdb
from scrobbles.models import Scrobble
from scrobbles.scrobblers import (
jellyfin_scrobble_track,
jellyfin_scrobble_video,
manual_scrobble_event,
manual_scrobble_video,
mopidy_scrobble_podcast,
mopidy_scrobble_track,
)
from scrobbles.serializers import ScrobbleSerializer
from scrobbles.thesportsdb import lookup_event_from_thesportsdb
from vrobbler.apps.music.aggregators import (
scrobble_counts,
@ -33,7 +36,6 @@ from vrobbler.apps.music.aggregators import (
top_tracks,
week_of_scrobbles,
)
from scrobbles.forms import ScrobbleForm
logger = logging.getLogger(__name__)
@ -95,7 +97,7 @@ class ManualScrobbleView(FormView):
def form_valid(self, form):
item_id = form.cleaned_data.get('itme_id')
item_id = form.cleaned_data.get('item_id')
data_dict = None
if 'tt' in item_id:
data_dict = lookup_video_from_imdb(
@ -104,12 +106,13 @@ class ManualScrobbleView(FormView):
if data_dict:
manual_scrobble_video(data_dict, self.request.user.id)
# if not data_dict:
# data_dict = lookup_event_from_thesportsdb(
# form.cleaned_data.get('item_id')
# )
# if data_dict:
# manual_scrobble_event(data_dict, self.request.user.id)
if not data_dict:
logger.debug(f"Looking for sport event with ID {item_id}")
data_dict = lookup_event_from_thesportsdb(
form.cleaned_data.get('item_id')
)
if data_dict:
manual_scrobble_event(data_dict, self.request.user.id)
return HttpResponseRedirect(reverse("home"))

View File

@ -78,27 +78,35 @@ class SportEvent(ScrobblableMixin):
exist.
"""
league_dict = {"name": data_dict.get("LeagueName", "")}
league_dict = {
"abbreviation_str": data_dict.get("LeagueName", ""),
"thesportsdb_id": data_dict.get("LeagueId", ""),
}
league, _created = League.objects.get_or_create(**league_dict)
home_team_dict = {
"name": data_dict.get("HomeTeamName", ""),
"thesportsdb_id": data_dict.get("HomeTeamId", ""),
"league": league,
}
home_team, _created = Team.objects.get_or_create(**home_team_dict)
away_team_dict = {
"name": data_dict.get("AwayTeamName", ""),
"thesportsdb_id": data_dict.get("AwayTeamId", ""),
"league": league,
}
away_team, _created = Team.objects.get_or_create(**away_team_dict)
event_dict = {
"event_type": SportEvent.Type.GAME,
"title": data_dict.get("Name"),
"event_type": data_dict.get("ItemType"),
"home_team": home_team,
"away_team": away_team,
"start_utc": data_dict['SportEventStart'],
"start": data_dict['Start'],
"league": league,
"run_time_ticks": data_dict.get("RunTimeTicks"),
"run_time": data_dict.get("RunTime", ""),
}
event, _created = cls.objects.get_or_create(**event_dict)

View File

@ -96,7 +96,6 @@ class Video(ScrobblableMixin):
video, created = cls.objects.get_or_create(**video_dict)
logger.debug(data_dict)
run_time_ticks = data_dict.get("RunTimeTicks", None)
if run_time_ticks:
run_time_ticks = run_time_ticks // 10000