Commit ead24890 authored by Seb's avatar Seb
Browse files

Generating of transcodes from admin

parent 5c30deb9
......@@ -5,9 +5,10 @@ from wagtail.wagtailadmin import widgets
from wagtail.wagtailadmin.forms import (BaseCollectionMemberForm,
collection_member_permission_formset_factory)
from enumchoicefield.forms import EnumField
from wagtailvideos.fields import WagtailVideoField
from wagtailvideos.formats import get_video_formats
from wagtailvideos.models import Video
from wagtailvideos.models import MediaFormats, Video
from wagtailvideos.permissions import \
permission_policy as video_permission_policy
......@@ -49,6 +50,19 @@ def get_video_form(model):
})
class VideoTranscodeAdminForm(forms.Form):
media_format = EnumField(MediaFormats)
def __init__(self, data=None, *, video, **kwargs):
super().__init__(data, **kwargs)
self.video = video
def save(self):
media_format = self.cleaned_data['media_format']
self.video.do_transcode(media_format)
class VideoInsertionForm(forms.Form):
"""
Form for selecting parameters of the image (e.g. format) prior to insertion
......
......@@ -33,6 +33,7 @@ class MediaFormats(ChoiceEnum):
mp4 = 'H.264 and MP3 in Mp4'
ogg = 'Theora and Voris in Ogg'
class VideoQuerySet(SearchableQuerySetMixin, models.QuerySet):
pass
......@@ -66,7 +67,6 @@ class AbstractVideo(CollectionMember, TagSearchable):
"""
try:
self.file.path
return True
except NotImplementedError:
return False
......@@ -145,13 +145,15 @@ class AbstractVideo(CollectionMember, TagSearchable):
def url(self):
return self.file.url
@property
def filename(self):
return os.path.basename(self.file.name)
def filename(self, include_ext=True):
if include_ext:
return os.path.basename(self.file.name)
else:
return os.path.splitext(os.path.basename(self.file.name))[0]
@property
def file_ext(self):
return os.path.splitext(self.filename)[1][1:]
return os.path.splitext(self.filename())[1][1:]
def is_editable_by_user(self, user):
from wagtail.wagtailimages.permissions import permission_policy
......@@ -165,30 +167,19 @@ class AbstractVideo(CollectionMember, TagSearchable):
return cls.transcodes.related.related_model
def get_transcode(self, media_format):
# TODO check media_format is MediaFormat
Transcode = self.get_transcode_model()
try:
return self.transcodes.get(media_format=media_format)
except Transcode.DoesNotExist:
output_dir = tempfile.mkdtemp()
return self.do_transcode(media_format)
transcode_filename = os.path.splitext(self.filename)[0] + '.' + media_format.name
def do_transcode(self, media_format, force=False):
input_file = self.file.path
output_dir = tempfile.mkdtemp()
transcode_name = "{0}.{1}".format(
self.filename(include_ext=False),
media_format.name)
transcoded_file = self.do_transcode(
media_format, self.file.path, output_dir, transcode_filename)
if transcoded_file:
transcode, created = self.transcodes.get_or_create(
media_format=media_format,
defaults={'file': transcoded_file}
)
return transcode
else:
# TODO handle transcode failure
return None
def do_transcode(self, media_format, input_file, output_dir, transcode_name):
output_file = os.path.join(output_dir, transcode_name)
FNULL = open(os.devnull, 'r')
try:
......@@ -224,7 +215,8 @@ class AbstractVideo(CollectionMember, TagSearchable):
])
else:
return None
transcoded_file = ContentFile(open(output_file, 'rb').read(), transcode_name)
transcoded_file = ContentFile(
open(output_file, 'rb').read(), transcode_name)
except subprocess.CalledProcessError:
return None
......@@ -232,8 +224,12 @@ class AbstractVideo(CollectionMember, TagSearchable):
finally:
shutil.rmtree(output_dir, ignore_errors=True)
return transcoded_file
transcode, created = self.transcodes.get_or_create(
media_format=media_format,
defaults={'file': transcoded_file}
)
return transcode
class Meta:
abstract = True
......
{% extends "wagtailadmin/base.html" %}
{% load wagtailimages_tags staticfiles i18n %}
{% load wagtailimages_tags staticfiles i18n wagtailvideos_tags %}
{% block titletag %}{% blocktrans with title=video.title %}Editing video {{ title }}{% endblocktrans %}{% endblock %}
{% block extra_js %}
......@@ -47,10 +47,12 @@
</div>
<div class="col5 divider-after">
<h2 class="label">{% trans "Video preview" %}</h2>
<video style='max-width:100%;height:auto;' {# FIXME Inline styles #} preload="auto" controls="true" poster='{{video.thumbnail.url}}'>
<source src="{{video.file.url}}" type='video/mp4'/>
</video>
{% video video controls style=max-width:100% %}
<form action="{% url 'wagtailvideos:create_transcode' video.id %}" method="POST">
{% csrf_token %}
{{ transcode_form.media_format }}
<input type='submit' />
</form>
{% if transcodes %}
<h3>Available Transcodes</h3>
<ul>
......@@ -60,8 +62,7 @@
</ul>
{% else %}
<h3>No transcodes found</h3>
<p>If you wish to generate HTML5 compliant transcodes use the button below. This may take a while.</p>
<button>Generate Transcodes</button>
<p>If you wish to generate HTML5 compliant transcodes use the form above. This may take a while.</p>
{% endif %}
</div>
<div class="col2 ">
......
......@@ -32,6 +32,7 @@ def video(parser, token):
extra_attrs[param] = '' # attributes without values e.g. autoplay, controls
return VideoNode(video_expr, html5, extra_attrs)
class VideoNode(template.Node):
def __init__(self, video, html5=False, attrs={}):
self.video = template.Variable(video)
......@@ -42,11 +43,11 @@ class VideoNode(template.Node):
video = self.video.resolve(context)
if not self.html5:
return mark_safe("<video {0}><source src='{1}' type='video/{2}'></video>"
.format(flatatt(self.attrs), video.url, video.file_ext)) # FIXME get mimetype properly
.format(flatatt(self.attrs), video.url, video.file_ext)) # FIXME get mimetype properly (extension is not always reliable)
else:
transcodes = []
for media_format in MediaFormats:
transcode = video.get_transcode(media_format) # FIXME this is blocking
transcode = video.get_transcode(media_format) # FIXME this is blocking when no transcodes are found
transcodes.append("<source src='{0}' type='video/{1}' >".format(transcode.url, transcode.media_format.name))
return mark_safe(
"<video {0}>{1}</video".format(flatatt(self.attrs), "\n".join(transcodes)))
from django.conf.urls import url
from wagtailvideos.views import chooser, multiple, videos
urlpatterns = [
......@@ -7,6 +8,9 @@ urlpatterns = [
url(r'^(\d+)/delete/$', videos.delete, name='delete'),
url(r'^(\d+)/generate_url/$', videos.url_generator, name='url_generator'),
url(r'^(\d+)/generate_url/(.*)/$', videos.generate_url, name='generate_url'),
url(r'^(\d+)/create_transcode/$', videos.create_transcode, name='create_transcode'),
#url(r'^(\d+)/preview/(.*)/$', videos.preview, name='preview'),
url(r'^add/$', videos.add, name='add'),
url(r'^usage/(\d+)/$', videos.usage, name='video_usage'),
......
import os
from django.core.urlresolvers import NoReverseMatch, reverse
from django.http import JsonResponse
from django.http import HttpResponseNotAllowed, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import ugettext as _
from django.views.decorators.vary import vary_on_headers
......@@ -11,7 +11,8 @@ from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailcore.models import Collection, Site
from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.forms import URLGeneratorForm, get_video_form
from wagtailvideos.forms import (URLGeneratorForm, VideoTranscodeAdminForm,
get_video_form)
from wagtailvideos.models import get_video_model
......@@ -124,9 +125,24 @@ def edit(request, video_id):
'url_generator_enabled': url_generator_enabled,
'filesize': video.get_file_size(),
'transcodes': video.transcodes.all(),
'transcode_form': VideoTranscodeAdminForm(video=video)
})
def create_transcode(request, video_id):
if request.method != 'POST':
return HttpResponseNotAllowed(['POST'])
Video = get_video_model()
video = get_object_or_404(Video, id=video_id)
transcode_form = VideoTranscodeAdminForm(request.POST, video=video)
if transcode_form.is_valid():
transcode_form.save()
return redirect('wagtailvideos:edit', video_id)
# TODO was dis?
def url_generator(request, image_id):
image = get_object_or_404(get_video_model(), id=image_id)
......
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