"""Run the thumbnailer synchronously and stream progress to the console. python manage.py generate_thumbnails 1 2 # specific projects python manage.py generate_thumbnails --all # every project with a clip python manage.py generate_thumbnails --failed # only failed/stuck ones Unlike the upload path (which spawns a daemon thread and logs), this runs in the foreground so you can watch each ffmpeg pass and the final status without tailing app logs. """ from django.core.management.base import BaseCommand, CommandError from scenes.models import Project from scenes.thumbnails import generate_project_thumbnails class Command(BaseCommand): help = "Generate thumbnails for projects, streaming progress to stdout." def add_arguments(self, parser): parser.add_argument("project_ids", nargs="*", type=int, help="Project ids to (re)generate.") parser.add_argument("--all", action="store_true", help="Generate for every project that has a clip.") parser.add_argument("--failed", action="store_true", help="Generate for projects whose status is failed/running/pending.") def handle(self, *args, **opts): ids = list(opts["project_ids"]) if opts["all"]: ids += list(Project.objects.exclude(clip="").values_list("pk", flat=True)) if opts["failed"]: ids += list(Project.objects .filter(thumbnail_status__in=["failed", "running", "pending"]) .values_list("pk", flat=True)) ids = sorted(set(ids)) if not ids: raise CommandError("no projects selected (pass ids, --all, or --failed)") for pk in ids: self.stdout.write(self.style.MIGRATE_HEADING(f"project {pk}")) generate_project_thumbnails(pk, log=lambda msg: self.stdout.write(f" {msg}")) # report the resulting state so a sweep ends with a clear summary self.stdout.write("") for project in Project.objects.filter(pk__in=ids).order_by("pk"): line = f"project {project.pk} [{project.thumbnail_status}] {project.name}" style = (self.style.SUCCESS if project.thumbnail_status == "ready" else self.style.ERROR if project.thumbnail_status == "failed" else self.style.WARNING) self.stdout.write(style(line)) if project.thumbnail_error: self.stdout.write(f" error: {project.thumbnail_error[:500]}")