Commit 3a520f21 authored by fred's avatar fred

check and set sound file duration at upload time

parent 056d2177
...@@ -6,6 +6,7 @@ import uuid ...@@ -6,6 +6,7 @@ import uuid
from django import forms from django import forms
from django.forms import fields from django.forms import fields
from django.forms import ValidationError
from django.core.files.storage import DefaultStorage from django.core.files.storage import DefaultStorage
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -19,6 +20,7 @@ from taggit.forms import TagWidget ...@@ -19,6 +20,7 @@ from taggit.forms import TagWidget
from .models import (Emission, Episode, Diffusion, Schedule, SoundFile, from .models import (Emission, Episode, Diffusion, Schedule, SoundFile,
NewsItem, Absence, PlaylistElement) NewsItem, Absence, PlaylistElement)
from .utils import get_duration
from .widgets import DateTimeWidget, DateWidget from .widgets import DateTimeWidget, DateWidget
...@@ -240,6 +242,13 @@ class SoundFileForm(forms.ModelForm): ...@@ -240,6 +242,13 @@ class SoundFileForm(forms.ModelForm):
'file': JqueryFileUploadInput(), 'file': JqueryFileUploadInput(),
} }
def clean(self):
super().clean()
if self.cleaned_data.get('file'):
duration = get_duration(self.cleaned_data['file'].file.name)
if not duration:
raise ValidationError(_('Invalid file, could not get duration.'))
class SoundFileEditForm(forms.ModelForm): class SoundFileEditForm(forms.ModelForm):
class Meta: class Meta:
......
...@@ -82,12 +82,8 @@ class Command(BaseCommand): ...@@ -82,12 +82,8 @@ class Command(BaseCommand):
if not soundfile.podcastable: if not soundfile.podcastable:
# get duration using initial file # get duration using initial file
if not soundfile.duration: if not soundfile.duration:
cmd = ['soxi', '-D', soundfile.file.path] soundfile.compute_duration()
try: if soundfile.duration:
soundfile.duration = int(float(subprocess.check_output(cmd)))
except (ValueError, subprocess.CalledProcessError):
pass
else:
soundfile.save() soundfile.save()
continue continue
for format in formats.split(','): for format in formats.split(','):
...@@ -98,14 +94,9 @@ class Command(BaseCommand): ...@@ -98,14 +94,9 @@ class Command(BaseCommand):
if created or reset_metadata: if created or reset_metadata:
self.set_metadata(soundfile, format) self.set_metadata(soundfile, format)
if (force or not soundfile.duration): if (force or not soundfile.duration):
for extension in ('ogg', 'mp3'): soundfile.compute_duration()
soundfile_name = soundfile.get_format_path(extension) if soundfile.duration:
if os.path.exists(soundfile_name): soundfile.save()
cmd = ['soxi', '-D', soundfile_name]
soundfile.duration = int(float(subprocess.check_output(cmd)))
soundfile.save()
break
def create(self, soundfile, format): def create(self, soundfile, format):
file_path = soundfile.get_format_path(format) file_path = soundfile.get_format_path(format)
......
...@@ -17,7 +17,7 @@ from django.dispatch.dispatcher import receiver ...@@ -17,7 +17,7 @@ from django.dispatch.dispatcher import receiver
from ckeditor.fields import RichTextField from ckeditor.fields import RichTextField
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
from .utils import maybe_resize from .utils import maybe_resize, get_duration
LICENSES = ( LICENSES = (
...@@ -496,6 +496,12 @@ class SoundFile(models.Model): ...@@ -496,6 +496,12 @@ class SoundFile(models.Model):
creation_timestamp = models.DateTimeField(auto_now_add=True, null=True) creation_timestamp = models.DateTimeField(auto_now_add=True, null=True)
last_update_timestamp = models.DateTimeField(auto_now=True, null=True) last_update_timestamp = models.DateTimeField(auto_now=True, null=True)
def compute_duration(self):
for path in (self.get_format_path('ogg'), self.get_format_path('mp3'), self.file.path):
self.duration = get_duration(path)
if self.duration:
return
def get_format_filename(self, format): def get_format_filename(self, format):
return '%s_%05d__%s.%s' % ( return '%s_%05d__%s.%s' % (
self.episode.slug, self.episode.slug,
......
from datetime import datetime, timedelta, time from datetime import datetime, timedelta, time
import os import os
import subprocess
from PIL import Image from PIL import Image
def get_duration(filename):
p = subprocess.Popen(['mediainfo', '--Inform=Audio;%Duration%', filename],
close_fds=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
try:
return int(stdout) / 1000
except ValueError:
pass
# fallback on soxi
p = subprocess.Popen(['soxi', filename], close_fds=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
for line in stdout.splitlines():
line = force_text(line)
if not line.startswith('Duration'):
continue
try:
hours, minutes, seconds = re.findall(r'(\d\d):(\d\d):(\d\d)', line)[0]
except IndexError:
continue
return int(hours) * 3600 + int(minutes) * 60 + int(seconds)
return None
def maybe_resize(image_path): def maybe_resize(image_path):
if not os.path.exists(image_path): if not os.path.exists(image_path):
return return
......
...@@ -370,6 +370,13 @@ class EpisodeAddSoundFileView(CreateView): ...@@ -370,6 +370,13 @@ class EpisodeAddSoundFileView(CreateView):
raise PermissionDenied() raise PermissionDenied()
return super(EpisodeAddSoundFileView, self).get_form(*args, **kwargs) return super(EpisodeAddSoundFileView, self).get_form(*args, **kwargs)
def form_valid(self, form):
response = super().form_valid(form)
if not form.instance.duration:
form.instance.compute_duration()
form.instance.save()
return response
def get_success_url(self): def get_success_url(self):
messages.success(self.request, SUCCESS_MESSAGE) messages.success(self.request, SUCCESS_MESSAGE)
return self.object.episode.get_absolute_url() return self.object.episode.get_absolute_url()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment