[tasks] Allow scrobbling tasks from URLs
This commit is contained in:
@ -22,11 +22,20 @@ MEDIA_END_PADDING_SECONDS = {
|
|||||||
"Video": 3600, # 60 min
|
"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 = {
|
SCROBBLE_CONTENT_URLS = {
|
||||||
"-i": "https://www.imdb.com/title/",
|
"-i": "https://www.imdb.com/title/",
|
||||||
"-s": "https://www.thesportsdb.com/event/",
|
"-s": "https://www.thesportsdb.com/event/",
|
||||||
"-g": "https://boardgamegeek.com/boardgame/",
|
"-g": "https://boardgamegeek.com/boardgame/",
|
||||||
"-b": "https://www.amazon.com/",
|
"-b": "https://www.amazon.com/",
|
||||||
|
"-t": task_urls,
|
||||||
}
|
}
|
||||||
|
|
||||||
EXCLUDE_FROM_NOW_PLAYING = ("GeoLocation",)
|
EXCLUDE_FROM_NOW_PLAYING = ("GeoLocation",)
|
||||||
@ -38,6 +47,7 @@ MANUAL_SCROBBLE_FNS = {
|
|||||||
"-i": "manual_scrobble_video",
|
"-i": "manual_scrobble_video",
|
||||||
"-g": "manual_scrobble_board_game",
|
"-g": "manual_scrobble_board_game",
|
||||||
"-w": "manual_scrobble_webpage",
|
"-w": "manual_scrobble_webpage",
|
||||||
|
"-t": "manual_scrobble_task",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,12 @@ from sports.thesportsdb import lookup_event_from_thesportsdb
|
|||||||
from videogames.howlongtobeat import lookup_game_from_hltb
|
from videogames.howlongtobeat import lookup_game_from_hltb
|
||||||
from videogames.models import VideoGame
|
from videogames.models import VideoGame
|
||||||
from videos.models import Video
|
from videos.models import Video
|
||||||
from vrobbler.apps.scrobbles.constants import (
|
from scrobbles.constants import (
|
||||||
MANUAL_SCROBBLE_FNS,
|
MANUAL_SCROBBLE_FNS,
|
||||||
SCROBBLE_CONTENT_URLS,
|
SCROBBLE_CONTENT_URLS,
|
||||||
|
TASK_SOURCE_URL_PATTERNS,
|
||||||
)
|
)
|
||||||
|
from tasks.models import Task
|
||||||
from webpages.models import WebPage
|
from webpages.models import WebPage
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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:
|
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 = ""
|
content_key = ""
|
||||||
|
try:
|
||||||
|
domain = url.split("//")[-1].split("/")[0]
|
||||||
|
except IndexError:
|
||||||
|
domain = None
|
||||||
|
|
||||||
for key, content_url in SCROBBLE_CONTENT_URLS.items():
|
for key, content_url in SCROBBLE_CONTENT_URLS.items():
|
||||||
if content_url in url:
|
if domain in content_url:
|
||||||
content_key = key
|
content_key = key
|
||||||
|
|
||||||
|
item_id = None
|
||||||
if not content_key:
|
if not content_key:
|
||||||
return
|
content_key = "-w"
|
||||||
|
item_id = url
|
||||||
|
|
||||||
try:
|
if not item_id:
|
||||||
item_id = re.findall("\d+", url)[0]
|
try:
|
||||||
except IndexError:
|
item_id = re.findall("\d+", url)[0]
|
||||||
item_id = None
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if content_key == "-t":
|
||||||
|
item_id = url
|
||||||
|
|
||||||
scrobble_fn = MANUAL_SCROBBLE_FNS[content_key]
|
scrobble_fn = MANUAL_SCROBBLE_FNS[content_key]
|
||||||
return eval(scrobble_fn)(item_id, user_id)
|
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):
|
def manual_scrobble_webpage(url: str, user_id: int):
|
||||||
webpage = WebPage.find_or_create({"url": url})
|
webpage = WebPage.find_or_create({"url": url})
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ from scrobbles.models import (
|
|||||||
RetroarchImport,
|
RetroarchImport,
|
||||||
Scrobble,
|
Scrobble,
|
||||||
)
|
)
|
||||||
from scrobbles.scrobblers import *
|
from scrobbles.scrobblers import manual_scrobble_from_url
|
||||||
from scrobbles.tasks import (
|
from scrobbles.tasks import (
|
||||||
process_koreader_import,
|
process_koreader_import,
|
||||||
process_lastfm_import,
|
process_lastfm_import,
|
||||||
@ -97,16 +97,8 @@ class RecentScrobbleList(ListView):
|
|||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
if user.is_authenticated:
|
if user.is_authenticated:
|
||||||
if scrobble_url := self.request.GET.get("scrobble_url"):
|
if scrobble_url := self.request.GET.get("scrobble_url", ""):
|
||||||
for content_url in SCROBBLE_CONTENT_URLS.values():
|
scrobble = manual_scrobble_from_url(
|
||||||
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(
|
|
||||||
scrobble_url, self.request.user.id
|
scrobble_url, self.request.user.id
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(scrobble.redirect_url(user.id))
|
return HttpResponseRedirect(scrobble.redirect_url(user.id))
|
||||||
|
|||||||
@ -7,14 +7,10 @@ from django.db import models
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from scrobbles.dataclasses import LongPlayLogData
|
from scrobbles.dataclasses import LongPlayLogData
|
||||||
from scrobbles.mixins import LongPlayScrobblableMixin
|
from scrobbles.mixins import LongPlayScrobblableMixin
|
||||||
|
from scrobbles.constants import TASK_SOURCE_URL_PATTERNS
|
||||||
|
|
||||||
BNULL = {"blank": True, "null": True}
|
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
|
@dataclass
|
||||||
class TaskLogData(LongPlayLogData):
|
class TaskLogData(LongPlayLogData):
|
||||||
@ -66,7 +62,7 @@ class Task(LongPlayScrobblableMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def find_or_create(cls, title: str) -> "Task":
|
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):
|
def scrobbles(self, user_id):
|
||||||
Scrobble = apps.get_model("scrobbles", "Scrobble")
|
Scrobble = apps.get_model("scrobbles", "Scrobble")
|
||||||
|
|||||||
Reference in New Issue
Block a user