from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError from django.db.models import Q from apps.library import e621, matching from apps.library.models import MatchTask, MediaItem class Command(BaseCommand): help = ( "Match library items against e621 by MD5 and refresh matched metadata " "(also detects deleted posts). Uses a user's stored e621 credentials." ) def add_arguments(self, parser): parser.add_argument( "--user", help="Username whose e621 credentials to use " "(defaults to the first staff account with credentials).", ) parser.add_argument( "--scope", choices=[MatchTask.SCOPE_MISSING, MatchTask.SCOPE_ALL], default=MatchTask.SCOPE_MISSING, help="'missing' checks unchecked items only; 'all' also refreshes " "already matched items (default: missing).", ) def handle(self, *args, **options): User = get_user_model() username = options.get("user") if username: user = User.objects.filter(username=username).first() if user is None: raise CommandError(f"No such user: {username}") else: user = ( User.objects.filter( Q(is_superuser=True) | Q(is_staff=True) | Q(role=User.ROLE_STAFF), e621_api_key__gt="", e621_username__gt="", ) .order_by("id") .first() ) if not e621.credentials_configured(user): raise CommandError( "No e621 credentials found. Pass --user or configure them in Account." ) queryset = matching.scope_queryset(options["scope"]) total = queryset.count() counters = {"matched": 0, "not_found": 0, "deleted": 0} for index, item_id in enumerate(queryset.values_list("id", flat=True), start=1): item = MediaItem.objects.filter(id=item_id).first() if item is None: continue try: status = matching.check_item(item, user) except e621.E621Error as exc: raise CommandError(f"Aborted after {index - 1}/{total}: {exc}") counters[status] = counters.get(status, 0) + 1 self.stdout.write( f"[{index}/{total}] J-{item_id}: {status}", ending="\r" ) self.stdout.write( self.style.SUCCESS( "\nDone: " f"{counters['matched']} matched, {counters['not_found']} not found, " f"{counters['deleted']} deleted (scope: {options['scope']})." ) )