diff --git a/vrobbler/apps/scrobbles/constants.py b/vrobbler/apps/scrobbles/constants.py index 1c9ce49..ac6e6ac 100644 --- a/vrobbler/apps/scrobbles/constants.py +++ b/vrobbler/apps/scrobbles/constants.py @@ -22,11 +22,20 @@ MEDIA_END_PADDING_SECONDS = { "Video": 3600, # 60 min } +TASK_SOURCE_URL_PATTERNS = [ + ("https://app.shortcut.com/sure/story/{id}", "Shortcut"), + ("https://app.todoist.com/app/task/{id}", "Todoist"), +] + +for task_pattern in TASK_SOURCE_URL_PATTERNS: + task_urls = ", ".join([t[0] for t in TASK_SOURCE_URL_PATTERNS]) + SCROBBLE_CONTENT_URLS = { "-i": "https://www.imdb.com/title/", "-s": "https://www.thesportsdb.com/event/", "-g": "https://boardgamegeek.com/boardgame/", "-b": "https://www.amazon.com/", + "-t": task_urls, } EXCLUDE_FROM_NOW_PLAYING = ("GeoLocation",) @@ -38,6 +47,7 @@ MANUAL_SCROBBLE_FNS = { "-i": "manual_scrobble_video", "-g": "manual_scrobble_board_game", "-w": "manual_scrobble_webpage", + "-t": "manual_scrobble_task", } diff --git a/vrobbler/apps/scrobbles/scrobblers.py b/vrobbler/apps/scrobbles/scrobblers.py index 98e1d0f..f7a75c6 100644 --- a/vrobbler/apps/scrobbles/scrobblers.py +++ b/vrobbler/apps/scrobbles/scrobblers.py @@ -22,10 +22,12 @@ from sports.thesportsdb import lookup_event_from_thesportsdb from videogames.howlongtobeat import lookup_game_from_hltb from videogames.models import VideoGame from videos.models import Video -from vrobbler.apps.scrobbles.constants import ( +from scrobbles.constants import ( MANUAL_SCROBBLE_FNS, SCROBBLE_CONTENT_URLS, + TASK_SOURCE_URL_PATTERNS, ) +from tasks.models import Task from webpages.models import WebPage logger = logging.getLogger(__name__) @@ -273,23 +275,73 @@ def manual_scrobble_board_game(bggeek_id: str, user_id: int): def manual_scrobble_from_url(url: str, user_id: int) -> Scrobble: + """We have scrobblable media URLs, and then any other webpages that + we want to scrobble as a media type in and of itself. This checks whether + we know about the content type, and routes it to the appropriate media + scrobbler. Otherwise, return nothing.""" content_key = "" + try: + domain = url.split("//")[-1].split("/")[0] + except IndexError: + domain = None + for key, content_url in SCROBBLE_CONTENT_URLS.items(): - if content_url in url: + if domain in content_url: content_key = key + item_id = None if not content_key: - return + content_key = "-w" + item_id = url - try: - item_id = re.findall("\d+", url)[0] - except IndexError: - item_id = None + if not item_id: + try: + item_id = re.findall("\d+", url)[0] + except IndexError: + pass + + if content_key == "-t": + item_id = url scrobble_fn = MANUAL_SCROBBLE_FNS[content_key] return eval(scrobble_fn)(item_id, user_id) +def manual_scrobble_task(url: str, user_id: int): + source_id = re.findall("\d+", url)[0] + + if "shortcut" in url: + source = "Shortcut" + title = "Generic Shortcut task" + description = url.split("/")[-1] + if "todoist" in url: + source = "Todoist" + title = "Generic Todoist task" + description = url.split("-")[-1] + + task = Task.find_or_create(title) + + scrobble_dict = { + "user_id": user_id, + "timestamp": timezone.now(), + "playback_position_seconds": 0, + "source": source, + "log": {"description": description, "source_id": source_id}, + } + logger.info( + "[webhook] webpage scrobble request received", + extra={ + "task_id": task.id, + "user_id": user_id, + "scrobble_dict": scrobble_dict, + "media_type": Scrobble.MediaType.WEBPAGE, + }, + ) + + scrobble = Scrobble.create_or_update(task, user_id, scrobble_dict) + return scrobble + + def manual_scrobble_webpage(url: str, user_id: int): webpage = WebPage.find_or_create({"url": url}) diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index 3647ed8..e443556 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -44,7 +44,7 @@ from scrobbles.models import ( RetroarchImport, Scrobble, ) -from scrobbles.scrobblers import * +from scrobbles.scrobblers import manual_scrobble_from_url from scrobbles.tasks import ( process_koreader_import, process_lastfm_import, @@ -97,16 +97,8 @@ class RecentScrobbleList(ListView): def get(self, *args, **kwargs): user = self.request.user if user.is_authenticated: - if scrobble_url := self.request.GET.get("scrobble_url"): - for content_url in SCROBBLE_CONTENT_URLS.values(): - if content_url in scrobble_url: - scrobble = manual_scrobble_from_url( - scrobble_url, self.request.user.id - ) - return HttpResponseRedirect( - scrobble.redirect_url(user.id) - ) - scrobble = manual_scrobble_webpage( + if scrobble_url := self.request.GET.get("scrobble_url", ""): + scrobble = manual_scrobble_from_url( scrobble_url, self.request.user.id ) return HttpResponseRedirect(scrobble.redirect_url(user.id)) diff --git a/vrobbler/apps/tasks/models.py b/vrobbler/apps/tasks/models.py index 53ecaa1..12c6e1a 100644 --- a/vrobbler/apps/tasks/models.py +++ b/vrobbler/apps/tasks/models.py @@ -7,14 +7,10 @@ from django.db import models from django.urls import reverse from scrobbles.dataclasses import LongPlayLogData from scrobbles.mixins import LongPlayScrobblableMixin +from scrobbles.constants import TASK_SOURCE_URL_PATTERNS BNULL = {"blank": True, "null": True} -TASK_SOURCE_URL_PATTERNS = [ - ("https://app.shortcut.com/sure/story/{id}", "Shortcut"), - ("https://app.todoist.com/app/task/{id}", "Todoist"), -] - @dataclass class TaskLogData(LongPlayLogData): @@ -66,7 +62,7 @@ class Task(LongPlayScrobblableMixin): @classmethod def find_or_create(cls, title: str) -> "Task": - return cls.objects.filter(title=title).first() + return cls.objects.get_or_create(title=title)[0] def scrobbles(self, user_id): Scrobble = apps.get_model("scrobbles", "Scrobble")