Skip to content
Snippets Groups Projects
fix_track_files.py 3.82 KiB
Newer Older
  • Learn to ignore specific revisions
  • import cacheops
    import os
    
    from django.db import transaction
    
    from django.conf import settings
    from django.core.management.base import BaseCommand, CommandError
    
    from funkwhale_api.music import models, utils
    
    
    class Command(BaseCommand):
        help = 'Run common checks and fix against imported tracks'
    
        def add_arguments(self, parser):
            parser.add_argument(
                '--dry-run',
                action='store_true',
                dest='dry_run',
                default=False,
                help='Do not execute anything'
            )
    
        def handle(self, *args, **options):
            if options['dry_run']:
                self.stdout.write('Dry-run on, will not commit anything')
            self.fix_mimetypes(**options)
    
            self.fix_file_data(**options)
            self.fix_file_size(**options)
    
            cacheops.invalidate_model(models.TrackFile)
    
        @transaction.atomic
        def fix_mimetypes(self, dry_run, **kwargs):
            self.stdout.write('Fixing missing mimetypes...')
            matching = models.TrackFile.objects.filter(
    
                source__startswith='file://').exclude(mimetype__startswith='audio/')
    
                '[mimetypes] {} entries found with bad or no mimetype'.format(
    
                    matching.count()))
            for extension, mimetype in utils.EXTENSION_TO_MIMETYPE.items():
                qs = matching.filter(source__endswith='.{}'.format(extension))
                self.stdout.write(
                    '[mimetypes] setting {} {} files to {}'.format(
                        qs.count(), extension, mimetype
                    ))
                if not dry_run:
                    self.stdout.write('[mimetypes] commiting...')
                    qs.update(mimetype=mimetype)
    
    
        def fix_file_data(self, dry_run, **kwargs):
            self.stdout.write('Fixing missing bitrate or length...')
            matching = models.TrackFile.objects.filter(
                Q(bitrate__isnull=True) | Q(duration__isnull=True))
            total = matching.count()
            self.stdout.write(
                '[bitrate/length] {} entries found with missing values'.format(
                    total))
            if dry_run:
                return
            for i, tf in enumerate(matching.only('audio_file')):
                self.stdout.write(
                    '[bitrate/length] {}/{} fixing file #{}'.format(
                        i+1, total, tf.pk
                    ))
    
                try:
                    audio_file = tf.get_audio_file()
                    if audio_file:
                        with audio_file as f:
                            data = utils.get_audio_file_data(audio_file)
                        tf.bitrate = data['bitrate']
                        tf.duration = data['length']
                        tf.save(update_fields=['duration', 'bitrate'])
                    else:
                        self.stderr.write('[bitrate/length] no file found')
                except Exception as e:
                    self.stderr.write(
                        '[bitrate/length] error with file #{}: {}'.format(
                            tf.pk, str(e)
                        )
                    )
    
        def fix_file_size(self, dry_run, **kwargs):
            self.stdout.write('Fixing missing size...')
            matching = models.TrackFile.objects.filter(size__isnull=True)
            total = matching.count()
            self.stdout.write(
                '[size] {} entries found with missing values'.format(total))
            if dry_run:
                return
            for i, tf in enumerate(matching.only('size')):
                self.stdout.write(
                    '[size] {}/{} fixing file #{}'.format(
                        i+1, total, tf.pk
                    ))
    
                try:
                    tf.size = tf.get_file_size()
                    tf.save(update_fields=['size'])
                except Exception as e:
                    self.stderr.write(
                        '[size] error with file #{}: {}'.format(
                            tf.pk, str(e)
                        )
                    )