Skip to content

Commit

Permalink
handle different seervices other than youtube
Browse files Browse the repository at this point in the history
  • Loading branch information
cekk committed Jan 10, 2024
1 parent b1a5e78 commit aa1b317
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 81 deletions.
36 changes: 36 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,42 @@ YouTube API Support
Since version 2.0, YouTube integration is supported.
Videos can automatically be uploaded to a configured YouTube account.

Video Adapter - Support for various external services
-----------------------------------------------------

With the help of adapters it's now possible to embed videos
from different sources other than YouTube.

By default only YouTube adapter is registered. If you need to provide a new provider, just register an adapter like this::

<adapter
factory = ".foo_adapter.FooVideoEmbedCode"
name = "foo.com" />

And the code should be something like this::
from wildcard.video.adapters.video_embed_code import BaseEmbedCode
from wildcard.media.interfaces import IVideoEmbedCode
from wildcard.media.interfaces import IVideoEnabled
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
from zope.interface import implementer
from zope.interface import Interface
from zope.component import adapter


@implementer(IVideoEmbedCode)
@adapter(IVideoEnabled, Interface)
class FooVideoEmbedCode(BaseEmbedCode):
template = ViewPageTemplateFile("foo_template.pt")

The template file is the html snippet used for embedding the video.
The name of the adapter is the domain name of the streaming service.

If you set a video_url like "https://foo.com/videos/123456", the adapter with name "foo.com" will be used.
If the service uses more domains (for example youtube.com or youtu.be), you need to register several adapters for each domain.

If you link a direct link to an mp4 file, a default adapter will be used.


Install
~~~~~~~

Expand Down
7 changes: 7 additions & 0 deletions docs/HISTORY.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ Changelog

- Reintroduce support for partial streaming based on https://github.com/plone/plone.namedfile/pull/86 [pbauer]

- Now it's possible to use external services other than YouTube with the help of
adapter views for video contents.
[arsenico13, cekk]

- [BREAKING] Change attribute name for WildcardVideo contentype: youtube_url has
been changed in video_url (upgrade step available).
[arsenico13, cekk]

2.1.0 (2020-02-06)
------------------
Expand Down
12 changes: 8 additions & 4 deletions wildcard/media/adapters/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@
xmlns:five="http://namespaces.zope.org/five"
xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="wildcard.media">


<!-- Default video adapter -->
<adapter
factory = ".video_embed_code.DefaultVideoEmbedCode"/>

<!-- Internal video adapter -->
<adapter
factory = ".videoembedcode.VideoEmbedCode"
factory = ".video_embed_code.InternalVideoEmbedCode"
name = "internal" />

<!-- Youtube video adapter -->
<adapter
factory = ".videoembedcode.ClassicYoutubeEmbedCode"
factory = ".video_embed_code.YoutubeVideoEmbedCode"
name = "youtube.com" />

<adapter
factory = ".videoembedcode.ClassicYoutubeEmbedCode"
factory = ".video_embed_code.YoutubeVideoEmbedCode"
name = "youtu.be" />


Expand Down
19 changes: 19 additions & 0 deletions wildcard/media/adapters/templates/default_template.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="wcvideo-container default-player" tal:define="util context/@@wcmedia-utils;
settings util/settings;
video nocall: video|context;
height height|video/height|settings/default_video_height|string:720;
width width|video/width|settings/default_video_width|string:400;
video_url video/video_url">

<video width="320"
height="240"
controls="controls"
preload="none"
class="active pat-media"
tal:attributes="width width;
height height;">
<source src="${video_url}" />
</video>


</div>
32 changes: 32 additions & 0 deletions wildcard/media/adapters/templates/internal_video_template.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="wcvideo-container internal-video-player" tal:define="util context/@@wcmedia-utils;
settings util/settings;
video nocall: video|context;
height height|video/height|settings/default_video_height|string:720;
width width|video/width|settings/default_video_width|string:400;
upload_to_youtube video/upload_video_to_youtube|nothing;
video_url view/get_embed_url|nothing">


<video width="320" height="240" poster="poster.jpg" controls="controls" preload="none" class="active pat-media" tal:attributes="poster util/image_url;
width width;
height height;">
<tal:videos tal:repeat="video python:util.videos()">
<source src="/media/echo-hereweare.mp4" type="video/mp4" tal:attributes="src video/url;
type string:video/${video/type}" />
</tal:videos>
<track kind="subtitles" src="subtitles.srt" srclang="en" tal:condition="util/subtitles_url" tal:attributes="src util/subtitles_url" />
<object width="320" height="240" type="application/x-shockwave-flash" data="flashmediaelement.swf" tal:attributes="data string:${util/mstatic}/flashmediaelement.swf;
width width;
height height;">
<param name="movie" value="flashmediaelement.swf" tal:attributes="value string:${util/mstatic}/flashmediaelement.swf"/>
<param name="flashvars" value="controls=true&file=myvideo.mp4" tal:attributes="value string:controls=true&file=${util/mp4_url_quoted}&poster=${util/image_url_quoted};" />
<param name="allowFullScreen" value="true" />
<img src="myvideo.jpg" width="320" height="240" title="No video playback capabilities" tal:condition="util/image_url" tal:attributes="src util/image_url;
title video/Title;
width width;
height height;"/>
</object>
</video>


</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="wcvideo-container" tal:define="util context/@@wcmedia-utils;
<div class="wcvideo-container youtube-player" tal:define="util context/@@wcmedia-utils;
settings util/settings;
video nocall: video|context;
height height|video/height|settings/default_video_height|string:720;
Expand Down
21 changes: 16 additions & 5 deletions wildcard/media/adapters/video_embed_code.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from urlparse import urlparse
from wildcard.media.behavior import IVideo
from wildcard.media.interfaces import IVideoEmbedCode
from wildcard.media.interfaces import IVideoEnabled
Expand All @@ -9,6 +8,12 @@
from zope.interface import Interface
from zope.component import adapter

try:
# Python 3
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse


@implementer(IVideoEmbedCode)
@adapter(IVideoEnabled, Interface)
Expand All @@ -23,14 +28,20 @@ def __call__(self):
return self.template()


class VideoEmbedCode(BaseEmbedCode):
class DefaultVideoEmbedCode(BaseEmbedCode):
""""""

template = ViewPageTemplateFile("templates/default_template.pt")


class InternalVideoEmbedCode(BaseEmbedCode):
"""Internal video adapter"""

template = ViewPageTemplateFile("templates/internalvideo_template.pt")
template = ViewPageTemplateFile("templates/internal_video_template.pt")


class ClassicYoutubeEmbedCode(BaseEmbedCode):
"""ClassicYoutubeEmbedCode
class YoutubeVideoEmbedCode(BaseEmbedCode):
"""
Provides a way to have the html code to embed Youtube video in a web page
"""

Expand Down
10 changes: 4 additions & 6 deletions wildcard/media/behavior.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ def valid_audio(namedblob):
return True


def getDefaultWidth():
def getDefaultWidth(context=None):
portal = getSite()
settings = GlobalSettings(portal)
return settings.default_video_width


def getDefaultHeight():
def getDefaultHeight(context=None):
portal = getSite()
settings = GlobalSettings(portal)
return settings.default_video_height
Expand Down Expand Up @@ -133,7 +133,6 @@ def validate_videos(data):
default_mime_type="text/html",
output_mime_type="text/html",
allowed_mime_types=("text/html", "text/plain"),
default="",
required=False,
)

Expand All @@ -157,7 +156,6 @@ class IAudio(model.Schema):
default_mime_type="text/html",
output_mime_type="text/html",
allowed_mime_types=("text/html", "text/plain"),
default="",
required=False,
)

Expand Down Expand Up @@ -244,11 +242,11 @@ def _set_video_file(self, value):
def get_youtube_id_from_url(self):
if not getattr(self.context, "video_url", None):
return ""
pattern = r"((?<=(v|V)/)|(?<=be/)|(?<=(\?|\&)v=)|(?<=embed/))([\w-]+)"
pattern = r"(youtu.*be.*)\/(watch\?v=|embed\/|v|shorts|)(.*?((?=[&#?])|$))"
match = re.search(pattern, self.context.video_url)
if not match:
return ""
return match.group()
return match.groups()[2]

video_file = property(_get_video_file, _set_video_file)

Expand Down
43 changes: 27 additions & 16 deletions wildcard/media/browser/views.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error

from plone import api
from plone.memoize.instance import memoize
from plone.z3cform.layout import wrap_form
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone import PloneMessageFactory as pmf
from Products.Five import BrowserView
from plone import api
from plone.z3cform.layout import wrap_form
from plone.memoize.instance import memoize
from wildcard.media import _
from wildcard.media.behavior import IVideo
from wildcard.media.config import getFormat
from wildcard.media.interfaces import IGlobalMediaSettings
from wildcard.media.interfaces import IMediaEnabled
from wildcard.media.interfaces import IVideoEmbedCode
from wildcard.media.settings import GlobalSettings
from wildcard.media.subscribers import video_edited
from z3c.form import button
from z3c.form import field
from z3c.form import form
from z3c.form import group
from zope.component import getMultiAdapter, ComponentLookupError
from zope.component.hooks import getSite
from zope.interface import alsoProvides
from zope.component import getMultiAdapter, ComponentLookupError
from wildcard.media.adapter import IVideoEmbedCode
from urlparse import urlparse


import logging
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error

try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse

try:
from wildcard.media import youtube
Expand All @@ -33,6 +39,9 @@
from zope.interface import Interface as IDisableCSRFProtection # noqa


logger = logging.getLogger(__name__)


class MediaView(BrowserView):
@property
@memoize
Expand Down Expand Up @@ -81,10 +90,6 @@ def get_edit_url(self):
url = "%s/@@edit" % self.context.absolute_url()
return addTokenToUrl(url)

def get_site_id(self):
video_site = urlparse(self.context.video_url)[1].replace("www.", "")
return video_site

def get_player_code(self):
"""Fetch the correct adapter for the Video.
The video can be internal (inside the Plone site) or from an
Expand All @@ -95,18 +100,24 @@ def get_player_code(self):
util = getMultiAdapter((self.context, self.request), name="wcmedia-utils")
if util.mp4_url():
name = "internal"

# Extract the domain from the URL of the video. We use it as the
# name for the different adapters that handle different external services.
else:
# Extract the domain from the URL of the video. We use it as the
# name for the different adapters that handle different external services.
name = urlparse(self.context.video_url)[1].replace("www.", "")

try:
adapter = getMultiAdapter(
(self.context, self.request), IVideoEmbedCode, name=name
)
except ComponentLookupError:
# use default one
adapter = getMultiAdapter((self.context, self.request), IVideoEmbedCode)
if not adapter:
logger.warning(
'No adapter with name "{}" for {}.'.format(
name, self.context.absolute_url()
)
)
return ""
return adapter()


Expand Down
1 change: 1 addition & 0 deletions wildcard/media/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
Products.DCWorkflow.interfaces.IAfterTransitionEvent"
handler=".subscribers.video_state_changed" />

<include package=".adapters" />
<include package=".browser" />
<include file="profiles.zcml" />
<include package=".tiles" file="configure.zcml" zcml:condition="installed collective.cover"/>
Expand Down
Loading

0 comments on commit aa1b317

Please sign in to comment.