[videos] More dedup scripts
All checks were successful
build & deploy / test (push) Successful in 1m47s
build & deploy / deploy (push) Successful in 22s

This commit is contained in:
2026-03-21 18:48:04 -04:00
parent d29708bd59
commit bf17a0eeab
2 changed files with 182 additions and 0 deletions

View File

@ -0,0 +1,84 @@
from django.core.management.base import BaseCommand
from django.db import models
class Command(BaseCommand):
help = "Find TV Series with duplicate imdb_id values and merge videos to the newest series"
def add_arguments(self, parser):
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be done without making changes",
)
parser.add_argument(
"--auto",
action="store_true",
help="Automatically fix duplicates without prompting",
)
def handle(self, *args, **options):
from videos.models import Series
dry_run = options["dry_run"]
auto = options["auto"]
duplicate_imdb_ids = (
Series.objects.filter(imdb_id__isnull=False)
.exclude(imdb_id="")
.values("imdb_id")
.annotate(count=models.Count("id"))
.filter(count__gt=1)
)
if not duplicate_imdb_ids.exists():
self.stdout.write("No duplicate imdb_id values found in Series")
return
self.stdout.write(
f"Found {duplicate_imdb_ids.count()} imdb_ids with duplicates in Series"
)
for dup in duplicate_imdb_ids:
imdb_id = dup["imdb_id"]
series_list = list(
Series.objects.filter(imdb_id=imdb_id).order_by("created")
)
self.stdout.write(f"\nimdb_id: {imdb_id}")
self.stdout.write(f" Found {len(series_list)} series:")
for s in series_list:
video_count = s.video_set.count()
self.stdout.write(
f" id={s.id}, name='{s.name}', created={s.created}, videos={video_count}"
)
keeper = series_list[-1]
duplicates = series_list[:-1]
self.stdout.write(f" Keeping: id={keeper.id} ('{keeper.name}')")
self.stdout.write(f" Merging from: {[d.id for d in duplicates]}")
if dry_run:
self.stdout.write(self.style.WARNING(" [DRY RUN] Would move videos"))
continue
if not auto:
confirm = input(" Move videos from duplicates to keeper? [y/N] ")
if confirm.lower() != "y":
self.stdout.write(" Skipped")
continue
for dup_series in duplicates:
video_count = dup_series.video_set.count()
if video_count > 0:
dup_series.video_set.update(tv_series=keeper)
self.stdout.write(
f" Moved {video_count} videos from id={dup_series.id} to id={keeper.id}"
)
dup_series.delete()
self.stdout.write(f" Deleted series id={dup_series.id}")
self.stdout.write(self.style.SUCCESS("\nDone!"))

View File

@ -0,0 +1,98 @@
from django.core.management.base import BaseCommand
from django.db import models
class Command(BaseCommand):
help = "Find TV Series with duplicate names, merge Videos into the one with 'tt' IMDB id"
def add_arguments(self, parser):
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be done without making changes",
)
parser.add_argument(
"--auto",
action="store_true",
help="Automatically fix duplicates without prompting",
)
def handle(self, *args, **options):
from videos.models import Series
dry_run = options["dry_run"]
auto = options["auto"]
duplicate_names = (
Series.objects.values("name")
.annotate(count=models.Count("id"))
.filter(count__gt=1)
)
if not duplicate_names.exists():
self.stdout.write("No duplicate Series names found")
return
self.stdout.write(f"Found {duplicate_names.count()} names with duplicates")
for dup in duplicate_names:
name = dup["name"]
series_list = list(Series.objects.filter(name=name).order_by("created"))
self.stdout.write(f"\nSeries name: {name}")
self.stdout.write(f" Found {len(series_list)} series:")
for s in series_list:
video_count = s.video_set.count()
self.stdout.write(
f" id={s.id}, imdb_id='{s.imdb_id}', created={s.created}, videos={video_count}"
)
tt_series = None
for s in series_list:
if s.imdb_id and s.imdb_id.startswith("tt"):
tt_series = s
break
if not tt_series:
self.stdout.write(
self.style.ERROR(
f" ERROR: No series with 'tt' IMDB id found, skipping"
)
)
continue
duplicates = [s for s in series_list if s.id != tt_series.id]
self.stdout.write(
f" Keeper (tt): id={tt_series.id} ('{tt_series.imdb_id}')"
)
self.stdout.write(f" Merging from: {[d.id for d in duplicates]}")
if dry_run:
self.stdout.write(self.style.WARNING(" [DRY RUN] Would move videos"))
continue
if not auto:
confirm = input(" Move videos from duplicates to keeper? [y/N] ")
if confirm.lower() != "y":
self.stdout.write(" Skipped")
continue
total_moved = 0
for dup_series in duplicates:
video_count = dup_series.video_set.count()
if video_count > 0:
dup_series.video_set.update(tv_series=tt_series)
self.stdout.write(
f" Moved {video_count} videos from id={dup_series.id} to id={tt_series.id}"
)
total_moved += video_count
dup_series.delete()
self.stdout.write(f" Deleted series id={dup_series.id}")
self.stdout.write(
self.style.SUCCESS(f" Merged {total_moved} videos total")
)
self.stdout.write(self.style.SUCCESS("\nDone!"))