Newer
Older
from django.core.management.base import BaseCommand
Eliot Berriot
committed
from django.db import transaction
Eliot Berriot
committed
from django.db.models import Q
Eliot Berriot
committed
from funkwhale_api.music import models, utils
class Command(BaseCommand):
help = "Run common checks and fix against imported tracks"
Eliot Berriot
committed
def add_arguments(self, parser):
parser.add_argument(
Eliot Berriot
committed
default=False,
Eliot Berriot
committed
)
parser.add_argument(
"--mimetypes",
action="store_true",
dest="mimetypes",
default=True,
help="Check and fix mimetypes",
)
parser.add_argument(
"--audio-data",
action="store_true",
dest="data",
default=False,
help="Check and fix bitrate and duration, can be really slow because it needs to access files",
)
parser.add_argument(
"--size",
action="store_true",
dest="size",
default=False,
help="Check and fix file size, can be really slow because it needs to access files",
)
Eliot Berriot
committed
def handle(self, *args, **options):
if options["dry_run"]:
self.stdout.write("Dry-run on, will not commit anything")
if options["mimetypes"]:
self.fix_mimetypes(**options)
if options["data"]:
self.fix_file_data(**options)
if options["size"]:
self.fix_file_size(**options)
Eliot Berriot
committed
@transaction.atomic
def fix_mimetypes(self, dry_run, **kwargs):
matching = models.Upload.objects.filter(
Q(source__startswith="file://") | Q(source__startswith="upload://")
).exclude(mimetype__startswith="audio/")
Eliot Berriot
committed
self.stdout.write(
"[mimetypes] {} entries found with bad or no mimetype".format(
matching.count()
)
)
Eliot Berriot
committed
for extension, mimetype in utils.EXTENSION_TO_MIMETYPE.items():
qs = matching.filter(source__endswith=".{}".format(extension))
Eliot Berriot
committed
self.stdout.write(
Eliot Berriot
committed
qs.count(), extension, mimetype
Eliot Berriot
committed
if not dry_run:
Eliot Berriot
committed
qs.update(mimetype=mimetype)
Eliot Berriot
committed
def fix_file_data(self, dry_run, **kwargs):
self.stdout.write("Fixing missing bitrate or length...")
Eliot Berriot
committed
total = matching.count()
self.stdout.write(
"[bitrate/length] {} entries found with missing values".format(total)
)
Eliot Berriot
committed
if dry_run:
return
for i, upload in enumerate(matching.only("audio_file")):
Eliot Berriot
committed
self.stdout.write(
"[bitrate/length] {}/{} fixing file #{}".format(i + 1, total, upload.pk)
Eliot Berriot
committed
try:
Eliot Berriot
committed
if audio_file:
data = utils.get_audio_file_data(audio_file)
upload.bitrate = data["bitrate"]
upload.duration = data["length"]
upload.save(update_fields=["duration", "bitrate"])
Eliot Berriot
committed
else:
Eliot Berriot
committed
except Exception as e:
self.stderr.write(
"[bitrate/length] error with file #{}: {}".format(upload.pk, str(e))
Eliot Berriot
committed
)
def fix_file_size(self, dry_run, **kwargs):
matching = models.Upload.objects.filter(size__isnull=True)
Eliot Berriot
committed
total = matching.count()
self.stdout.write("[size] {} entries found with missing values".format(total))
Eliot Berriot
committed
if dry_run:
return
Eliot Berriot
committed
self.stdout.write(
"[size] {}/{} fixing file #{}".format(i + 1, total, upload.pk)
Eliot Berriot
committed
try:
upload.size = upload.get_file_size()
upload.save(update_fields=["size"])
Eliot Berriot
committed
except Exception as e:
self.stderr.write(
"[size] error with file #{}: {}".format(upload.pk, str(e))