Commit 4098444c authored by Seb's avatar Seb
Browse files

Got rid of extra cruft. Added in error handling for ffmpeg

parent 6d9645f9
from django.utils.html import escape
from wagtail.utils.apps import get_app_submodules
from .shortcuts import get_rendition_or_not_found
class Format(object):
def __init__(self, name, label, classnames, filter_spec):
self.name = name
self.label = label
self.classnames = classnames
self.filter_spec = filter_spec
def editor_attributes(self, video, alt_text):
"""
Return string of additional attributes to go on the HTML element
when outputting this image within a rich text editor field
"""
return 'data-embedtype="image" data-id="%d" data-format="%s" data-alt="%s" ' % (
video.id, self.name, alt_text
)
def video_to_editor_html(self, image, alt_text):
return self.image_to_html(
image, alt_text, self.editor_attributes(image, alt_text)
)
def video_to_html(self, image, alt_text, extra_attributes=''):
rendition = get_rendition_or_not_found(image, self.filter_spec)
if self.classnames:
class_attr = 'class="%s" ' % escape(self.classnames)
else:
class_attr = ''
return '<img %s%ssrc="%s" width="%d" height="%d" alt="%s">' % (
extra_attributes, class_attr,
escape(rendition.url), rendition.width, rendition.height, alt_text
)
FORMATS = []
FORMATS_BY_NAME = {}
def register_video_format(format):
if format.name in FORMATS_BY_NAME:
raise KeyError("Image format '%s' is already registered" % format.name)
FORMATS_BY_NAME[format.name] = format
FORMATS.append(format)
def unregister_video_format(format_name):
global FORMATS
# handle being passed a format object rather than a format name string
try:
format_name = format_name.name
except AttributeError:
pass
try:
del FORMATS_BY_NAME[format_name]
FORMATS = [fmt for fmt in FORMATS if fmt.name != format_name]
except KeyError:
raise KeyError("Image format '%s' is not registered" % format_name)
def get_video_formats():
search_for_video_formats()
return FORMATS
def get_video_format(name):
search_for_video_formats()
return FORMATS_BY_NAME[name]
_searched_for_video_formats = False
def search_for_video_formats():
global _searched_for_video_formats
if not _searched_for_video_formats:
list(get_app_submodules('video_formats'))
_searched_for_video_formats = True
# Define default image formats
register_video_format(Format('fullwidth', 'Full width', 'richtext-image full-width', 'width-800'))
register_video_format(Format('left', 'Left-aligned', 'richtext-image left', 'width-500'))
register_video_format(Format('right', 'Right-aligned', 'richtext-image right', 'width-500'))
......@@ -7,7 +7,6 @@ from wagtail.wagtailadmin.forms import (BaseCollectionMemberForm,
from enumchoicefield.forms import EnumField
from wagtailvideos.fields import WagtailVideoField
from wagtailvideos.formats import get_video_formats
from wagtailvideos.models import MediaFormats, Video
from wagtailvideos.permissions import \
permission_policy as video_permission_policy
......@@ -64,15 +63,7 @@ class VideoTranscodeAdminForm(forms.Form):
class VideoInsertionForm(forms.Form):
"""
Form for selecting parameters of the image (e.g. format) prior to insertion
into a rich text area
"""
format = forms.ChoiceField(
choices=[(format.name, format.label) for format in get_video_formats()],
widget=forms.RadioSelect
)
alt_text = forms.CharField()
pass
class URLGeneratorForm(forms.Form):
......
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-06 01:53
from __future__ import unicode_literals
from django.db import migrations, models
import wagtailvideos.models
class Migration(migrations.Migration):
dependencies = [
('wagtailvideos', '0003_auto_20160705_1646'),
]
operations = [
migrations.AlterField(
model_name='videotranscode',
name='file',
field=models.FileField(blank=True, null=True, upload_to=wagtailvideos.models.get_upload_to, verbose_name='file'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-06 04:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wagtailvideos', '0004_auto_20160706_1153'),
]
operations = [
migrations.AddField(
model_name='videotranscode',
name='error_message',
field=models.TextField(blank=True),
),
]
......@@ -185,7 +185,8 @@ class AbstractVideo(CollectionMember, TagSearchable):
transcode.processing = True
transcode.save(update_fields=['processing']) # Lock the transcode model
TranscodingThread(transcode).start()
return None
else:
pass # TODO Queue?
class Meta:
abstract = True
......@@ -216,66 +217,56 @@ class TranscodingThread(threading.Thread):
output_file = os.path.join(output_dir, transcode_name)
FNULL = open(os.devnull, 'r')
args = ['ffmpeg', '-hide_banner', '-i', input_file]
try:
if media_format is MediaFormats.ogg:
subprocess.check_call([
'ffmpeg',
'-i', input_file,
subprocess.check_output(args + [
'-codec:v', 'libtheora',
'-qscale:v', '7',
'-codec:a', 'libvorbis',
'-qscale:a', '5',
output_file,
], stdin=FNULL)
], stdin=FNULL, stderr=subprocess.STDOUT)
elif media_format is MediaFormats.mp4:
subprocess.check_call([
'ffmpeg',
'-i', input_file,
subprocess.check_call(args + [
'-codec:v', 'libx264',
'-preset', 'slow', # TODO Checkout other presets
'-crf', '22',
'-codec:a', 'copy',
output_file,
])
], stdin=FNULL, stderr=subprocess.STDOUT)
elif media_format is MediaFormats.webm:
subprocess.check_call([
'ffmpeg',
'-i', input_file,
subprocess.check_call(args + [
'-codec:v', 'libvpx',
'-crf', '10',
'-b:v', '1M',
'-codec:a', 'libvorbis',
output_file,
])
else:
return None
transcoded_file = ContentFile(
], stdin=FNULL, stderr=subprocess.STDOUT)
self.transcode.file = ContentFile(
open(output_file, 'rb').read(), transcode_name)
except subprocess.CalledProcessError:
return None
self.transcode.error_message = ''
except subprocess.CalledProcessError as error:
self.transcode.error_message = error.output
finally:
self.transcode.processing = False
self.transcode.save()
shutil.rmtree(output_dir, ignore_errors=True)
self.transcode.processing = False
self.transcode.file = transcoded_file
self.transcode.save(update_fields=[
'processing', 'file'
])
# Delete files when model is deleted
@receiver(pre_delete, sender=Video)
def video_delete(sender, instance, **kwargs):
print('Video pre delete received')
instance.file.delete(False)
class AbstractVideoTranscode(models.Model):
media_format = EnumChoiceField(MediaFormats)
processing = models.BooleanField(default=False)
file = models.FileField(null=True,
file = models.FileField(null=True, blank=True,
verbose_name=_('file'), upload_to=get_upload_to)
error_message = models.TextField(blank=True)
@property
def url(self):
......
# coding=utf-8
def get_rendition_or_not_found(image, specs):
"""
Tries to get / create the rendition for the image or renders a not-found image if it does not exist.
:param image: AbstractImage
:param specs: str or Filter
:return: Rendition
"""
try:
return image.get_rendition(specs)
except image.DoesNotExist:
# Image file is (probably) missing from /media/original_images - generate a dummy
# rendition so that we just output a broken image, rather than crashing out completely
# during rendering.
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
rendition = Rendition(image=image, width=0, height=0)
rendition.file.name = 'not-found'
return rendition
......@@ -57,11 +57,11 @@
<h3>Available Transcodes</h3>
<ul>
{% for transcode in transcodes %}
{% if transcode.processing %}
<li>{{ transcode.media_format }} (Processing... hold tight) </li>
{%else %}
<li>{{ transcode.media_format }}</li>
{% endif %}
<li>
{{ transcode.media_format }}
{% if transcode.processing %} (Processing... hold tight) {% endif %}
{% if transcode.error_message %} <pre> {{ transcode.error_message }}</pre> {% endif %}
</li>
{% endfor %}
</ul>
{% else %}
......
......@@ -38,8 +38,8 @@ class VideoNode(template.Node):
video = self.video.resolve(context)
sources = ["<source src='{1}' type='video/{2}'>"
.format(flatatt(self.attrs), video.url, video.file_ext)] # TODO get mimetype properly (extension is not always reliable)
for transcode in video.transcodes.filter(processing=False):
sources.append("<source src='{0}' type='video/{1}' >".format(transcode.url, transcode.media_format.name))
for transcode in video.transcodes.exclude(processing=True, file=''):
sources.append("<source src='{0}' type='video/{1}' >".format(transcode.media_format.value, transcode.media_format.name))
sources.append("<p>Sorry, your browser doesn't support playback for this video</p>")
return mark_safe(
"<video {0}>{1}</video".format(flatatt(self.attrs), "\n".join(sources)))
"<video {0}>{1}</video>".format(flatatt(self.attrs), "\n".join(sources)))
......@@ -8,7 +8,6 @@ from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailcore.models import Collection
from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.formats import get_video_format
from wagtailvideos.forms import VideoInsertionForm, get_video_form
from wagtailvideos.models import Video
......@@ -144,14 +143,11 @@ def chooser_select_format(request, video_id):
form = VideoInsertionForm(request.POST, initial={'alt_text': video.default_alt_text})
if form.is_valid():
format = get_video_format(form.cleaned_data['format'])
preview_video = video.get_rendition(format.filter_spec)
video_json = json.dumps({
'id': image.id,
'title': image.title,
'format': format.name,
'alt': form.cleaned_data['alt_text'],
'class': format.classnames,
'edit_link': reverse('wagtailvideos:edit', args=(video.id,)),
'preview': {
......
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