diff --git a/AGENTS.md b/AGENTS.md index 32d31a9..c71e5ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,8 @@ ro class method should call the utility function. Be sure to check pyproject.toml for project defaults. Specifically for black and isort expectations. +Imports in python files should always be top level if possible. + All tasks live in the PROJECT.org file and include an org ID that is a uuid to make them unique. In local development, environment variables for various sensitive values live in a .envrc file diff --git a/PROJECT.org b/PROJECT.org index 2e19c50..95989ef 100644 --- a/PROJECT.org +++ b/PROJECT.org @@ -88,7 +88,7 @@ fetching and simple saving. *** Metadata sources **** Scraper -* Backlog [0/20] :vrobbler:project:personal: +* Backlog [1/21] :vrobbler:project:personal: ** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :bug:music:scrobbles: :PROPERTIES: :ID: 702462cf-d54b-48c6-8a7c-78b8de751deb @@ -594,6 +594,17 @@ named constants for maintainability. - ~vrobbler/apps/webpages/models.py~ (line 290) -- ="url"= - ~vrobbler/apps/scrobbles/importers/tsv.py~ (line 55) -- ="S"= completion status +** DONE [#B] Make ArchiveBox push asynchronous :archivebox:async: +:PROPERTIES: +:ID: 17c116a7-5952-db37-e56c-2987c2fc456b +:END: +*** Description + +=push_to_archivebox()= runs synchronously during the request. Should be moved to a +Celery task or similar background worker. + +File: ~vrobbler/apps/webpages/models.py~ (line 133) + * Version 52.2 [1/1] ** DONE [#A] Fix bug in recomputing long play seconds taking forever :bug:longplay:commands: :PROPERTIES: diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index b213515..bc22ef0 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -952,27 +952,6 @@ class Scrobble(TimeStampedModel): self.share_token_version += 1 self.save(update_fields=["share_token_version"]) - def push_to_archivebox(self): - pushable_media = hasattr(self.media_obj, "push_to_archivebox") and callable( - self.media_obj.push_to_archivebox - ) - - if pushable_media and self.user.profile.archivebox_url: - try: - self.media_obj.push_to_archivebox( - url=self.user.profile.archivebox_url, - username=self.user.profile.archivebox_username, - password=self.user.profile.archivebox_password, - ) - except Exception: - logger.info( - "Failed to push URL to archivebox", - extra={ - "archivebox_url": self.user.profile.archivebox_url, - "archivebox_username": self.user.profile.archivebox_username, - }, - ) - @property def logdata(self) -> Optional[logdata.BaseLogData]: if self.media_obj: diff --git a/vrobbler/apps/scrobbles/scrobblers.py b/vrobbler/apps/scrobbles/scrobblers.py index 4758b84..a3b75df 100644 --- a/vrobbler/apps/scrobbles/scrobblers.py +++ b/vrobbler/apps/scrobbles/scrobblers.py @@ -32,6 +32,7 @@ from scrobbles.constants import ( ) from scrobbles.models import Scrobble from scrobbles.notifications import ScrobbleNtfyNotification +from scrobbles.tasks import push_scrobble_to_archivebox from scrobbles.utils import ( convert_to_seconds, extract_domain, @@ -1028,8 +1029,7 @@ def manual_scrobble_webpage( if action == "stop": scrobble.stop(force_finish=True) else: - # possibly async this? - scrobble.push_to_archivebox() + push_scrobble_to_archivebox.delay(scrobble.id) return scrobble diff --git a/vrobbler/apps/scrobbles/tasks.py b/vrobbler/apps/scrobbles/tasks.py index bbc4fe7..5d04bdf 100644 --- a/vrobbler/apps/scrobbles/tasks.py +++ b/vrobbler/apps/scrobbles/tasks.py @@ -252,6 +252,25 @@ def update_charts_for_timestamp(user_id, year, month, day, week): logger.error(f"[charts] Failed to update charts: {e}") +@shared_task +def push_scrobble_to_archivebox(scrobble_id): + from scrobbles.models import Scrobble + + scrobble = Scrobble.objects.filter(id=scrobble_id).first() + if not scrobble: + logger.warning( + "Scrobble %s not found for archivebox push", scrobble_id + ) + return + webpage = scrobble.web_page + if not webpage: + logger.warning( + "Scrobble %s has no web_page for archivebox push", scrobble_id + ) + return + webpage.push_to_archivebox(scrobble.user) + + # ── Crontab replacements ────────────────────────────────────────────────────── diff --git a/vrobbler/apps/webpages/models.py b/vrobbler/apps/webpages/models.py index ab55f1f..3b6a8e8 100644 --- a/vrobbler/apps/webpages/models.py +++ b/vrobbler/apps/webpages/models.py @@ -17,6 +17,7 @@ from htmldate import find_date from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFit from scrobbles.mixins import ScrobblableConstants, ScrobblableMixin +from scrobbles.tasks import push_scrobble_to_archivebox from taggit.managers import TaggableManager logger = logging.getLogger(__name__) @@ -130,8 +131,7 @@ class WebPage(ScrobblableMixin): }, ) scrobble = Scrobble.create_or_update(self, user_id, scrobble_data) - # TODO Possibly make this async? - scrobble.push_to_archivebox() + push_scrobble_to_archivebox.delay(scrobble.id) return scrobble def scrobbles(self, user): @@ -183,7 +183,13 @@ class WebPage(ScrobblableMixin): if save: self.save(update_fields=["date"]) - def push_to_archivebox(self, url: str, username: str, password: str): + def push_to_archivebox(self, user): + profile = user.profile + url = profile.archivebox_url + if not url: + return + username = profile.archivebox_username + password = profile.archivebox_password login_url = requests.compat.urljoin(url, "admin/login/") session = requests.Session() response = session.get(login_url)