From a4537879f93f2c195dc49ff470f4948021e7b4b3 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Sun, 5 Mar 2023 18:05:10 -0500 Subject: [PATCH] Allow scrobbling video games --- vrobbler/apps/scrobbles/scrobblers.py | 22 ++++++++++++++++++++++ vrobbler/apps/scrobbles/views.py | 16 ++++++++++------ vrobbler/apps/sports/thesportsdb.py | 6 +++++- vrobbler/apps/videogames/models.py | 9 +++++++-- vrobbler/apps/videogames/urls.py | 14 ++++++++++++++ vrobbler/apps/videogames/views.py | 12 ++++++++++++ vrobbler/urls.py | 2 ++ 7 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 vrobbler/apps/videogames/urls.py create mode 100644 vrobbler/apps/videogames/views.py diff --git a/vrobbler/apps/scrobbles/scrobblers.py b/vrobbler/apps/scrobbles/scrobblers.py index c935306..cf556ce 100644 --- a/vrobbler/apps/scrobbles/scrobblers.py +++ b/vrobbler/apps/scrobbles/scrobblers.py @@ -15,6 +15,7 @@ from scrobbles.models import Scrobble from scrobbles.utils import convert_to_seconds, parse_mopidy_uri from sports.models import SportEvent from videos.models import Video +from videogames.models import VideoGame logger = logging.getLogger(__name__) @@ -200,3 +201,24 @@ def manual_scrobble_event(data_dict: dict, user_id: Optional[int]): scrobble_dict = build_scrobble_dict(data_dict, user_id) return Scrobble.create_or_update(event, user_id, scrobble_dict) + + +def manual_scrobble_video_game(data_dict: dict, user_id: Optional[int]): + game = VideoGame.find_or_create(data_dict) + + last_scrobble = Scrobble.objects.filter( + video_game=game, user_id=user_id, played_to_completion=True + ).last() + + playback_position = 0 + if last_scrobble and not last_scrobble.playback_position: + playback_position = last_scrobble.playback_position + (30 * 60) + scrobble_dict = { + "user_id": user_id, + "timestamp": timezone.now(), + "playback_position_ticks": playback_position * 1000, + "playback_position": playback_position, + "source": "Vrobbler", + } + + return Scrobble.create_or_update(game, user_id, scrobble_dict) diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index 8123278..9a0660c 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -46,6 +46,7 @@ from scrobbles.scrobblers import ( jellyfin_scrobble_video, manual_scrobble_event, manual_scrobble_video, + manual_scrobble_video_game, mopidy_scrobble_podcast, mopidy_scrobble_track, ) @@ -56,6 +57,7 @@ from scrobbles.tasks import ( ) from sports.thesportsdb import lookup_event_from_thesportsdb from videos.imdb import lookup_video_from_imdb +from videogames.howlongtobeat import lookup_game_from_hltb logger = logging.getLogger(__name__) @@ -180,20 +182,22 @@ class ManualScrobbleView(FormView): item_id = form.cleaned_data.get("item_id") data_dict = None if "tt" in item_id: - data_dict = lookup_video_from_imdb( - form.cleaned_data.get("item_id") - ) + data_dict = lookup_video_from_imdb(item_id) if data_dict: manual_scrobble_video(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") - ) + data_dict = lookup_event_from_thesportsdb(item_id) if data_dict: manual_scrobble_event(data_dict, self.request.user.id) + if not data_dict: + logger.debug(f"Looking for video game with ID {item_id}") + data_dict = lookup_game_from_hltb(item_id) + if data_dict: + manual_scrobble_video_game(data_dict, self.request.user.id) + return HttpResponseRedirect(reverse("vrobbler-home")) diff --git a/vrobbler/apps/sports/thesportsdb.py b/vrobbler/apps/sports/thesportsdb.py index 65b9bb8..7179cbd 100644 --- a/vrobbler/apps/sports/thesportsdb.py +++ b/vrobbler/apps/sports/thesportsdb.py @@ -14,7 +14,11 @@ client = TheSportsDbClient(api_key=API_KEY) def lookup_event_from_thesportsdb(event_id: str) -> dict: - event = client.lookup_event(event_id)["events"][0] + try: + event = client.lookup_event(event_id)["events"][0] + except TypeError: + return {} + if not event or type(event) != dict: return {} league = {} # client.lookup_league(league_id=event.get('idLeague')) diff --git a/vrobbler/apps/videogames/models.py b/vrobbler/apps/videogames/models.py index e8c94d2..c3bfd81 100644 --- a/vrobbler/apps/videogames/models.py +++ b/vrobbler/apps/videogames/models.py @@ -7,8 +7,7 @@ from django.db import models from django.urls import reverse from django_extensions.db.models import TimeStampedModel from scrobbles.mixins import ScrobblableMixin - -from vrobbler.apps.scrobbles.utils import get_scrobbles_for_media +from scrobbles.utils import get_scrobbles_for_media logger = logging.getLogger(__name__) BNULL = {"blank": True, "null": True} @@ -132,3 +131,9 @@ class VideoGame(ScrobblableMixin): self.run_time_ticks = self.main_story_time * 1000 # miliseconds self.run_time = self.main_story_time self.save(update_fields=["run_time_ticks", "run_time"]) + + @classmethod + def find_or_create(cls, data_dict: dict) -> "Game": + from videogames.utils import get_or_create_videogame + + return get_or_create_videogame(data_dict.get("hltb_id")) diff --git a/vrobbler/apps/videogames/urls.py b/vrobbler/apps/videogames/urls.py new file mode 100644 index 0000000..c890467 --- /dev/null +++ b/vrobbler/apps/videogames/urls.py @@ -0,0 +1,14 @@ +from django.urls import path +from videogames import views + +app_name = "videogames" + + +urlpatterns = [ + path("game/", views.VideoGameListView.as_view(), name="videogame_list"), + path( + "game//", + views.VideoGameDetailView.as_view(), + name="videogame_detail", + ), +] diff --git a/vrobbler/apps/videogames/views.py b/vrobbler/apps/videogames/views.py new file mode 100644 index 0000000..a1536dd --- /dev/null +++ b/vrobbler/apps/videogames/views.py @@ -0,0 +1,12 @@ +from django.views import generic +from videogames.models import VideoGame + + +class VideoGameListView(generic.ListView): + model = VideoGame + paginate_by = 20 + + +class VideoGameDetailView(generic.DetailView): + model = VideoGame + slug_field = "uuid" diff --git a/vrobbler/urls.py b/vrobbler/urls.py index bce2792..b7e7cbd 100644 --- a/vrobbler/urls.py +++ b/vrobbler/urls.py @@ -6,6 +6,7 @@ import vrobbler.apps.scrobbles.views as scrobbles_views from vrobbler.apps.books.api.views import AuthorViewSet, BookViewSet from vrobbler.apps.music import urls as music_urls from vrobbler.apps.sports import urls as sports_urls +from vrobbler.apps.videogames import urls as videogame_urls from vrobbler.apps.music.api.views import ( AlbumViewSet, ArtistViewSet, @@ -58,6 +59,7 @@ urlpatterns = [ path("accounts/", include("allauth.urls")), path("", include(music_urls, namespace="music")), path("", include(video_urls, namespace="videos")), + path("", include(videogame_urls, namespace="videogames")), path("", include(sports_urls, namespace="sports")), path("", include(scrobble_urls, namespace="scrobbles")), path(