Commit 6d9645f9 authored by Seb's avatar Seb
Browse files

Made generating transcodes happen in seprate thread to stop the blocking of...

Made generating transcodes happen in seprate thread to stop the blocking of the frontend. Also got rid of proxy method for video model - we don't need custom models
parent b2d3a929
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-05 06:46
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import enumchoicefield.fields
import wagtailvideos.models
class Migration(migrations.Migration):
dependencies = [
('wagtailvideos', '0002_auto_20160321_1610'),
]
operations = [
migrations.CreateModel(
name='VideoTranscode',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('media_format', enumchoicefield.fields.EnumChoiceField(enum_class=wagtailvideos.models.MediaFormats, max_length=4)),
('processing', models.BooleanField(default=False)),
('file', models.FileField(null=True, upload_to=wagtailvideos.models.get_upload_to, verbose_name='file')),
('video', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transcodes', to='wagtailvideos.Video')),
],
),
migrations.AlterUniqueTogether(
name='videotranscode',
unique_together=set([('video', 'media_format')]),
),
]
......@@ -5,6 +5,7 @@ import os.path
import shutil
import subprocess
import tempfile
import threading
from tempfile import NamedTemporaryFile
import django
......@@ -176,10 +177,41 @@ class AbstractVideo(CollectionMember, TagSearchable):
return self.do_transcode(media_format)
def do_transcode(self, media_format, force=False):
input_file = self.file.path
transcode, created = self.transcodes.get_or_create(
media_format=media_format,
)
if transcode.processing is False:
transcode.processing = True
transcode.save(update_fields=['processing']) # Lock the transcode model
TranscodingThread(transcode).start()
return None
class Meta:
abstract = True
class Video(AbstractVideo):
admin_form_fields = (
'title',
'file',
'collection',
'tags',
)
# TODO move out to utils.py or somewhere appropriate
class TranscodingThread(threading.Thread):
def __init__(self, transcode, **kwargs):
super().__init__(**kwargs)
self.transcode = transcode
def run(self):
video = self.transcode.video
media_format = self.transcode.media_format
input_file = video.file.path
output_dir = tempfile.mkdtemp()
transcode_name = "{0}.{1}".format(
self.filename(include_ext=False),
video.filename(include_ext=False),
media_format.name)
output_file = os.path.join(output_dir, transcode_name)
......@@ -226,25 +258,11 @@ class AbstractVideo(CollectionMember, TagSearchable):
finally:
shutil.rmtree(output_dir, ignore_errors=True)
transcode, created = self.transcodes.get_or_create(
media_format=media_format,
defaults={'file': transcoded_file}
)
return transcode
class Meta:
abstract = True
class Video(AbstractVideo):
admin_form_fields = (
'title',
'file',
'collection',
'tags',
)
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)
......@@ -253,31 +271,11 @@ def video_delete(sender, instance, **kwargs):
instance.file.delete(False)
def get_video_model():
from django.conf import settings
from django.apps import apps
try:
app_label, model_name = settings.WAGTAILVIDEOS_VIDEO_MODEL.split('.')
except AttributeError:
return Video
except ValueError:
raise ImproperlyConfigured("WAGTAILVIDEOS_VIDEO_MODEL must be of the form 'app_label.model_name'")
#TODO is this neccescary ??
image_model = apps.get_model(app_label, model_name)
if image_model is None:
raise ImproperlyConfigured(
"WAGTAILVIDEOS_VIDEO_MODEL refers to model '%s' that has not been installed" %
settings.WAGTAILIMAGES_IMAGE_MODEL
)
return image_model
class AbstractVideoTranscode(models.Model):
media_format = EnumChoiceField(MediaFormats)
file = models.FileField(
verbose_name=_('file'), upload_to=get_upload_to) # FIXME get_transcode_upload_to
processing = models.BooleanField(default=False)
file = models.FileField(null=True,
verbose_name=_('file'), upload_to=get_upload_to)
@property
def url(self):
......
from wagtail.wagtailcore.permission_policies.collections import \
CollectionOwnershipPermissionPolicy
from wagtailvideos.models import Video, get_video_model
from wagtailvideos.models import Video
permission_policy = CollectionOwnershipPermissionPolicy(
get_video_model(),
Video,
auth_model=Video,
owner_field_name='uploaded_by_user'
)
......@@ -57,7 +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 %}
{% endfor %}
</ul>
{% else %}
......
......@@ -8,7 +8,7 @@ from django.utils.text import mark_safe
from wagtailvideos.models import MediaFormats, Video
register = template.Library()
# {% video self.intro_video html5(optional) extra_att extra_att %}
# {% video self.intro_video extra_att extra_att %}
@register.tag(name="video")
......@@ -17,37 +17,29 @@ def video(parser, token):
video_expr = template_params[0]
extra_attrs = {}
html5 = False
# Everyting after video expression
if(len(template_params) > 1):
for param in template_params[1:]:
if param == 'html5':
html5 = True
else:
try:
name, value = param.split('=')
extra_attrs[name] = value
except ValueError:
extra_attrs[param] = '' # attributes without values e.g. autoplay, controls
return VideoNode(video_expr, html5, extra_attrs)
try:
name, value = param.split('=')
extra_attrs[name] = value
except ValueError:
extra_attrs[param] = '' # attributes without values e.g. autoplay, controls
return VideoNode(video_expr, extra_attrs)
class VideoNode(template.Node):
def __init__(self, video, html5=False, attrs={}):
def __init__(self, video, attrs={}):
self.video = template.Variable(video)
self.html5 = html5
self.attrs = attrs
def render(self, context):
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 (extension is not always reliable)
else:
transcodes = []
for media_format in MediaFormats:
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)))
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))
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)))
......@@ -7,9 +7,10 @@ from wagtail.wagtailadmin.forms import SearchForm
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 get_video_model
from wagtailvideos.models import Video
def get_video_json(video):
......@@ -29,8 +30,6 @@ def get_video_json(video):
def chooser(request):
Video = get_video_model()
VideoForm = get_video_form(Video)
uploadform = VideoForm()
......@@ -91,7 +90,7 @@ def chooser(request):
def video_chosen(request, video_id):
video = get_object_or_404(get_video_model(), id=video_id)
video = get_object_or_404(Video, id=video_id)
return render_modal_workflow(
request, None, 'wagtailvideos/chooser/video_chosen.js',
......@@ -100,7 +99,6 @@ def video_chosen(request, video_id):
def chooser_upload(request):
Video = get_video_model()
VideoForm = get_video_form(Video)
searchform = SearchForm()
......@@ -140,7 +138,7 @@ def chooser_upload(request):
def chooser_select_format(request, video_id):
video = get_object_or_404(get_video_model(), id=video_id)
video = get_object_or_404(Video, id=video_id)
if request.POST:
form = VideoInsertionForm(request.POST, initial={'alt_text': video.default_alt_text})
......
......@@ -9,7 +9,7 @@ from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.fields import ALLOWED_EXTENSIONS
from wagtailvideos.forms import get_video_form
from wagtailvideos.models import get_video_model
from wagtailvideos.models import Video
from wagtailvideos.permissions import permission_policy
permission_checker = PermissionPolicyChecker(permission_policy)
......@@ -31,7 +31,6 @@ def get_video_edit_form(VideoModel):
@vary_on_headers('X-Requested-With')
def add(request):
Video = get_video_model()
VideoForm = get_video_form(Video)
collections = permission_policy.collections_user_has_permission_for(request.user, 'add')
......@@ -98,7 +97,6 @@ def add(request):
@require_POST
def edit(request, video_id, callback=None):
Video = get_video_model()
VideoForm = get_video_edit_form(Video)
video = get_object_or_404(Video, id=video_id)
......@@ -134,7 +132,7 @@ def edit(request, video_id, callback=None):
@require_POST
def delete(request, video_id):
video = get_object_or_404(get_video_model(), id=video_id)
video = get_object_or_404(Video, id=video_id)
if not request.is_ajax():
return HttpResponseBadRequest("Cannot POST to this view without AJAX")
......
......@@ -14,7 +14,7 @@ from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.forms import (URLGeneratorForm, VideoTranscodeAdminForm,
get_video_form)
from wagtailvideos.models import get_video_model
from wagtailvideos.models import Video
from wagtailvideos.permissions import permission_policy
permission_checker = PermissionPolicyChecker(permission_policy)
......@@ -22,9 +22,7 @@ permission_checker = PermissionPolicyChecker(permission_policy)
@permission_checker.require_any('add', 'change', 'delete')
@vary_on_headers('X-Requested-With')
def index(request):
Video = get_video_model()
# Get images (filtered by user permission)
# Get Videos (filtered by user permission)
videos = Video.objects.all()
# Search
......@@ -72,7 +70,6 @@ def index(request):
@permission_checker.require('change')
def edit(request, video_id):
Video = get_video_model()
VideoForm = get_video_form(Video)
video = get_object_or_404(Video, id=video_id)
......@@ -130,7 +127,6 @@ 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)
......@@ -140,7 +136,7 @@ def create_transcode(request, video_id):
@permission_checker.require('delete')
def delete(request, video_id):
video = get_object_or_404(get_video_model(), id=video_id)
video = get_object_or_404(Video, id=video_id)
if request.POST:
video.delete()
......@@ -153,7 +149,9 @@ def delete(request, video_id):
@permission_checker.require('add')
def add(request):
ImageModel = get_video_model()
# FIXME try and find where this is used
print("\n\n----------------------------ADD HIT---------------------------\n\n")
ImageModel = Video
ImageForm = get_video_form(ImageModel)
if request.POST:
......@@ -184,7 +182,7 @@ def add(request):
def usage(request, image_id):
image = get_object_or_404(get_video_model(), id=image_id)
image = get_object_or_404(Video, id=image_id)
paginator, used_by = paginate(request, image.get_usage())
......
......@@ -6,7 +6,7 @@ from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from wagtail.wagtailadmin.widgets import AdminChooser
from wagtailvideos.models import get_video_model
from wagtailvideos.models import Video
class AdminVideoChooser(AdminChooser):
......@@ -16,7 +16,7 @@ class AdminVideoChooser(AdminChooser):
def __init__(self, **kwargs):
super(AdminVideoChooser, self).__init__(**kwargs)
self.video_model = get_video_model()
self.video_model = Video
def render_html(self, name, value, attrs):
instance, value = self.get_instance_and_id(self.video_model, value)
......
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