funkwhale/api/funkwhale_api/music/management/commands/check_inplace_files.py

76 wiersze
2.5 KiB
Python

import os
from argparse import RawTextHelpFormatter
from django.core.management.base import BaseCommand
from django.db import transaction
from funkwhale_api.music import models
def progress(buffer, count, total, status=""):
bar_len = 60
filled_len = int(round(bar_len * count / float(total)))
bar = "=" * filled_len + "-" * (bar_len - filled_len)
buffer.write(f"[{bar}] {count}/{total} ...{status}\r")
buffer.flush()
class Command(BaseCommand):
help = """
Loop through all in-place imported files in the database, and verify
that the corresponding files are present on the filesystem. If some files are not
found and --no-dry-run is specified, the corresponding database objects will be deleted.
"""
def create_parser(self, *args, **kwargs):
parser = super().create_parser(*args, **kwargs)
parser.formatter_class = RawTextHelpFormatter
return parser
def add_arguments(self, parser):
parser.add_argument(
"--no-dry-run",
action="store_false",
dest="dry_run",
default=True,
help="Disable dry run mode and apply pruning for real on the database",
)
@transaction.atomic
def handle(self, *args, **options):
candidates = models.Upload.objects.filter(source__startswith="file://")
candidates = candidates.filter(audio_file__in=["", None])
total = candidates.count()
self.stdout.write(f"Checking {total} in-place imported files…")
missing = []
for i, row in enumerate(candidates.values("id", "source").iterator()):
path = row["source"].replace("file://", "")
progress(self.stdout, i + 1, total)
if not os.path.exists(path):
missing.append((path, row["id"]))
if missing:
for path, _ in missing:
self.stdout.write(f" {path}")
self.stdout.write(
"The previous {} paths are referenced in database, but not found on disk!".format(
len(missing)
)
)
else:
self.stdout.write("All in-place imports have a matching on-disk file")
return
to_delete = candidates.filter(pk__in=[id for _, id in missing])
if options["dry_run"]:
self.stdout.write(
"Nothing was deleted, rerun this command with --no-dry-run to apply the changes"
)
else:
self.stdout.write(f"Deleting {to_delete.count()} uploads…")
to_delete.delete()