Skip to content
Snippets Groups Projects
fix_uploads.py 4.41 KiB
Newer Older
Eliot Berriot's avatar
Eliot Berriot committed
from django.core.management.base import BaseCommand

from funkwhale_api.music import models, utils


class Command(BaseCommand):
Eliot Berriot's avatar
Eliot Berriot committed
    help = "Run common checks and fix against imported tracks"

    def add_arguments(self, parser):
        parser.add_argument(
Eliot Berriot's avatar
Eliot Berriot committed
            "--dry-run",
            action="store_true",
            dest="dry_run",
Eliot Berriot's avatar
Eliot Berriot committed
            help="Do not execute anything",
        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's avatar
Eliot Berriot committed
        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)

    @transaction.atomic
    def fix_mimetypes(self, dry_run, **kwargs):
Eliot Berriot's avatar
Eliot Berriot committed
        self.stdout.write("Fixing missing mimetypes...")
        matching = models.Upload.objects.filter(
            Q(source__startswith="file://") | Q(source__startswith="upload://")
        ).exclude(mimetype__startswith="audio/")
Eliot Berriot's avatar
Eliot Berriot committed
            "[mimetypes] {} entries found with bad or no mimetype".format(
                matching.count()
            )
        )
        for extension, mimetype in utils.EXTENSION_TO_MIMETYPE.items():
Eliot Berriot's avatar
Eliot Berriot committed
            qs = matching.filter(source__endswith=".{}".format(extension))
Eliot Berriot's avatar
Eliot Berriot committed
                "[mimetypes] setting {} {} files to {}".format(
Eliot Berriot's avatar
Eliot Berriot committed
                )
            )
Eliot Berriot's avatar
Eliot Berriot committed
                self.stdout.write("[mimetypes] commiting...")

    def fix_file_data(self, dry_run, **kwargs):
Eliot Berriot's avatar
Eliot Berriot committed
        self.stdout.write("Fixing missing bitrate or length...")
Eliot Berriot's avatar
Eliot Berriot committed
        matching = models.Upload.objects.filter(
Eliot Berriot's avatar
Eliot Berriot committed
            Q(bitrate__isnull=True) | Q(duration__isnull=True)
        )
        total = matching.count()
        self.stdout.write(
Eliot Berriot's avatar
Eliot Berriot committed
            "[bitrate/length] {} entries found with missing values".format(total)
        )
Eliot Berriot's avatar
Eliot Berriot committed
        for i, upload in enumerate(matching.only("audio_file")):
Eliot Berriot's avatar
Eliot Berriot committed
                "[bitrate/length] {}/{} fixing file #{}".format(i + 1, total, upload.pk)
Eliot Berriot's avatar
Eliot Berriot committed
            )
Eliot Berriot's avatar
Eliot Berriot committed
                audio_file = upload.get_audio_file()
                    data = utils.get_audio_file_data(audio_file)
Eliot Berriot's avatar
Eliot Berriot committed
                    upload.bitrate = data["bitrate"]
                    upload.duration = data["length"]
                    upload.save(update_fields=["duration", "bitrate"])
Eliot Berriot's avatar
Eliot Berriot committed
                    self.stderr.write("[bitrate/length] no file found")
Eliot Berriot's avatar
Eliot Berriot committed
                    "[bitrate/length] error with file #{}: {}".format(upload.pk, str(e))
Eliot Berriot's avatar
Eliot Berriot committed
        self.stdout.write("Fixing missing size...")
Eliot Berriot's avatar
Eliot Berriot committed
        matching = models.Upload.objects.filter(size__isnull=True)
Eliot Berriot's avatar
Eliot Berriot committed
        self.stdout.write("[size] {} entries found with missing values".format(total))
Eliot Berriot's avatar
Eliot Berriot committed
        for i, upload in enumerate(matching.only("size")):
Eliot Berriot's avatar
Eliot Berriot committed
                "[size] {}/{} fixing file #{}".format(i + 1, total, upload.pk)
Eliot Berriot's avatar
Eliot Berriot committed
            )
Eliot Berriot's avatar
Eliot Berriot committed
                upload.size = upload.get_file_size()
                upload.save(update_fields=["size"])
Eliot Berriot's avatar
Eliot Berriot committed
                    "[size] error with file #{}: {}".format(upload.pk, str(e))