sessions / fb775f2f585a81dcd51a358fffe4eace33f5e227

/home/powellc/src/code.unbl.ink/secstate/vrobbler

This commit has no recorded session.

diff

show whitespace

commit fb775f2f585a81dcd51a358fffe4eace33f5e227Author: Colin Powell <colin@unbl.ink>Date:   Wed Jun 17 11:05:38 2026 -0400    [videos] Add cmd to cleanup series metadatadiff --git a/PROJECT.org b/PROJECT.orgindex 179e0da..222982a 100644--- a/PROJECT.org+++ b/PROJECT.org@@ -88,7 +88,7 @@ fetching and simple saving. *** Metadata sources **** Scraper -* Backlog [3/23] :vrobbler:project:personal:+* Backlog [4/24] :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@@ -590,6 +590,10 @@ We should rename `email_scrobble_board_game` to reflect the fact that it's just a helper method to create board game scrobbles given a json blob. It's independent of the email flow it was originally creatdd for +** DONE [#B] Add script to clean up TV series metadata :videos:metadata:+:PROPERTIES:+:ID:       a468b328-59d9-f84b-9ddb-087216783453+:END: ** DONE [#A] Update youtube video detail pages with links to channel :videos:templates: :PROPERTIES: :ID:       8b87cb42-09e5-a3f5-136f-182f967fa81fdiff --git a/vrobbler/apps/videos/management/commands/cleanup_series_metadata.py b/vrobbler/apps/videos/management/commands/cleanup_series_metadata.pynew file mode 100644index 0000000..94bb7eb--- /dev/null+++ b/vrobbler/apps/videos/management/commands/cleanup_series_metadata.py@@ -0,0 +1,68 @@+import logging++from django.core.management.base import BaseCommand+from django.db import transaction++logger = logging.getLogger(__name__)+++class Command(BaseCommand):+    help = "Enrich TV series metadata from TMDB/OMDB APIs"++    def add_arguments(self, parser):+        parser.add_argument(+            "--force",+            action="store_true",+            help="Overwrite existing cover image",+        )+        parser.add_argument(+            "--dry-run",+            action="store_true",+            help="Show what would be done without making changes",+        )+        parser.add_argument(+            "--imdb-id",+            type=str,+            help="Only process series with this imdb_id",+        )++    def handle(self, *args, **options):+        from videos.models import Series++        force = options["force"]+        dry_run = options["dry_run"]+        imdb_id = options["imdb_id"]++        qs = Series.objects.all()+        if imdb_id:+            qs = qs.filter(imdb_id=imdb_id)++        total = qs.count()+        self.stdout.write(f"Processing {total} series")++        if dry_run:+            for series in qs.iterator():+                self.stdout.write(+                    f"  [DRY RUN] Would fix {series.name} (imdb_id={series.imdb_id})"+                )+            return++        updated = 0+        errors = 0+        for series in qs.iterator():+            try:+                with transaction.atomic():+                    series.fix_metadata(force_update=force)+                updated += 1+                self.stdout.write(f"  [{updated}/{total}] {series.name}")+            except Exception as e:+                errors += 1+                self.stdout.write(+                    self.style.ERROR(+                        f"  Error updating series {series.name} (imdb_id={series.imdb_id}): {e}"+                    )+                )++        self.stdout.write(+            self.style.SUCCESS(f"\nDone! {updated} series updated, {errors} errors")+        )diff --git a/vrobbler/apps/videos/models.py b/vrobbler/apps/videos/models.pyindex c64c87a..be82333 100644--- a/vrobbler/apps/videos/models.py+++ b/vrobbler/apps/videos/models.py@@ -330,16 +330,18 @@ class Series(TimeStampedModel):             logger.warning(f"No imdb data for {self}")             return -        cover_url = imdb_dict.get("cover_url")--        if (not self.cover_image or force_update) and cover_url:-            r = requests.get(cover_url)+        if video_metadata.cover_url and (not self.cover_image or force_update):+            r = requests.get(video_metadata.cover_url)             if r.status_code == 200:                 fname = f"{self.name}_{self.uuid}.jpg"                 self.cover_image.save(fname, ContentFile(r.content), save=True) -        if genres := imdb_dict.get("genres"):-            self.genre.add(*genres)+        self.plot = video_metadata.plot+        self.imdb_rating = video_metadata.imdb_rating+        self.save()++        if video_metadata.genres:+            self.genre.add(*video_metadata.genres)      @classmethod     def find_or_create(cls, imdb_id: str, overwrite: bool = True):