mirror of
https://github.com/Hopiu/django-embed-video.git
synced 2026-05-10 21:53:12 +00:00
Merge commit '0fdc6a3df75813235a4d6beafc250dcb3d3cfabd'
This commit is contained in:
commit
319f8afbda
9 changed files with 237 additions and 119 deletions
|
|
@ -4,6 +4,7 @@ python:
|
|||
env:
|
||||
- DJANGO_VERSION=1.4.5
|
||||
- DJANGO_VERSION=1.5.1
|
||||
- DJANGO_VERSION=1.5.2
|
||||
install:
|
||||
- pip install -q Django==$DJANGO_VERSION --use-mirrors
|
||||
- pip install coveralls --use-mirrors
|
||||
|
|
|
|||
26
CHANGES.rst
26
CHANGES.rst
|
|
@ -1,6 +1,32 @@
|
|||
Changes
|
||||
*******
|
||||
|
||||
0.3
|
||||
------
|
||||
|
||||
- Security fix: faked urls are treated as invalid. See `this page
|
||||
<https://github.com/yetty/django-embed-video/commit/d0d357b767e324a7cc21b5035357fdfbc7c8ce8e>`_
|
||||
for more details.
|
||||
|
||||
- Fixes:
|
||||
|
||||
- allow of empty video field.
|
||||
|
||||
- requirements in setup.py
|
||||
|
||||
- Added simplier way to embed video in one-line template tag::
|
||||
|
||||
{{ 'http://www.youtube.com/watch?v=guXyvo2FfLs'|embed:'large' }}
|
||||
|
||||
- ``backend`` variable in ``video`` template tag.
|
||||
|
||||
Usage::
|
||||
|
||||
{% video item.video as my_video %}
|
||||
Backend: {{ my_video.backend }}
|
||||
{% endvideo %}
|
||||
|
||||
|
||||
0.2
|
||||
-----
|
||||
|
||||
|
|
|
|||
15
README.rst
15
README.rst
|
|
@ -65,6 +65,7 @@ Usage of variables:
|
|||
{% video item.video as my_video %}
|
||||
URL: {{ my_video.url }}
|
||||
Thumbnail: {{ my_video.thumbnail }}
|
||||
Backend: {{ my_video.backend }}
|
||||
{% endvideo %}
|
||||
|
||||
|
||||
|
|
@ -111,7 +112,15 @@ TODO
|
|||
- Vimeo thumbnail
|
||||
|
||||
|
||||
|
||||
Websites using django-embed-video
|
||||
*********************************
|
||||
|
||||
- `Tchorici.cz <http://www.tchorici.cz>`_ (`sources
|
||||
<https://github.com/yetty/Tchorici/>`_)
|
||||
|
||||
*Are you using django-embed-video? Send pull request!*
|
||||
|
||||
|
||||
|
||||
.. vim: set tw=80:
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ import requests
|
|||
import json
|
||||
|
||||
DETECT_YOUTUBE = re.compile(
|
||||
# r'^(http(s)?://(www\.)?)?youtu(\.?)be(\.com)?.*', re.I
|
||||
r'(?:www.|)?youtu(\.?)be(\.com)?.*', re.I
|
||||
r'^(http(s)?://(www\.)?)?youtu(\.?)be(\.com)?/.*', re.I
|
||||
)
|
||||
DETECT_VIMEO = re.compile(
|
||||
r'^(http(s)?://(www\.)?)?vimeo\.com.*', re.I
|
||||
r'^(http(s)?://(www\.)?)?vimeo\.com/.*', re.I
|
||||
)
|
||||
DETECT_SOUNDCLOUD = re.compile(
|
||||
r'^(http(s)?://(www\.)?)?soundcloud\.com.*', re.I
|
||||
r'^(http(s)?://(www\.)?)?soundcloud\.com/.*', re.I
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ def detect_backend(url):
|
|||
elif DETECT_VIMEO.match(url):
|
||||
return VimeoBackend(url)
|
||||
elif DETECT_SOUNDCLOUD.match(url):
|
||||
return SoundCloundBackend(url)
|
||||
return SoundCloudBackend(url)
|
||||
else:
|
||||
raise UnknownBackendException
|
||||
|
||||
|
|
@ -38,6 +37,7 @@ class VideoBackend(object):
|
|||
def __init__(self, url):
|
||||
self._url = url
|
||||
|
||||
self.backend = self.__class__.__name__
|
||||
self.code = self.get_code()
|
||||
self.url = self.get_url()
|
||||
self.thumbnail = self.get_thumbnail_url()
|
||||
|
|
@ -54,7 +54,33 @@ class VideoBackend(object):
|
|||
return self.pattern_thumbnail_url % self.code
|
||||
|
||||
|
||||
class SoundCloundBackend(VideoBackend):
|
||||
class YoutubeBackend(VideoBackend):
|
||||
re_code = re.compile(
|
||||
r'youtu(?:be\.com/watch\?v=|\.be/)(?P<code>[\w-]*)(&(amp;)?[\w\?=]*)?',
|
||||
re.I
|
||||
)
|
||||
pattern_url = 'http://www.youtube.com/embed/%s?wmode=opaque'
|
||||
pattern_thumbnail_url = 'http://img.youtube.com/vi/%s/hqdefault.jpg'
|
||||
|
||||
def get_code(self):
|
||||
code = super(YoutubeBackend, self).get_code()
|
||||
|
||||
if not code:
|
||||
parse_data = urlparse.urlparse(self._url)
|
||||
code = urlparse.parse_qs(parse_data.query)['v'][0]
|
||||
|
||||
return code
|
||||
|
||||
|
||||
class VimeoBackend(VideoBackend):
|
||||
re_code = re.compile(r'vimeo\.com/(?P<code>[0-9]+)', re.I)
|
||||
pattern_url = 'http://player.vimeo.com/video/%s'
|
||||
|
||||
def get_thumbnail_url(self):
|
||||
pass # not implemented
|
||||
|
||||
|
||||
class SoundCloudBackend(VideoBackend):
|
||||
base_url = 'http://soundcloud.com/oembed'
|
||||
|
||||
re_code = re.compile(r'src=".*%2F(?P<code>\d+)&show_artwork.*"', re.I)
|
||||
|
|
@ -72,7 +98,7 @@ class SoundCloundBackend(VideoBackend):
|
|||
self.width = self.response.get('width')
|
||||
self.height = self.response.get('height')
|
||||
|
||||
super(SoundCloundBackend, self).__init__(url)
|
||||
super(SoundCloudBackend, self).__init__(url)
|
||||
|
||||
def get_thumbnail_url(self):
|
||||
return self.response.get('thumbnail_url')
|
||||
|
|
@ -84,34 +110,3 @@ class SoundCloundBackend(VideoBackend):
|
|||
def get_code(self):
|
||||
match = self.re_code.search(self.response.get('html'))
|
||||
return match.group('code')
|
||||
|
||||
|
||||
class YoutubeBackend(VideoBackend):
|
||||
re_code = re.compile(
|
||||
r'(?:http|https|)(?::\/\/|)(?:www.|)(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\/ytscreeningroom\?v=|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))(?P<code>[\w\-]{11})[a-z0-9;:@?&%=+\/\$_.-]*',
|
||||
# r'(?:http|https|)(?::\/\/|)(?:www.|)(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\/ytscreeningroom\?v=|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))(?P<code>[\w\-]{11})[a-z0-9;:@?&%=+\/\$_.-]*',
|
||||
# r'youtu(?:be\.com/watch\?v=|\.be/)(?P<code>[\w-]*)(&(amp;)?[\w\?=]*)?',
|
||||
re.I
|
||||
)
|
||||
pattern_url = 'http://www.youtube.com/embed/%s?wmode=opaque'
|
||||
pattern_thumbnail_url = 'http://img.youtube.com/vi/%s/hqdefault.jpg'
|
||||
|
||||
def get_code(self):
|
||||
code = super(YoutubeBackend, self).get_code()
|
||||
|
||||
if not code:
|
||||
parse_data = urlparse.urlparse(self._url)
|
||||
try:
|
||||
code = urlparse.parse_qs(parse_data.query)['v'][0]
|
||||
except KeyError:
|
||||
raise UnknownIdException
|
||||
|
||||
return code
|
||||
|
||||
|
||||
class VimeoBackend(VideoBackend):
|
||||
re_code = re.compile(r'vimeo\.com/(?P<code>[0-9]+)', re.I)
|
||||
pattern_url = 'http://player.vimeo.com/video/%s'
|
||||
|
||||
def get_thumbnail_url(self):
|
||||
pass # not implemented
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils.safestring import mark_safe, SafeText
|
||||
|
||||
from ..base import detect_backend, SoundCloundBackend
|
||||
from ..base import detect_backend, SoundCloudBackend
|
||||
|
||||
register = Library()
|
||||
|
||||
|
|
@ -43,6 +43,17 @@ def embed(backend, _size='small'):
|
|||
if isinstance(backend, SafeText):
|
||||
backend = detect_backend(backend)
|
||||
|
||||
size = _embed_get_size(_size)
|
||||
params = _embed_get_params(backend, size)
|
||||
|
||||
return mark_safe(
|
||||
'<iframe width="%(width)d" height="%(height)d" '
|
||||
'src="%(url)s" frameborder="0" allowfullscreen>'
|
||||
'</iframe>' % params
|
||||
)
|
||||
|
||||
|
||||
def _embed_get_size(size):
|
||||
sizes = {
|
||||
'tiny': (420, 315),
|
||||
'small': (480, 360),
|
||||
|
|
@ -51,22 +62,22 @@ def embed(backend, _size='small'):
|
|||
'huge': (1280, 960),
|
||||
}
|
||||
|
||||
if _size in sizes:
|
||||
size = sizes[_size]
|
||||
elif 'x' in _size:
|
||||
size = _size.split('x')
|
||||
if size in sizes:
|
||||
return sizes[size]
|
||||
elif 'x' in size:
|
||||
return [int(x) for x in size.split('x')]
|
||||
|
||||
|
||||
def _embed_get_params(backend, size):
|
||||
params = {
|
||||
'url': backend.url,
|
||||
'width': int(size[0]),
|
||||
'height': int(size[1]),
|
||||
'width': size[0],
|
||||
'height': size[1],
|
||||
}
|
||||
|
||||
if isinstance(backend, SoundCloundBackend):
|
||||
if isinstance(backend, SoundCloudBackend):
|
||||
params.update({'height': backend.height})
|
||||
|
||||
return mark_safe(
|
||||
'<iframe width="%(width)d" height="%(height)d" '
|
||||
'src="%(url)s" frameborder="0" allowfullscreen>'
|
||||
'</iframe>' % params
|
||||
)
|
||||
return params
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
from unittest import TestCase
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.template.base import Template
|
||||
from django.template.context import RequestContext
|
||||
|
||||
from ..base import detect_backend, YoutubeBackend, VimeoBackend, \
|
||||
SoundCloundBackend
|
||||
SoundCloudBackend, UnknownBackendException
|
||||
|
||||
|
||||
class EmbedVideoTestCase(TestCase):
|
||||
unknown_backend_urls = (
|
||||
'http://myurl.com/?video=http://www.youtube.com/watch?v=jsrRJyHBvzw',
|
||||
'http://myurl.com/?video=www.youtube.com/watch?v=jsrRJyHBvzw',
|
||||
'http://youtube.com.myurl.com/watch?v=jsrRJyHBvzw',
|
||||
'http://vimeo.com.myurl.com/66577491',
|
||||
)
|
||||
|
||||
youtube_urls = (
|
||||
('http://www.youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('http://youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
|
|
@ -36,61 +39,9 @@ class EmbedVideoTestCase(TestCase):
|
|||
from django.conf import settings as django_settings
|
||||
self.django_settings = django_settings
|
||||
|
||||
def _grc(self):
|
||||
return RequestContext(HttpRequest())
|
||||
|
||||
def test_embed(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb|embed:'large' }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = u'<iframe width="960" height="720" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_direct_embed(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{{ 'http://www.youtube.com/watch?v=jsrRJyHBvzw'|embed:'large' }}
|
||||
""")
|
||||
rendered = u'<iframe width="960" height="720" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_embed_user_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb|embed:'800x800' }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = u'<iframe width="800" height="800" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_youtube(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_vimeo(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://vimeo.com/66577491' as vimeo %}
|
||||
{{ vimeo.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://player.vimeo.com/video/66577491'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
def test_detect_bad_urls(self):
|
||||
for url in self.unknown_backend_urls:
|
||||
self.assertRaises(UnknownBackendException, detect_backend, url)
|
||||
|
||||
def test_detect_youtube(self):
|
||||
for url in self.youtube_urls:
|
||||
|
|
@ -105,7 +56,7 @@ class EmbedVideoTestCase(TestCase):
|
|||
def test_detect_soundcloud(self):
|
||||
for url in self.soundcloud_urls:
|
||||
backend = detect_backend(url[0])
|
||||
self.assertIsInstance(backend, SoundCloundBackend)
|
||||
self.assertIsInstance(backend, SoundCloudBackend)
|
||||
|
||||
def test_code_youtube(self):
|
||||
for url in self.youtube_urls:
|
||||
|
|
@ -121,6 +72,6 @@ class EmbedVideoTestCase(TestCase):
|
|||
|
||||
def test_code_soundcloud(self):
|
||||
for url in self.soundcloud_urls:
|
||||
backend = SoundCloundBackend(url[0])
|
||||
backend = SoundCloudBackend(url[0])
|
||||
code = backend.get_code()
|
||||
self.assertEqual(code, url[1])
|
||||
|
|
|
|||
|
|
@ -39,3 +39,9 @@ class EmbedVideoFormFieldTestCase(TestCase):
|
|||
mock_detect_backend.side_effect = UnknownIdException
|
||||
self.assertRaises(ValidationError, self.formfield.validate,
|
||||
('http://youtube.com/v/123/',))
|
||||
|
||||
def test_validation_correct(self):
|
||||
url = 'http://my-testing.url.com'
|
||||
with patch('embed_video.fields.detect_backend') as mock_detect_backend:
|
||||
mock_detect_backend.return_value = True
|
||||
self.assertEqual(url, self.formfield.validate(url))
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@ from unittest import TestCase
|
|||
from mock import Mock
|
||||
|
||||
from django.template import TemplateSyntaxError
|
||||
from django.http import HttpRequest
|
||||
from django.template.base import Template
|
||||
from django.template.context import RequestContext
|
||||
|
||||
from ..templatetags.embed_video_tags import VideoNode
|
||||
from embed_video.base import YoutubeBackend, SoundCloudBackend
|
||||
from embed_video.templatetags.embed_video_tags import VideoNode, \
|
||||
_embed_get_size, _embed_get_params
|
||||
|
||||
|
||||
class EmbedVideoNodeTestCase(TestCase):
|
||||
|
|
@ -11,11 +16,97 @@ class EmbedVideoNodeTestCase(TestCase):
|
|||
self.parser = Mock()
|
||||
self.token = Mock(methods=['split_contents'])
|
||||
|
||||
def _grc(self):
|
||||
return RequestContext(HttpRequest())
|
||||
|
||||
def test_embed(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb|embed:'large' }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = u'<iframe width="960" height="720" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_direct_embed(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{{ 'http://www.youtube.com/watch?v=jsrRJyHBvzw'|embed:'large' }}
|
||||
""")
|
||||
rendered = u'<iframe width="960" height="720" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_embed_user_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb|embed:'800x800' }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = u'<iframe width="800" height="800" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_youtube(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_vimeo(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://vimeo.com/66577491' as vimeo %}
|
||||
{{ vimeo.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://player.vimeo.com/video/66577491'
|
||||
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_backend_variable_vimeo(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://vimeo.com/66577491' as vimeo %}
|
||||
{{ vimeo.backend }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'VimeoBackend'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_backend_variable_youtube(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvz' as youtube %}
|
||||
{{ youtube.backend }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'YoutubeBackend'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_tag_backend_variable_soundcloud(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://soundcloud.com/glassnote/mumford-sons-i-will-wait' as soundcloud %}
|
||||
{{ soundcloud.backend }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'SoundCloudBackend'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_syntax_error(self):
|
||||
self.token.split_contents.return_value = []
|
||||
|
||||
try:
|
||||
instance = VideoNode(self.parser, self.token)
|
||||
VideoNode(self.parser, self.token)
|
||||
except TemplateSyntaxError:
|
||||
assert True
|
||||
|
||||
|
|
@ -28,4 +119,32 @@ class EmbedVideoNodeTestCase(TestCase):
|
|||
node = VideoNode(self.parser, self.token)
|
||||
self.assertEqual(str(node), '<VideoNode "some_url">')
|
||||
|
||||
def test_embed_get_params(self):
|
||||
url = 'http://youtu.be/13456'
|
||||
backend = YoutubeBackend(url)
|
||||
params = _embed_get_params(backend, (3, 8))
|
||||
|
||||
self.assertEqual('http://www.youtube.com/embed/13456?wmode=opaque', params['url'])
|
||||
self.assertEqual(3, params['width'])
|
||||
self.assertEqual(8, params['height'])
|
||||
|
||||
def test_embed_get_params_soundcloud_height(self):
|
||||
url = 'https://soundcloud.com/glassnote/mumford-sons-i-will-wait'
|
||||
backend = SoundCloudBackend(url)
|
||||
params = _embed_get_params(backend, (1, 2))
|
||||
|
||||
self.assertEqual(backend.height, params['height'])
|
||||
|
||||
def test_videonode_iter(self):
|
||||
out = ['a', 'b', 'c', 'd']
|
||||
|
||||
class FooNode(VideoNode):
|
||||
nodelist_file = out
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
node = FooNode()
|
||||
self.assertEqual(out, [x for x in node])
|
||||
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -12,7 +12,7 @@ CHANGES = read('CHANGES.rst')
|
|||
setup(
|
||||
name='django-embed-video',
|
||||
packages=find_packages(),
|
||||
version='0.2.3',
|
||||
version='0.3',
|
||||
author='Juda Kaleta',
|
||||
author_email='juda.kaleta@gmail.com',
|
||||
url='https://github.com/yetty/django-embed-video',
|
||||
|
|
|
|||
Loading…
Reference in a new issue