Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Websites UFRPE
Wagtail Videos
Commits
7a4cf265
Commit
7a4cf265
authored
Jan 28, 2021
by
Seb
Browse files
Added ability to change the video model
parent
6d7c3bd8
Changes
15
Hide whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
View file @
7a4cf265
...
...
@@ -27,4 +27,15 @@ lts_211:
image
:
python:3.8
extends
:
.python_test
before_script
:
-
pip install .['testing'] wagtail~=2.11 django~=3.1
\ No newline at end of file
-
pip install .['testing'] wagtail~=2.11 django~=3.1
build
:
image
:
python:3.8
stage
:
release
before_script
:
-
pip install --upgrade setuptools wheel twine
script
:
-
./setup.py sdist bdist_wheel
-
twine upload dist/*
only
:
-
tags
README.rst
View file @
7a4cf265
...
...
@@ -43,6 +43,7 @@ Implement as a ``ForeignKey`` relation, same as wagtailimages.
from wagtailvideos.edit_handlers import VideoChooserPanel
class HomePage(Page):
body = RichtextField()
header_video = models.ForeignKey('wagtailvideos.Video',
...
...
@@ -68,6 +69,7 @@ A VideoChooserBlock is included
from wagtailvideos.blocks import VideoChooserBlock
class ContentPage(Page):
body = StreamField([
('video', VideoChooserBlock()),
...
...
@@ -90,6 +92,8 @@ tag. The original video and all extra transcodes are added as
{% load wagtailvideos_tags %}
{% video self.header_video autoplay controls width=256 %}
Jinja2 extensions are also included.
How to transcode using ffmpeg:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
...
@@ -99,8 +103,46 @@ be used to create new transcodes. It is assumed that your compiled
version of ffmpeg has the matching codec libraries required for the
transcode.
Custom Video models:
~~~~~~~~~~~~~~~~~~~~
Same as Wagtail Images, a custom model can be used to replace the built in Video model using the
``WAGTAILVIDEOS_VIDEO_MODEL`` setting.
.. code:: django
# settings.py
WAGTAILVIDEOS_VIDEO_MODEL = 'videos.AttributedVideo'
# app.videos.models
from django.db import models
from wagtailvideos.models import AbstractVideo, AbstractVideoTranscode
class AttributedVideo(AbstractVideo):
attribution = models.TextField()
admin_form_fields = (
'title',
'attribution',
'file',
'collection',
'thumbnail',
'tags',
)
class CustomTranscode(AbstractVideoTranscode):
video = models.ForeignKey(AttributedVideo, related_name='transcodes', on_delete=models.CASCADE)
class Meta:
unique_together = (
('video', 'media_format')
)
Future features
---------------
- Some docs
- Richtext embed
- Transcoding via amazon service rather than ffmpeg
tests/app/migrations/0003_customvideomodel_customvideotranscode.py
0 → 100644
View file @
7a4cf265
# Generated by Django 2.2.17 on 2021-01-27 23:53
from
django.conf
import
settings
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
enumchoicefield.fields
import
taggit.managers
import
wagtail.core.models
import
wagtail.search.index
import
wagtailvideos.models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
(
'taggit'
,
'0003_taggeditem_add_unique_index'
),
(
'wagtailcore'
,
'0059_apply_collection_ordering'
),
(
'app'
,
'0002_testpage_video_streamfield'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'CustomVideoModel'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
auto_created
=
True
,
primary_key
=
True
,
serialize
=
False
,
verbose_name
=
'ID'
)),
(
'title'
,
models
.
CharField
(
max_length
=
255
,
verbose_name
=
'title'
)),
(
'file'
,
models
.
FileField
(
upload_to
=
wagtailvideos
.
models
.
get_upload_to
,
verbose_name
=
'file'
)),
(
'thumbnail'
,
models
.
ImageField
(
blank
=
True
,
null
=
True
,
upload_to
=
wagtailvideos
.
models
.
get_upload_to
)),
(
'created_at'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
db_index
=
True
,
verbose_name
=
'created at'
)),
(
'duration'
,
models
.
DurationField
(
blank
=
True
,
null
=
True
)),
(
'file_size'
,
models
.
PositiveIntegerField
(
editable
=
False
,
null
=
True
)),
(
'attribution'
,
models
.
TextField
()),
(
'collection'
,
models
.
ForeignKey
(
default
=
wagtail
.
core
.
models
.
get_root_collection_id
,
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
related_name
=
'+'
,
to
=
'wagtailcore.Collection'
,
verbose_name
=
'collection'
)),
(
'tags'
,
taggit
.
managers
.
TaggableManager
(
blank
=
True
,
help_text
=
None
,
through
=
'taggit.TaggedItem'
,
to
=
'taggit.Tag'
,
verbose_name
=
'tags'
)),
(
'uploaded_by_user'
,
models
.
ForeignKey
(
blank
=
True
,
editable
=
False
,
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'uploaded by user'
)),
],
options
=
{
'ordering'
:
[
'-created_at'
],
'abstract'
:
False
,
},
bases
=
(
wagtail
.
search
.
index
.
Indexed
,
models
.
Model
),
),
migrations
.
CreateModel
(
name
=
'CustomVideoTranscode'
,
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
)),
(
'quality'
,
enumchoicefield
.
fields
.
EnumChoiceField
(
default
=
wagtailvideos
.
models
.
VideoQuality
(
1
),
enum_class
=
wagtailvideos
.
models
.
VideoQuality
,
max_length
=
7
)),
(
'processing'
,
models
.
BooleanField
(
default
=
False
)),
(
'file'
,
models
.
FileField
(
blank
=
True
,
null
=
True
,
upload_to
=
wagtailvideos
.
models
.
get_upload_to
,
verbose_name
=
'file'
)),
(
'error_message'
,
models
.
TextField
(
blank
=
True
)),
(
'video'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
related_name
=
'transcodes'
,
to
=
'app.CustomVideoModel'
)),
],
options
=
{
'unique_together'
:
{(
'video'
,
'media_format'
)},
},
),
]
tests/app/models.py
View file @
7a4cf265
...
...
@@ -5,6 +5,30 @@ from wagtail.admin.edit_handlers import StreamFieldPanel
from
wagtailvideos.edit_handlers
import
VideoChooserPanel
from
wagtailvideos.blocks
import
VideoChooserBlock
from
wagtailvideos.models
import
AbstractVideo
,
AbstractVideoTranscode
class
CustomVideoModel
(
AbstractVideo
):
attribution
=
models
.
TextField
()
admin_form_fields
=
(
'title'
,
'attribution'
,
'file'
,
'collection'
,
'thumbnail'
,
'tags'
,
)
class
CustomVideoTranscode
(
AbstractVideoTranscode
):
video
=
models
.
ForeignKey
(
CustomVideoModel
,
related_name
=
'transcodes'
,
on_delete
=
models
.
CASCADE
)
class
Meta
:
unique_together
=
(
(
'video'
,
'media_format'
)
)
class
TestPage
(
Page
):
video_field
=
models
.
ForeignKey
(
...
...
tests/test_custom_model.py
0 → 100644
View file @
7a4cf265
from
django.core.exceptions
import
ImproperlyConfigured
from
django.test
import
TestCase
,
override_settings
from
wagtail.tests.utils
import
WagtailTestUtils
from
wagtailvideos
import
get_video_model
,
get_video_model_string
from
wagtailvideos.models
import
Video
from
tests.app.models
import
CustomVideoModel
class
TestGetVideoModel
(
WagtailTestUtils
,
TestCase
):
@
override_settings
(
WAGTAILVIDEOS_VIDEO_MODEL
=
'app.CustomVideoModel'
)
def
test_custom_get_video_model
(
self
):
self
.
assertIs
(
get_video_model
(),
CustomVideoModel
)
@
override_settings
(
WAGTAILVIDEOS_VIDEO_MODEL
=
'app.CustomVideoModel'
)
def
test_custom_get_video_model_string
(
self
):
self
.
assertEqual
(
get_video_model_string
(),
'app.CustomVideoModel'
)
def
test_standard_get_video_model
(
self
):
self
.
assertIs
(
get_video_model
(),
Video
)
def
test_standard_get_video_model_string
(
self
):
self
.
assertEqual
(
get_video_model_string
(),
'wagtailvideos.Video'
)
@
override_settings
(
WAGTAILVIDEOS_VIDEO_MODEL
=
'app.UnknownModel'
)
def
test_unknown_get_video_model
(
self
):
with
self
.
assertRaises
(
ImproperlyConfigured
):
get_video_model
()
@
override_settings
(
WAGTAILVIDEOS_VIDEO_MODEL
=
'invalid-string'
)
def
test_invalid_get_video_model
(
self
):
with
self
.
assertRaises
(
ImproperlyConfigured
):
get_video_model
()
\ No newline at end of file
wagtailvideos/__init__.py
View file @
7a4cf265
from
django.conf
import
settings
from
django.core.exceptions
import
ImproperlyConfigured
default_app_config
=
'wagtailvideos.apps.WagtailVideosApp'
def
get_video_model_string
():
return
getattr
(
settings
,
'WAGTAILVIDEOS_VIDEO_MODEL'
,
'wagtailvideos.Video'
)
def
get_video_model
():
from
django.apps
import
apps
model_string
=
get_video_model_string
()
try
:
return
apps
.
get_model
(
model_string
)
except
ValueError
:
raise
ImproperlyConfigured
(
"WAGTAILVIDEOS_VIDEO_MODEL must be of the form 'app_label.model_name'"
)
except
LookupError
:
raise
ImproperlyConfigured
(
"WAGTAILVIDEOS_VIDEO_MODEL refers to model '%s' that has not been installed"
%
model_string
)
\ No newline at end of file
wagtailvideos/blocks.py
View file @
7a4cf265
from
wagtail.core.blocks
import
ChooserBlock
from
django.utils.functional
import
cached_property
class
VideoChooserBlock
(
ChooserBlock
):
@
cached_property
def
target_model
(
self
):
from
wagtailvideos
.models
import
Video
return
Video
from
wagtailvideos
import
get_video_model
return
get_video_model
()
@
cached_property
def
widget
(
self
):
...
...
wagtailvideos/jinja2tags.py
View file @
7a4cf265
from
jinja2.ext
import
Extension
from
.models
import
Video
from
.
import
get_video_model
Video
=
get_video_model
()
def
video
(
video
,
**
attrs
):
...
...
wagtailvideos/models.py
View file @
7a4cf265
...
...
@@ -19,10 +19,9 @@ from django.db.models.signals import post_save, pre_delete
from
django.dispatch.dispatcher
import
receiver
from
django.forms.utils
import
flatatt
from
django.urls
import
reverse
from
django.utils.
html
import
mark_safe
from
django.utils.
safestring
import
mark_safe
from
django.utils.translation
import
ugettext_lazy
as
_
from
enumchoicefield
import
ChoiceEnum
,
EnumChoiceField
from
six
import
python_2_unicode_compatible
from
taggit.managers
import
TaggableManager
from
wagtail.core.models
import
CollectionMember
from
wagtail.search
import
index
...
...
@@ -79,7 +78,6 @@ def get_upload_to(instance, filename):
return
instance
.
get_upload_to
(
filename
)
@
python_2_unicode_compatible
class
AbstractVideo
(
CollectionMember
,
index
.
Indexed
,
models
.
Model
):
title
=
models
.
CharField
(
max_length
=
255
,
verbose_name
=
_
(
'title'
))
file
=
models
.
FileField
(
...
...
wagtailvideos/permissions.py
View file @
7a4cf265
from
wagtail.core.permission_policies.collections
import
(
CollectionOwnershipPermissionPolicy
)
from
wagtailvideos
import
get_video_model
from
wagtailvideos.models
import
Video
permission_policy
=
CollectionOwnershipPermissionPolicy
(
Video
,
get_video_model
()
,
auth_model
=
Video
,
owner_field_name
=
'uploaded_by_user'
)
wagtailvideos/views/chooser.py
View file @
7a4cf265
...
...
@@ -11,7 +11,7 @@ from wagtail.images.views.chooser import get_chooser_js_data
from
wagtail.search
import
index
as
search_index
from
wagtailvideos.forms
import
get_video_form
from
wagtailvideos
.models
import
Video
from
wagtailvideos
import
get_video_model
from
wagtailvideos.permissions
import
permission_policy
if
LooseVersion
(
wagtail
.
__version__
)
>=
LooseVersion
(
'2.7'
):
...
...
@@ -41,6 +41,7 @@ def get_video_json(video):
def
chooser
(
request
):
Video
=
get_video_model
()
VideoForm
=
get_video_form
(
Video
)
uploadform
=
VideoForm
()
...
...
@@ -101,7 +102,7 @@ def chooser(request):
def
video_chosen
(
request
,
video_id
):
video
=
get_object_or_404
(
Video
,
id
=
video_id
)
video
=
get_object_or_404
(
get_video_model
()
,
id
=
video_id
)
return
render_modal_workflow
(
request
,
None
,
json_data
=
{
...
...
@@ -112,6 +113,7 @@ def video_chosen(request, video_id):
@
permission_checker
.
require
(
'add'
)
def
chooser_upload
(
request
):
Video
=
get_video_model
()
VideoForm
=
get_video_form
(
Video
)
searchform
=
SearchForm
()
...
...
wagtailvideos/views/multiple.py
View file @
7a4cf265
...
...
@@ -10,7 +10,7 @@ from django.views.decorators.vary import vary_on_headers
from
wagtail.search.backends
import
get_search_backends
from
wagtailvideos.forms
import
get_video_form
from
wagtailvideos
.models
import
Video
from
wagtailvideos
import
get_video_model
from
wagtailvideos.permissions
import
permission_policy
if
LooseVersion
(
wagtail
.
__version__
)
>=
LooseVersion
(
'2.7'
):
...
...
@@ -37,6 +37,7 @@ 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,6 +99,7 @@ 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
)
...
...
@@ -133,7 +135,7 @@ def edit(request, video_id, callback=None):
@
require_POST
def
delete
(
request
,
video_id
):
video
=
get_object_or_404
(
Video
,
id
=
video_id
)
video
=
get_object_or_404
(
get_video_model
()
,
id
=
video_id
)
if
not
request
.
is_ajax
():
return
HttpResponseBadRequest
(
"Cannot POST to this view without AJAX"
)
...
...
wagtailvideos/views/videos.py
View file @
7a4cf265
...
...
@@ -12,9 +12,8 @@ from wagtail.admin.forms.search import SearchForm
from
wagtail.core.models
import
Collection
from
wagtail.search.backends
import
get_search_backends
from
wagtailvideos
import
ffmpeg
from
wagtailvideos
import
ffmpeg
,
get_video_model
from
wagtailvideos.forms
import
VideoTranscodeAdminForm
,
get_video_form
from
wagtailvideos.models
import
Video
from
wagtailvideos.permissions
import
permission_policy
if
LooseVersion
(
wagtail
.
__version__
)
>=
LooseVersion
(
'2.7'
):
...
...
@@ -31,6 +30,7 @@ permission_checker = PermissionPolicyChecker(permission_policy)
@
vary_on_headers
(
'X-Requested-With'
)
def
index
(
request
):
# Get Videos (filtered by user permission)
Video
=
get_video_model
()
videos
=
Video
.
objects
.
all
()
# Search
...
...
@@ -80,6 +80,7 @@ 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
)
...
...
@@ -134,7 +135,7 @@ def edit(request, video_id):
def
create_transcode
(
request
,
video_id
):
if
request
.
method
!=
'POST'
:
return
HttpResponseNotAllowed
([
'POST'
])
video
=
get_object_or_404
(
Video
,
id
=
video_id
)
video
=
get_object_or_404
(
get_video_model
()
,
id
=
video_id
)
transcode_form
=
VideoTranscodeAdminForm
(
data
=
request
.
POST
,
video
=
video
)
if
transcode_form
.
is_valid
():
...
...
@@ -144,7 +145,7 @@ def create_transcode(request, video_id):
@
permission_checker
.
require
(
'delete'
)
def
delete
(
request
,
video_id
):
video
=
get_object_or_404
(
Video
,
id
=
video_id
)
video
=
get_object_or_404
(
get_video_model
()
,
id
=
video_id
)
if
request
.
POST
:
video
.
delete
()
...
...
@@ -158,6 +159,7 @@ def delete(request, video_id):
@
permission_checker
.
require
(
'add'
)
def
add
(
request
):
Video
=
get_video_model
()
VideoForm
=
get_video_form
(
Video
)
if
request
.
POST
:
...
...
@@ -188,7 +190,7 @@ def add(request):
def
usage
(
request
,
image_id
):
image
=
get_object_or_404
(
Video
,
id
=
image_id
)
image
=
get_object_or_404
(
get_video_model
()
,
id
=
image_id
)
paginator
=
Paginator
(
image
.
get_usage
(),
per_page
=
12
)
page
=
paginator
.
get_page
(
request
.
GET
.
get
(
'p'
))
...
...
wagtailvideos/wagtail_hooks.py
View file @
7a4cf265
...
...
@@ -10,10 +10,12 @@ from django.utils.html import format_html
from
django.templatetags.static
import
static
from
wagtailvideos
import
urls
from
wagtailvideos.forms
import
GroupVideoPermissionFormSet
from
wagtailvideos
.models
import
Video
from
wagtailvideos
import
get_video_model
from
.permissions
import
permission_policy
Video
=
get_video_model
()
@
hooks
.
register
(
'register_admin_urls'
)
def
register_admin_urls
():
...
...
wagtailvideos/widgets.py
View file @
7a4cf265
...
...
@@ -4,7 +4,7 @@ from django.template.loader import render_to_string
from
django.utils.translation
import
ugettext_lazy
as
_
from
wagtail.admin.widgets
import
AdminChooser
from
wagtailvideos
.models
import
Video
from
wagtailvideos
import
get_video_model
class
AdminVideoChooser
(
AdminChooser
):
...
...
@@ -14,7 +14,7 @@ class AdminVideoChooser(AdminChooser):
def
__init__
(
self
,
**
kwargs
):
super
(
AdminVideoChooser
,
self
).
__init__
(
**
kwargs
)
self
.
video_model
=
Video
self
.
video_model
=
get_video_model
()
def
render_html
(
self
,
name
,
value
,
attrs
):
instance
,
value
=
self
.
get_instance_and_id
(
self
.
video_model
,
value
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment