Jelajahi Sumber

[tasks] Allow scrobbling tasks from URLs

Colin Powell 9 bulan lalu
induk
melakukan
c251c5f413

+ 10 - 0
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",
 }
 
 

+ 59 - 7
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})
 

+ 3 - 11
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))

+ 2 - 6
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")