Commit 48a43d1f authored by Seb's avatar Seb
Browse files

Rework track models, add to modeladmin instead formset

parent 9a65727f
This diff is collapsed.
# Generated by Django 2.2.17 on 2021-01-28 23:40
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0003_auto_20210129_1006'),
]
operations = [
migrations.DeleteModel(
name='CustomTrack',
),
]
...@@ -5,7 +5,8 @@ from wagtail.admin.edit_handlers import StreamFieldPanel ...@@ -5,7 +5,8 @@ from wagtail.admin.edit_handlers import StreamFieldPanel
from wagtailvideos.edit_handlers import VideoChooserPanel from wagtailvideos.edit_handlers import VideoChooserPanel
from wagtailvideos.blocks import VideoChooserBlock from wagtailvideos.blocks import VideoChooserBlock
from wagtailvideos.models import AbstractVideo, AbstractVideoTranscode, AbstractTrack from wagtailvideos.models import AbstractVideo, AbstractVideoTranscode
from modelcluster.fields import ParentalKey
class CustomVideoModel(AbstractVideo): class CustomVideoModel(AbstractVideo):
...@@ -30,9 +31,6 @@ class CustomVideoTranscode(AbstractVideoTranscode): ...@@ -30,9 +31,6 @@ class CustomVideoTranscode(AbstractVideoTranscode):
) )
class CustomTrack(AbstractTrack):
video = models.ForeignKey(CustomVideoModel, related_name='tracks', on_delete=models.CASCADE)
class TestPage(Page): class TestPage(Page):
video_field = models.ForeignKey( video_field = models.ForeignKey(
'wagtailvideos.Video', related_name='+', null=True, blank=True, on_delete=models.SET_NULL) 'wagtailvideos.Video', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
......
...@@ -16,6 +16,7 @@ INSTALLED_APPS = [ ...@@ -16,6 +16,7 @@ INSTALLED_APPS = [
'wagtail.snippets', 'wagtail.snippets',
'wagtail.images', 'wagtail.images',
'wagtail.documents', 'wagtail.documents',
'wagtail.contrib.modeladmin',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
......
This diff is collapsed.
This diff is collapsed.
from wagtailvideos import get_video_model_string
from modelcluster.models import ClusterableModel
from modelcluster.fields import ParentalKey
import logging import logging
import mimetypes import mimetypes
import os import os
...@@ -73,7 +76,7 @@ def get_upload_to(instance, filename): ...@@ -73,7 +76,7 @@ def get_upload_to(instance, filename):
return instance.get_upload_to(filename) return instance.get_upload_to(filename)
class AbstractVideo(CollectionMember, index.Indexed, models.Model): class AbstractVideo(CollectionMember, index.Indexed, ClusterableModel):
title = models.CharField(max_length=255, verbose_name=_('title')) title = models.CharField(max_length=255, verbose_name=_('title'))
file = models.FileField( file = models.FileField(
verbose_name=_('file'), upload_to=get_upload_to) verbose_name=_('file'), upload_to=get_upload_to)
...@@ -314,8 +317,18 @@ class VideoTranscode(AbstractVideoTranscode): ...@@ -314,8 +317,18 @@ class VideoTranscode(AbstractVideoTranscode):
) )
class AbstractTrack(models.Model): class TrackListing(ClusterableModel):
# TODO move to TextChoices once djang0 < 3 is dropped video = models.OneToOneField(
get_video_model_string(), on_delete=models.CASCADE,
related_name='tracks')
def __str__(self):
return self.video.title
class VideoTrack(models.Model):
listing = ParentalKey(TrackListing, related_name='tracks', on_delete=models.CASCADE)
# TODO move to TextChoices once django < 3 is dropped
track_kinds = [ track_kinds = [
('subtitles', 'Subtitles'), ('subtitles', 'Subtitles'),
('captions', 'Captions'), ('captions', 'Captions'),
...@@ -345,10 +358,3 @@ class AbstractTrack(models.Model): ...@@ -345,10 +358,3 @@ class AbstractTrack(models.Model):
folder_name = 'video_tracks' folder_name = 'video_tracks'
filename = self.file.field.storage.get_valid_name(filename) filename = self.file.field.storage.get_valid_name(filename)
return os.path.join(folder_name, filename) return os.path.join(folder_name, filename)
class Meta:
abstract = True
class Track(AbstractTrack):
video = models.ForeignKey(Video, related_name='tracks', on_delete=models.CASCADE)
...@@ -6,6 +6,7 @@ from django.db import transaction ...@@ -6,6 +6,7 @@ from django.db import transaction
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from wagtailvideos import ffmpeg, get_video_model from wagtailvideos import ffmpeg, get_video_model
from wagtailvideos.models import VideoTrack
@contextmanager @contextmanager
...@@ -47,7 +48,7 @@ def video_post_save(instance, **kwargs): ...@@ -47,7 +48,7 @@ def video_post_save(instance, **kwargs):
if hasattr(instance, '_from_signal'): if hasattr(instance, '_from_signal'):
# Sender was us, don't run post save # Sender was us, don't run post save
return return
has_changed = instance._initial_file is not instance.file has_changed = instance._initial_file is not instance.file
filled_out = instance.thumbnail is not None and instance.duration is not None filled_out = instance.thumbnail is not None and instance.duration is not None
if has_changed or not filled_out: if has_changed or not filled_out:
...@@ -67,10 +68,8 @@ def video_post_save(instance, **kwargs): ...@@ -67,10 +68,8 @@ def video_post_save(instance, **kwargs):
def register_signal_handlers(): def register_signal_handlers():
Video = get_video_model() Video = get_video_model()
VideoTranscode = Video.get_transcode_model() VideoTranscode = Video.get_transcode_model()
VideoTrack = Video.get_track_model()
post_save.connect(video_post_save, sender=Video) post_save.connect(video_post_save, sender=Video)
post_delete.connect(post_delete_file_cleanup, sender=Video) post_delete.connect(post_delete_file_cleanup, sender=Video)
post_delete.connect(post_delete_file_cleanup, sender=VideoTranscode) post_delete.connect(post_delete_file_cleanup, sender=VideoTranscode)
post_delete.connect(post_delete_file_cleanup, sender=VideoTrack) post_delete.connect(post_delete_file_cleanup, sender=VideoTrack)
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
{% include "wagtailadmin/shared/field_as_li.html" with li_classes="label-above label-uppercase" %} {% include "wagtailadmin/shared/field_as_li.html" with li_classes="label-above label-uppercase" %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul>
<h2 class="u-text-transform-uppercase">Tracks</h2>
<p>Add/edit subtitles or accessibility captions for you video. For information about the filetype that should be used see the mozilla docs on <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API">WebVTT</a></p>
<li> <li>
<input type="submit" class="button" value="{% trans 'Save' %}" /> {% if user_can_delete %} <input type="submit" class="button" value="{% trans 'Save' %}" /> {% if user_can_delete %}
<a href="{% url 'wagtailvideos:delete' video.id %}" class="button button-secondary no">{% trans "Delete video" %}</a> {% endif %} <a href="{% url 'wagtailvideos:delete' video.id %}" class="button button-secondary no">{% trans "Delete video" %}</a> {% endif %}
...@@ -76,10 +79,10 @@ ...@@ -76,10 +79,10 @@
</div> </div>
<div class="row" style='margin-top: 2em;'> <div class="row" style='margin-top: 2em;'>
{% if can_transcode %} {% if can_transcode %}
<h3 class="label no-float u-text-transform-uppercase">Transcodes</h3> <h2 class="u-text-transform-uppercase">Transcodes</h2>
<p>If you wish to generate HTML5 compliant transcodes use the form below. This may take a while depending on the length of the video.</p> <p>If you wish to generate HTML5 compliant transcodes use the form below. This may take a while depending on the length of the video.</p>
{% if transcodes %} {% if transcodes %}
<h3 class="label no-float u-text-transform-uppercase">Available Transcodes</h3> <h3 class="u-text-transform-uppercase">Available Transcodes</h3>
<ul> <ul>
{% for transcode in transcodes %} {% for transcode in transcodes %}
<li> <li>
...@@ -93,7 +96,7 @@ ...@@ -93,7 +96,7 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<h3 class="label no-float u-text-transform-uppercase">Create transcode</h3> <h3 class="u-text-transform-uppercase">Create transcode</h3>
<form action="{% url 'wagtailvideos:create_transcode' video.id %}" method="POST"> <form action="{% url 'wagtailvideos:create_transcode' video.id %}" method="POST">
<ul class="fields"> <ul class="fields">
{% csrf_token %} {% csrf_token %}
......
...@@ -2,16 +2,16 @@ from distutils.version import LooseVersion ...@@ -2,16 +2,16 @@ from distutils.version import LooseVersion
import wagtail import wagtail
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.http import HttpResponseNotAllowed
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.http import require_POST
from django.views.decorators.vary import vary_on_headers from django.views.decorators.vary import vary_on_headers
from wagtail.admin import messages from wagtail.admin import messages
from wagtail.admin.forms.search import SearchForm from wagtail.admin.forms.search import SearchForm
from wagtail.core.models import Collection from wagtail.core.models import Collection
from wagtail.search.backends import get_search_backends from wagtail.search.backends import get_search_backends
from django.forms import modelformset_factory
from wagtailvideos import ffmpeg, get_video_model from wagtailvideos import ffmpeg, get_video_model
from wagtailvideos.forms import VideoTranscodeAdminForm, get_video_form from wagtailvideos.forms import VideoTranscodeAdminForm, get_video_form
from wagtailvideos.permissions import permission_policy from wagtailvideos.permissions import permission_policy
...@@ -104,10 +104,7 @@ def edit(request, video_id): ...@@ -104,10 +104,7 @@ def edit(request, video_id):
for backend in get_search_backends(): for backend in get_search_backends():
backend.add(video) backend.add(video)
messages.success(request, _("Video '{0}' updated.").format(video.title), buttons=[ messages.success(request, _("Video '{0}' updated.").format(video.title))
messages.button(reverse('wagtailvideos:edit', args=(video.id,)), _('Edit again'))
])
return redirect('wagtailvideos:index')
else: else:
messages.error(request, _("The video could not be saved due to errors.")) messages.error(request, _("The video could not be saved due to errors."))
else: else:
...@@ -121,9 +118,6 @@ def edit(request, video_id): ...@@ -121,9 +118,6 @@ def edit(request, video_id):
messages.button(reverse('wagtailvideos:delete', args=(video.id,)), _('Delete')) messages.button(reverse('wagtailvideos:delete', args=(video.id,)), _('Delete'))
]) ])
Track = Video.get_track_model()
TrackFormset = modelformset_factory(Track, exclude=('video',))
return render(request, "wagtailvideos/videos/edit.html", { return render(request, "wagtailvideos/videos/edit.html", {
'video': video, 'video': video,
'form': form, 'form': form,
...@@ -131,14 +125,12 @@ def edit(request, video_id): ...@@ -131,14 +125,12 @@ def edit(request, video_id):
'can_transcode': ffmpeg.installed(), 'can_transcode': ffmpeg.installed(),
'transcodes': video.transcodes.all(), 'transcodes': video.transcodes.all(),
'transcode_form': VideoTranscodeAdminForm(video=video), 'transcode_form': VideoTranscodeAdminForm(video=video),
'track_formset': TrackFormset(queryset=video.tracks.all()),
'user_can_delete': permission_policy.user_has_permission_for_instance(request.user, 'delete', video) 'user_can_delete': permission_policy.user_has_permission_for_instance(request.user, 'delete', video)
}) })
@require_POST
def create_transcode(request, video_id): def create_transcode(request, video_id):
if request.method != 'POST':
return HttpResponseNotAllowed(['POST'])
video = get_object_or_404(get_video_model(), id=video_id) video = get_object_or_404(get_video_model(), id=video_id)
transcode_form = VideoTranscodeAdminForm(data=request.POST, video=video) transcode_form = VideoTranscodeAdminForm(data=request.POST, video=video)
...@@ -193,13 +185,13 @@ def add(request): ...@@ -193,13 +185,13 @@ def add(request):
}) })
def usage(request, image_id): def usage(request, video_id):
image = get_object_or_404(get_video_model(), id=image_id) video = get_object_or_404(get_video_model(), id=video_id)
paginator = Paginator(image.get_usage(), per_page=12) paginator = Paginator(video.get_usage(), per_page=12)
page = paginator.get_page(request.GET.get('p')) page = paginator.get_page(request.GET.get('p'))
return render(request, "wagtailvideos/videos/usage.html", { return render(request, "wagtailvideos/videos/usage.html", {
'image': image, 'video': video,
'used_by': page 'used_by': page
}) })
from wagtail.admin.edit_handlers import InlinePanel
from wagtailvideos.edit_handlers import VideoChooserPanel
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from django.conf.urls import include, url from django.conf.urls import include, url
from django.templatetags.static import static
from django.urls import reverse from django.urls import reverse
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from wagtail.admin.menu import MenuItem, SubmenuMenuItem, Menu from wagtail.admin.menu import Menu, MenuItem, SubmenuMenuItem
from wagtail.admin.search import SearchArea from wagtail.admin.search import SearchArea
from wagtail.admin.site_summary import SummaryItem from wagtail.admin.site_summary import SummaryItem
from wagtail.core import hooks from wagtail.core import hooks
from django.utils.html import format_html
from django.templatetags.static import static from wagtailvideos import get_video_model, urls
from wagtailvideos import urls
from wagtailvideos.forms import GroupVideoPermissionFormSet from wagtailvideos.forms import GroupVideoPermissionFormSet
from wagtailvideos import get_video_model from wagtailvideos.models import TrackListing
from django.utils.safestring import mark_safe
from .permissions import permission_policy from .permissions import permission_policy
Video = get_video_model() Video = get_video_model()
...@@ -48,7 +52,7 @@ class VideoMenu(Menu): ...@@ -48,7 +52,7 @@ class VideoMenu(Menu):
def menu_items_for_request(self, request): def menu_items_for_request(self, request):
return [ return [
MenuItem(_('Videos'), reverse('wagtailvideos:index'), MenuItem(_('Manage videos'), reverse('wagtailvideos:index'),
name='videos', classnames='icon icon-media', order=300) name='videos', classnames='icon icon-media', order=300)
] ]
...@@ -109,3 +113,19 @@ def register_media_search_area(): ...@@ -109,3 +113,19 @@ def register_media_search_area():
@hooks.register('insert_global_admin_css') @hooks.register('insert_global_admin_css')
def summary_css(): def summary_css():
return format_html('<link rel="stylesheet" href="{}">', static('wagtailvideos/css/summary-override.css')) return format_html('<link rel="stylesheet" href="{}">', static('wagtailvideos/css/summary-override.css'))
@modeladmin_register
class TracksAdmin(ModelAdmin):
model = TrackListing
list_display = ('__str__', 'track_count')
def track_count(self, track_listing):
return track_listing.tracks.count()
track_count.short_description = 'No. tracks'
panels = [
VideoChooserPanel('video'),
InlinePanel('tracks', heading="Tracks")
]
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