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 ...@@ -5,6 +5,7 @@ import os.path
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
import threading
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import django import django
...@@ -176,10 +177,41 @@ class AbstractVideo(CollectionMember, TagSearchable): ...@@ -176,10 +177,41 @@ class AbstractVideo(CollectionMember, TagSearchable):
return self.do_transcode(media_format) return self.do_transcode(media_format)
def do_transcode(self, media_format, force=False): 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() output_dir = tempfile.mkdtemp()
transcode_name = "{0}.{1}".format( transcode_name = "{0}.{1}".format(
self.filename(include_ext=False), video.filename(include_ext=False),
media_format.name) media_format.name)
output_file = os.path.join(output_dir, transcode_name) output_file = os.path.join(output_dir, transcode_name)
...@@ -226,25 +258,11 @@ class AbstractVideo(CollectionMember, TagSearchable): ...@@ -226,25 +258,11 @@ class AbstractVideo(CollectionMember, TagSearchable):
finally: finally:
shutil.rmtree(output_dir, ignore_errors=True) shutil.rmtree(output_dir, ignore_errors=True)
transcode, created = self.transcodes.get_or_create( self.transcode.processing = False
media_format=media_format, self.transcode.file = transcoded_file
defaults={'file': transcoded_file} self.transcode.save(update_fields=[
) 'processing', 'file'
])
return transcode
class Meta:
abstract = True
class Video(AbstractVideo):
admin_form_fields = (
'title',
'file',
'collection',
'tags',
)
# Delete files when model is deleted # Delete files when model is deleted
@receiver(pre_delete, sender=Video) @receiver(pre_delete, sender=Video)
...@@ -253,31 +271,11 @@ def video_delete(sender, instance, **kwargs): ...@@ -253,31 +271,11 @@ def video_delete(sender, instance, **kwargs):
instance.file.delete(False) 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): class AbstractVideoTranscode(models.Model):
media_format = EnumChoiceField(MediaFormats) media_format = EnumChoiceField(MediaFormats)
file = models.FileField( processing = models.BooleanField(default=False)
verbose_name=_('file'), upload_to=get_upload_to) # FIXME get_transcode_upload_to file = models.FileField(null=True,
verbose_name=_('file'), upload_to=get_upload_to)
@property @property
def url(self): def url(self):
......
from wagtail.wagtailcore.permission_policies.collections import \ from wagtail.wagtailcore.permission_policies.collections import \
CollectionOwnershipPermissionPolicy CollectionOwnershipPermissionPolicy
from wagtailvideos.models import Video, get_video_model
from wagtailvideos.models import Video
permission_policy = CollectionOwnershipPermissionPolicy( permission_policy = CollectionOwnershipPermissionPolicy(
get_video_model(), Video,
auth_model=Video, auth_model=Video,
owner_field_name='uploaded_by_user' owner_field_name='uploaded_by_user'
) )
...@@ -57,7 +57,11 @@ ...@@ -57,7 +57,11 @@
<h3>Available Transcodes</h3> <h3>Available Transcodes</h3>
<ul> <ul>
{% for transcode in transcodes %} {% for transcode in transcodes %}
{% if transcode.processing %}
<li>{{ transcode.media_format }} (Processing... hold tight) </li>
{%else %}
<li>{{ transcode.media_format }}</li> <li>{{ transcode.media_format }}</li>
{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
......
...@@ -8,7 +8,7 @@ from django.utils.text import mark_safe ...@@ -8,7 +8,7 @@ from django.utils.text import mark_safe
from wagtailvideos.models import MediaFormats, Video from wagtailvideos.models import MediaFormats, Video
register = template.Library() 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") @register.tag(name="video")
...@@ -17,37 +17,29 @@ def video(parser, token): ...@@ -17,37 +17,29 @@ def video(parser, token):
video_expr = template_params[0] video_expr = template_params[0]
extra_attrs = {} extra_attrs = {}
html5 = False
# Everyting after video expression # Everyting after video expression
if(len(template_params) > 1): if(len(template_params) > 1):
for param in template_params[1:]: for param in template_params[1:]:
if param == 'html5': try:
html5 = True name, value = param.split('=')
else: extra_attrs[name] = value
try: except ValueError:
name, value = param.split('=') extra_attrs[param] = '' # attributes without values e.g. autoplay, controls
extra_attrs[name] = value return VideoNode(video_expr, extra_attrs)
except ValueError:
extra_attrs[param] = '' # attributes without values e.g. autoplay, controls
return VideoNode(video_expr, html5, extra_attrs)
class VideoNode(template.Node): class VideoNode(template.Node):
def __init__(self, video, html5=False, attrs={}): def __init__(self, video, attrs={}):
self.video = template.Variable(video) self.video = template.Variable(video)
self.html5 = html5
self.attrs = attrs self.attrs = attrs
def render(self, context): def render(self, context):
video = self.video.resolve(context) video = self.video.resolve(context)
if not self.html5: sources = ["<source src='{1}' type='video/{2}'>"
return mark_safe("<video {0}><source src='{1}' type='video/{2}'></video>" .format(flatatt(self.attrs), video.url, video.file_ext)] # TODO get mimetype properly (extension is not always reliable)
.format(flatatt(self.attrs), video.url, video.file_ext)) # FIXME get mimetype properly (extension is not always reliable) for transcode in video.transcodes.filter(processing=False):
else: sources.append("<source src='{0}' type='video/{1}' >".format(transcode.url, transcode.media_format.name))
transcodes = [] sources.append("<p>Sorry, your browser doesn't support playback for this video</p>")
for media_format in MediaFormats: return mark_safe(
transcode = video.get_transcode(media_format) # FIXME this is blocking when no transcodes are found "<video {0}>{1}</video".format(flatatt(self.attrs), "\n".join(sources)))
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)))
...@@ -7,9 +7,10 @@ from wagtail.wagtailadmin.forms import SearchForm ...@@ -7,9 +7,10 @@ from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailcore.models import Collection from wagtail.wagtailcore.models import Collection
from wagtail.wagtailsearch.backends import get_search_backends from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.formats import get_video_format from wagtailvideos.formats import get_video_format
from wagtailvideos.forms import VideoInsertionForm, get_video_form 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): def get_video_json(video):
...@@ -29,8 +30,6 @@ def get_video_json(video): ...@@ -29,8 +30,6 @@ def get_video_json(video):
def chooser(request): def chooser(request):
Video = get_video_model()
VideoForm = get_video_form(Video) VideoForm = get_video_form(Video)
uploadform = VideoForm() uploadform = VideoForm()
...@@ -91,7 +90,7 @@ def chooser(request): ...@@ -91,7 +90,7 @@ def chooser(request):
def video_chosen(request, video_id): 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( return render_modal_workflow(
request, None, 'wagtailvideos/chooser/video_chosen.js', request, None, 'wagtailvideos/chooser/video_chosen.js',
...@@ -100,7 +99,6 @@ def video_chosen(request, video_id): ...@@ -100,7 +99,6 @@ def video_chosen(request, video_id):
def chooser_upload(request): def chooser_upload(request):
Video = get_video_model()
VideoForm = get_video_form(Video) VideoForm = get_video_form(Video)
searchform = SearchForm() searchform = SearchForm()
...@@ -140,7 +138,7 @@ def chooser_upload(request): ...@@ -140,7 +138,7 @@ def chooser_upload(request):
def chooser_select_format(request, video_id): 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: if request.POST:
form = VideoInsertionForm(request.POST, initial={'alt_text': video.default_alt_text}) form = VideoInsertionForm(request.POST, initial={'alt_text': video.default_alt_text})
......
...@@ -9,7 +9,7 @@ from wagtail.wagtailsearch.backends import get_search_backends ...@@ -9,7 +9,7 @@ from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.fields import ALLOWED_EXTENSIONS from wagtailvideos.fields import ALLOWED_EXTENSIONS
from wagtailvideos.forms import get_video_form 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 from wagtailvideos.permissions import permission_policy
permission_checker = PermissionPolicyChecker(permission_policy) permission_checker = PermissionPolicyChecker(permission_policy)
...@@ -31,7 +31,6 @@ def get_video_edit_form(VideoModel): ...@@ -31,7 +31,6 @@ def get_video_edit_form(VideoModel):
@vary_on_headers('X-Requested-With') @vary_on_headers('X-Requested-With')
def add(request): def add(request):
Video = get_video_model()
VideoForm = get_video_form(Video) VideoForm = get_video_form(Video)
collections = permission_policy.collections_user_has_permission_for(request.user, 'add') collections = permission_policy.collections_user_has_permission_for(request.user, 'add')
...@@ -98,7 +97,6 @@ def add(request): ...@@ -98,7 +97,6 @@ def add(request):
@require_POST @require_POST
def edit(request, video_id, callback=None): def edit(request, video_id, callback=None):
Video = get_video_model()
VideoForm = get_video_edit_form(Video) VideoForm = get_video_edit_form(Video)
video = get_object_or_404(Video, id=video_id) video = get_object_or_404(Video, id=video_id)
...@@ -134,7 +132,7 @@ def edit(request, video_id, callback=None): ...@@ -134,7 +132,7 @@ def edit(request, video_id, callback=None):
@require_POST @require_POST
def delete(request, video_id): 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(): if not request.is_ajax():
return HttpResponseBadRequest("Cannot POST to this view without AJAX") return HttpResponseBadRequest("Cannot POST to this view without AJAX")
......
...@@ -14,7 +14,7 @@ from wagtail.wagtailsearch.backends import get_search_backends ...@@ -14,7 +14,7 @@ from wagtail.wagtailsearch.backends import get_search_backends
from wagtailvideos.forms import (URLGeneratorForm, VideoTranscodeAdminForm, from wagtailvideos.forms import (URLGeneratorForm, VideoTranscodeAdminForm,
get_video_form) get_video_form)
from wagtailvideos.models import get_video_model from wagtailvideos.models import Video
from wagtailvideos.permissions import permission_policy from wagtailvideos.permissions import permission_policy
permission_checker = PermissionPolicyChecker(permission_policy) permission_checker = PermissionPolicyChecker(permission_policy)
...@@ -22,9 +22,7 @@ permission_checker = PermissionPolicyChecker(permission_policy) ...@@ -22,9 +22,7 @@ permission_checker = PermissionPolicyChecker(permission_policy)
@permission_checker.require_any('add', 'change', 'delete') @permission_checker.require_any('add', 'change', 'delete')
@vary_on_headers('X-Requested-With') @vary_on_headers('X-Requested-With')
def index(request): def index(request):
Video = get_video_model() # Get Videos (filtered by user permission)
# Get images (filtered by user permission)
videos = Video.objects.all() videos = Video.objects.all()
# Search # Search
...@@ -72,7 +70,6 @@ def index(request): ...@@ -72,7 +70,6 @@ def index(request):
@permission_checker.require('change') @permission_checker.require('change')
def edit(request, video_id): def edit(request, video_id):
Video = get_video_model()
VideoForm = get_video_form(Video) VideoForm = get_video_form(Video)
video = get_object_or_404(Video, id=video_id) video = get_object_or_404(Video, id=video_id)
...@@ -130,7 +127,6 @@ def create_transcode(request, video_id): ...@@ -130,7 +127,6 @@ def create_transcode(request, video_id):
if request.method != 'POST': if request.method != 'POST':
return HttpResponseNotAllowed(['POST']) return HttpResponseNotAllowed(['POST'])
Video = get_video_model()
video = get_object_or_404(Video, id=video_id) video = get_object_or_404(Video, id=video_id)
transcode_form = VideoTranscodeAdminForm(request.POST, video=video) transcode_form = VideoTranscodeAdminForm(request.POST, video=video)
...@@ -140,7 +136,7 @@ def create_transcode(request, video_id): ...@@ -140,7 +136,7 @@ def create_transcode(request, video_id):
@permission_checker.require('delete') @permission_checker.require('delete')
def delete(request, video_id): 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: if request.POST:
video.delete() video.delete()
...@@ -153,7 +149,9 @@ def delete(request, video_id): ...@@ -153,7 +149,9 @@ def delete(request, video_id):
@permission_checker.require('add') @permission_checker.require('add')
def add(request): 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) ImageForm = get_video_form(ImageModel)
if request.POST: if request.POST:
...@@ -184,7 +182,7 @@ def add(request): ...@@ -184,7 +182,7 @@ def add(request):
def usage(request, image_id): 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()) paginator, used_by = paginate(request, image.get_usage())
......
...@@ -6,7 +6,7 @@ from django.template.loader import render_to_string ...@@ -6,7 +6,7 @@ from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from wagtail.wagtailadmin.widgets import AdminChooser from wagtail.wagtailadmin.widgets import AdminChooser
from wagtailvideos.models import get_video_model from wagtailvideos.models import Video
class AdminVideoChooser(AdminChooser): class AdminVideoChooser(AdminChooser):
...@@ -16,7 +16,7 @@ class AdminVideoChooser(AdminChooser): ...@@ -16,7 +16,7 @@ class AdminVideoChooser(AdminChooser):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(AdminVideoChooser, self).__init__(**kwargs) super(AdminVideoChooser, self).__init__(**kwargs)
self.video_model = get_video_model() self.video_model = Video
def render_html(self, name, value, attrs): def render_html(self, name, value, attrs):
instance, value = self.get_instance_and_id(self.video_model, value) 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