mirror of
https://github.com/Hopiu/django-embed-video.git
synced 2026-03-16 21:30:23 +00:00
Merge pull request #36 from yetty/I34-force-ssl
Closes #34. Options in embed tag.
This commit is contained in:
commit
45203418ff
19 changed files with 566 additions and 665 deletions
|
|
@ -1,6 +1,11 @@
|
|||
Release 1.0.0 (dev)
|
||||
-------------------
|
||||
|
||||
**Backward incompatible changes:**
|
||||
|
||||
- filter `embed_video_tags.embed` has been removed
|
||||
|
||||
Backward compatible changes:
|
||||
*No changes yet.*
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -48,34 +48,16 @@ Default sizes are ``tiny`` (420x315), ``small`` (480x360), ``medium`` (640x480),
|
|||
{% video my_video '100% x 50%' %}
|
||||
|
||||
|
||||
Some backends (e.g. YouTube) allow configuration of the embedding via passing
|
||||
query parameters. To specify the parameters:
|
||||
It is possible to set backend options via parameters in template tag. It is
|
||||
useful for example to enforce HTTPS protocol or set different query appended
|
||||
to url.
|
||||
|
||||
::
|
||||
|
||||
{% video item.video 'small' rel=0 %}
|
||||
|
||||
{% video item.video 'small' start=2 stop=5 repeat=1 %}
|
||||
|
||||
{% video item.video rel=0 as my_video %}
|
||||
URL: {{ my_video.url }}
|
||||
Thumbnail: {{ my_video.thumbnail }}
|
||||
Backend: {{ my_video.backend }}
|
||||
{% video my_video 'small' %}
|
||||
{% video my_video query="rel=0&wmode=transparent" is_secure=True %}
|
||||
{{ video.url }} {# always with https #}
|
||||
{% endvideo %}
|
||||
|
||||
Parameters may also be template variables:
|
||||
|
||||
::
|
||||
|
||||
{% video item.video 'small' start=item.start stop=item.stop repeat=item.repeat %}
|
||||
|
||||
|
||||
.. tip::
|
||||
|
||||
You can provide default values for the query string that's included in the
|
||||
embedded URL by updating your Django settings file.
|
||||
|
||||
|
||||
.. tip::
|
||||
|
||||
|
|
@ -96,7 +78,7 @@ Parameters may also be template variables:
|
|||
backend (:py:data:`~embed_video.backends.VideoBackend.template_name`).
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
||||
|
||||
``template_name`` has been added in version 0.9.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,21 @@
|
|||
import re
|
||||
import requests
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
|
||||
try:
|
||||
# Python <= 2.7
|
||||
import urlparse
|
||||
from urllib import urlencode
|
||||
except ImportError:
|
||||
# support for py3
|
||||
if sys.version_info.major == 3:
|
||||
import urllib.parse as urlparse
|
||||
from urllib.parse import urlencode
|
||||
else:
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import QueryDict
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.datastructures import SortedDict
|
||||
|
||||
from .utils import import_by_path
|
||||
from .settings import EMBED_VIDEO_BACKENDS, EMBED_VIDEO_TIMEOUT
|
||||
from .settings import EMBED_VIDEO_BACKENDS, EMBED_VIDEO_TIMEOUT, \
|
||||
EMBED_VIDEO_YOUTUBE_DEFAULT_QUERY
|
||||
|
||||
|
||||
class EmbedVideoException(Exception):
|
||||
|
|
@ -112,7 +109,12 @@ class VideoBackend(object):
|
|||
``{{ width }}``, ``{{ height }}``
|
||||
"""
|
||||
|
||||
def __init__(self, url, is_secure=False, query=None):
|
||||
default_query = ''
|
||||
"""
|
||||
Default query string or `QueryDict` appended to url
|
||||
"""
|
||||
|
||||
def __init__(self, url, is_secure=False):
|
||||
"""
|
||||
First it tries to load data from cache and if it don't succeed, run
|
||||
:py:meth:`init` and then save it to cache.
|
||||
|
|
@ -120,22 +122,17 @@ class VideoBackend(object):
|
|||
self.is_secure = is_secure
|
||||
self.backend = self.__class__.__name__
|
||||
self._url = url
|
||||
self.update_query(query)
|
||||
|
||||
def update_query(self, query=None):
|
||||
self._query = SortedDict(self.get_default_query())
|
||||
if query is not None:
|
||||
self._query.update(query)
|
||||
self.query = QueryDict(self.default_query, mutable=True)
|
||||
|
||||
@cached_property
|
||||
def code(self):
|
||||
return self.get_code()
|
||||
|
||||
@cached_property
|
||||
@property
|
||||
def url(self):
|
||||
return self.get_url()
|
||||
|
||||
@cached_property
|
||||
@property
|
||||
def protocol(self):
|
||||
return 'https' if self.allow_https and self.is_secure else 'http'
|
||||
|
||||
|
|
@ -147,6 +144,16 @@ class VideoBackend(object):
|
|||
def info(self):
|
||||
return self.get_info()
|
||||
|
||||
@property
|
||||
def query(self):
|
||||
return self._query
|
||||
|
||||
@query.setter
|
||||
def query(self, value):
|
||||
self._query = value \
|
||||
if isinstance(value, QueryDict) \
|
||||
else QueryDict(value, mutable=True)
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, url):
|
||||
"""
|
||||
|
|
@ -168,8 +175,7 @@ class VideoBackend(object):
|
|||
Returns URL folded from :py:data:`pattern_url` and parsed code.
|
||||
"""
|
||||
url = self.pattern_url.format(code=self.code, protocol=self.protocol)
|
||||
if self._query:
|
||||
url += '?' + urlencode(self._query, doseq=True)
|
||||
url += '?' + self.query.urlencode() if self.query else ''
|
||||
return mark_safe(url)
|
||||
|
||||
def get_thumbnail_url(self):
|
||||
|
|
@ -193,12 +199,9 @@ class VideoBackend(object):
|
|||
def get_info(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_default_query(self):
|
||||
# Derive backend name from class name
|
||||
backend_name = self.__class__.__name__[:-7].upper()
|
||||
default = getattr(self, 'default_query', {})
|
||||
settings_key = 'EMBED_VIDEO_{0}_QUERY'.format(backend_name)
|
||||
return getattr(settings, settings_key, default).copy()
|
||||
def set_options(self, options):
|
||||
for key in options:
|
||||
setattr(self, key, options[key])
|
||||
|
||||
|
||||
class YoutubeBackend(VideoBackend):
|
||||
|
|
@ -225,7 +228,7 @@ class YoutubeBackend(VideoBackend):
|
|||
|
||||
pattern_url = '{protocol}://www.youtube.com/embed/{code}'
|
||||
pattern_thumbnail_url = '{protocol}://img.youtube.com/vi/{code}/hqdefault.jpg'
|
||||
default_query = {'wmode': 'opaque'}
|
||||
default_query = EMBED_VIDEO_YOUTUBE_DEFAULT_QUERY
|
||||
|
||||
def get_code(self):
|
||||
code = super(YoutubeBackend, self).get_code()
|
||||
|
|
|
|||
|
|
@ -8,3 +8,6 @@ EMBED_VIDEO_BACKENDS = getattr(settings, 'EMBED_VIDEO_BACKENDS', (
|
|||
))
|
||||
|
||||
EMBED_VIDEO_TIMEOUT = getattr(settings, 'EMBED_VIDEO_TIMEOUT', 10)
|
||||
|
||||
EMBED_VIDEO_YOUTUBE_DEFAULT_QUERY = \
|
||||
getattr(settings, 'EMBED_VIDEO_YOUTUBE_DEFAULT_QUERY', 'wmode=opaque')
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
<iframe width="{{ width }}" height="{{ height }}" src="{{ backend.url }}"
|
||||
frameborder="0" allowfullscreen></iframe>
|
||||
<iframe width="{{ width }}" height="{{ height }}" src="{{ backend.url }}" frameborder="0" allowfullscreen></iframe>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import re
|
||||
import logging
|
||||
import requests
|
||||
from collections import defaultdict
|
||||
|
||||
from django.template import Library, Node, TemplateSyntaxError, Variable
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.encoding import smart_str
|
||||
|
||||
|
|
@ -14,8 +13,6 @@ register = Library()
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Used for parsing keyword arguments passed in as key-value pairs
|
||||
kw_pat = re.compile(r'^(?P<key>[\w]+)=(?P<value>.+)$')
|
||||
|
||||
|
||||
@register.tag('video')
|
||||
|
|
@ -28,25 +25,26 @@ class VideoNode(Node):
|
|||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% video URL [SIZE] %}
|
||||
{% video URL [SIZE] [key1=value1, key2=value2...] %}
|
||||
|
||||
Or as a block:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% video URL as VAR %}
|
||||
{% video URL [SIZE] [key1=value1, key2=value2...] as VAR %}
|
||||
...
|
||||
{% endvideo %}
|
||||
|
||||
Example:
|
||||
Examples:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% video item.video %}
|
||||
{% video item.video "large" %}
|
||||
{% video item.video "340x200" %}
|
||||
{% video item.video "100% x 300" %}
|
||||
{% video item.video "100% x 300" query="rel=0&wmode=opaque" %}
|
||||
|
||||
{% video item.video as my_video %}
|
||||
{% video item.video is_secure=True as my_video %}
|
||||
URL: {{ my_video.url }}
|
||||
Thumbnail: {{ my_video.thumbnail }}
|
||||
Backend: {{ my_video.backend }}
|
||||
|
|
@ -57,62 +55,48 @@ class VideoNode(Node):
|
|||
'[size] [key1=val1 key2=val2 ...] [as var] %}``'
|
||||
default_size = 'small'
|
||||
|
||||
re_size = re.compile('(?P<width>\d+%?) *x *(?P<height>\d+%?)')
|
||||
re_size = re.compile('[\'"]?(?P<width>\d+%?) *x *(?P<height>\d+%?)[\'"]?')
|
||||
re_option = re.compile(r'^(?P<key>[\w]+)=(?P<value>.+)$')
|
||||
|
||||
def __init__(self, parser, token):
|
||||
self.size = None
|
||||
self.bits = token.split_contents()
|
||||
self.query = None
|
||||
self.parser = parser
|
||||
self.bits = list(token.split_contents())
|
||||
self.tag_name = str(self.pop_bit())
|
||||
self.url = self.pop_bit()
|
||||
|
||||
try:
|
||||
self.url = parser.compile_filter(self.bits[1])
|
||||
except IndexError:
|
||||
raise TemplateSyntaxError(self.error_msg)
|
||||
|
||||
# Determine if the tag is being used as a context variable
|
||||
if self.bits[-2] == 'as':
|
||||
option_bits = self.bits[2:-2]
|
||||
self.nodelist_file = parser.parse(('endvideo',))
|
||||
if len(self.bits) > 1 and self.bits[-2] == 'as':
|
||||
del self.bits[-2]
|
||||
self.variable_name = str(self.pop_bit(-1))
|
||||
self.nodelist_file = parser.parse(('end' + self.tag_name, ))
|
||||
parser.delete_first_token()
|
||||
else:
|
||||
option_bits = self.bits[2:]
|
||||
self.variable_name = None
|
||||
|
||||
# Size must be the first argument and is only accepted when this is
|
||||
# used as a template tag (but not when used as a block tag)
|
||||
if len(option_bits) != 0 and '=' not in option_bits[0]:
|
||||
self.size = parser.compile_filter(option_bits[0])
|
||||
option_bits = option_bits[1:]
|
||||
else:
|
||||
self.size = self.default_size
|
||||
self.size = self.pop_bit() if self.bits and '=' not in self.bits[0] else None
|
||||
self.options = self.parse_options(self.bits)
|
||||
|
||||
# Parse arguments passed in as KEY=VALUE pairs that will be added to
|
||||
# the URL as a GET query string
|
||||
if len(option_bits) != 0:
|
||||
self.query = defaultdict(list)
|
||||
def pop_bit(self, index=0):
|
||||
return self.parser.compile_filter(self.bits.pop(index))
|
||||
|
||||
for bit in option_bits:
|
||||
match = kw_pat.match(bit)
|
||||
key = smart_str(match.group('key'))
|
||||
value = Variable(smart_str(match.group('value')))
|
||||
self.query[key].append(value)
|
||||
def parse_options(self, bits):
|
||||
options = {}
|
||||
for bit in bits:
|
||||
parsed_bit = self.re_option.match(bit)
|
||||
key = smart_str(parsed_bit.group('key'))
|
||||
value = self.parser.compile_filter(parsed_bit.group('value'))
|
||||
options[key] = value
|
||||
return options
|
||||
|
||||
def render(self, context):
|
||||
# Attempt to resolve any parameters passed in.
|
||||
if self.query is not None:
|
||||
resolved_query = defaultdict(list)
|
||||
for key, values in self.query.items():
|
||||
for value in values:
|
||||
resolved_value = value.resolve(context)
|
||||
resolved_query[key].append(resolved_value)
|
||||
else:
|
||||
resolved_query = None
|
||||
|
||||
url = self.url.resolve(context)
|
||||
size = self.size.resolve(context) if self.size else None
|
||||
options = self.resolve_options(context)
|
||||
|
||||
try:
|
||||
if self.size:
|
||||
return self.__render_embed(url, context, resolved_query)
|
||||
else:
|
||||
return self.__render_block(url, context, resolved_query)
|
||||
if not self.variable_name:
|
||||
return self.embed(url, size, context=context, **options)
|
||||
backend = self.get_backend(url, context=context, **options)
|
||||
return self.render_block(context, backend)
|
||||
except requests.Timeout:
|
||||
logger.exception('Timeout reached during rendering embed video (`{0}`)'.format(url))
|
||||
except UnknownBackendException:
|
||||
|
|
@ -122,23 +106,22 @@ class VideoNode(Node):
|
|||
|
||||
return ''
|
||||
|
||||
def __render_embed(self, url, context, query):
|
||||
size = self.size.resolve(context) \
|
||||
if hasattr(self.size, 'resolve') else self.size
|
||||
return self.embed(url, size, context=context, query=query)
|
||||
|
||||
def __render_block(self, url, context, query):
|
||||
as_var = self.bits[-1]
|
||||
def resolve_options(self, context):
|
||||
options = {}
|
||||
for key in self.options:
|
||||
value = self.options[key]
|
||||
options[key] = value.resolve(context)
|
||||
return options
|
||||
|
||||
def render_block(self, context, backend):
|
||||
context.push()
|
||||
context[as_var] = self.get_backend(url, context=context, query=query)
|
||||
context[self.variable_name] = backend
|
||||
output = self.nodelist_file.render(context)
|
||||
context.pop()
|
||||
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
def get_backend(backend_or_url, context=None, query=None):
|
||||
def get_backend(backend_or_url, context=None, **options):
|
||||
"""
|
||||
Returns instance of VideoBackend. If context is passed to the method
|
||||
and request is secure, than the is_secure mark is set to backend.
|
||||
|
|
@ -151,22 +134,22 @@ class VideoNode(Node):
|
|||
|
||||
if context and 'request' in context:
|
||||
backend.is_secure = context['request'].is_secure()
|
||||
|
||||
backend.update_query(query)
|
||||
if options:
|
||||
backend.set_options(options)
|
||||
|
||||
return backend
|
||||
|
||||
@staticmethod
|
||||
def embed(url, size, GET=None, context=None, query=None):
|
||||
@classmethod
|
||||
def embed(cls, url, size, context=None, **options):
|
||||
"""
|
||||
Direct render of embed video.
|
||||
"""
|
||||
backend = VideoNode.get_backend(url, context=context, query=query)
|
||||
width, height = VideoNode.get_size(size)
|
||||
backend = cls.get_backend(url, context=context, **options)
|
||||
width, height = cls.get_size(size)
|
||||
return mark_safe(backend.get_embed_code(width=width, height=height))
|
||||
|
||||
@staticmethod
|
||||
def get_size(value):
|
||||
@classmethod
|
||||
def get_size(cls, value):
|
||||
"""
|
||||
Predefined sizes:
|
||||
|
||||
|
|
@ -191,11 +174,12 @@ class VideoNode(Node):
|
|||
'huge': (1280, 960),
|
||||
}
|
||||
|
||||
value = value or cls.default_size
|
||||
if value in sizes:
|
||||
return sizes[value]
|
||||
|
||||
try:
|
||||
size = VideoNode.re_size.match(value)
|
||||
size = cls.re_size.match(value)
|
||||
return [size.group('width'), size.group('height')]
|
||||
except AttributeError:
|
||||
raise TemplateSyntaxError(
|
||||
|
|
@ -209,28 +193,3 @@ class VideoNode(Node):
|
|||
|
||||
def __repr__(self):
|
||||
return '<VideoNode "%s">' % self.url
|
||||
|
||||
|
||||
@register.filter(is_safe=True)
|
||||
def embed(backend, size='small'):
|
||||
"""
|
||||
.. warning::
|
||||
.. deprecated:: 0.7
|
||||
Use :py:func:`VideoNode.embed` instead.
|
||||
|
||||
Same like :py:func:`VideoNode.embed` tag but **always uses insecure
|
||||
HTTP protocol**.
|
||||
|
||||
Usage:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ URL|embed:SIZE }}
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ 'http://www.youtube.com/watch?v=guXyvo2FfLs'|embed:'large' }}
|
||||
"""
|
||||
return VideoNode.embed(backend, size)
|
||||
|
|
|
|||
17
embed_video/tests/backends/__init__.py
Normal file
17
embed_video/tests/backends/__init__.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from embed_video.backends import detect_backend
|
||||
|
||||
|
||||
class BackendTestMixin(object):
|
||||
urls = []
|
||||
instance = None
|
||||
|
||||
def test_detect(self):
|
||||
for url in self.urls:
|
||||
backend = detect_backend(url[0])
|
||||
self.assertIsInstance(backend, self.instance)
|
||||
|
||||
def test_code(self):
|
||||
for url in self.urls:
|
||||
backend = self.instance(url[0])
|
||||
self.assertEqual(backend.code, url[1])
|
||||
|
||||
|
|
@ -1,8 +1,15 @@
|
|||
import re
|
||||
from unittest import TestCase
|
||||
|
||||
from embed_video.backends import detect_backend
|
||||
from embed_video.backends import VideoBackend, detect_backend
|
||||
|
||||
from .custom_backend import CustomBackend
|
||||
|
||||
class CustomBackend(VideoBackend):
|
||||
re_detect = re.compile(r'http://myvideo\.com/[0-9]+')
|
||||
re_code = re.compile(r'http://myvideo\.com/(?P<code>[0-9]+)')
|
||||
|
||||
pattern_url = '{protocol}://play.myvideo.com/c/{code}/'
|
||||
pattern_thumbnail_url = '{protocol}://thumb.myvideo.com/c/{code}/'
|
||||
|
||||
|
||||
class CustomBackendTestCase(TestCase):
|
||||
|
|
@ -27,4 +34,3 @@ class CustomBackendTestCase(TestCase):
|
|||
def test_thumbnail(self):
|
||||
self.assertEqual(self.backend.get_thumbnail_url(),
|
||||
'http://thumb.myvideo.com/c/1530/')
|
||||
|
||||
55
embed_video/tests/backends/tests_soundcloud.py
Normal file
55
embed_video/tests/backends/tests_soundcloud.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import requests
|
||||
from mock import patch
|
||||
from unittest import TestCase
|
||||
|
||||
from . import BackendTestMixin
|
||||
from embed_video.backends import SoundCloudBackend, VideoDoesntExistException
|
||||
|
||||
|
||||
class SoundCloudBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('https://soundcloud.com/community/soundcloud-case-study-wildlife', '82244706'),
|
||||
('https://soundcloud.com/matej-roman/jaromir-nohavica-karel-plihal-mikymauz', '7834701'),
|
||||
('https://soundcloud.com/beny97/sets/jaromir-nohavica-prazska', '960591'),
|
||||
('https://soundcloud.com/corbel-keep/norah-jones-come-away-with', '22485933'),
|
||||
)
|
||||
|
||||
instance = SoundCloudBackend
|
||||
|
||||
def setUp(self):
|
||||
class FooBackend(SoundCloudBackend):
|
||||
url = 'foobar'
|
||||
|
||||
def get_info(self):
|
||||
return {
|
||||
'width': 123,
|
||||
'height': 321,
|
||||
'thumbnail_url': 'xyz',
|
||||
'html': u'\u003Ciframe width=\"100%\" height=\"400\" '
|
||||
u'scrolling=\"no\" frameborder=\"no\" '
|
||||
u'src=\"{0}\"\u003E\u003C/iframe\u003E'.format(self.url)
|
||||
}
|
||||
|
||||
self.foo = FooBackend('abcd')
|
||||
|
||||
def test_width(self):
|
||||
self.assertEqual(self.foo.width, 123)
|
||||
|
||||
def test_height(self):
|
||||
self.assertEqual(self.foo.height, 321)
|
||||
|
||||
def test_get_thumbnail_url(self):
|
||||
self.assertEqual(self.foo.get_thumbnail_url(), 'xyz')
|
||||
|
||||
def test_get_url(self):
|
||||
self.assertEqual(self.foo.get_url(), self.foo.url)
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
def test_timeout_in_get_info(self):
|
||||
backend = SoundCloudBackend('https://soundcloud.com/community/soundcloud-case-study-wildlife')
|
||||
self.assertRaises(requests.Timeout, backend.get_info)
|
||||
|
||||
def test_invalid_url(self):
|
||||
""" Check if bug #21 is fixed. """
|
||||
backend = SoundCloudBackend('https://soundcloud.com/xyz/foo')
|
||||
self.assertRaises(VideoDoesntExistException, backend.get_info)
|
||||
20
embed_video/tests/backends/tests_videobackend.py
Normal file
20
embed_video/tests/backends/tests_videobackend.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from unittest import TestCase
|
||||
from embed_video.backends import UnknownBackendException, detect_backend, \
|
||||
VideoBackend
|
||||
|
||||
|
||||
class VideoBackendTestCase(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/72304002',
|
||||
)
|
||||
|
||||
def test_detect_bad_urls(self):
|
||||
for url in self.unknown_backend_urls:
|
||||
self.assertRaises(UnknownBackendException, detect_backend, url)
|
||||
|
||||
def test_not_implemented_get_info(self):
|
||||
backend = VideoBackend('http://www.example.com')
|
||||
self.assertRaises(NotImplementedError, backend.get_info)
|
||||
34
embed_video/tests/backends/tests_vimeo.py
Normal file
34
embed_video/tests/backends/tests_vimeo.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import requests
|
||||
from mock import patch
|
||||
from unittest import TestCase
|
||||
|
||||
from . import BackendTestMixin
|
||||
from embed_video.backends import VimeoBackend, VideoDoesntExistException
|
||||
|
||||
|
||||
class VimeoBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('http://vimeo.com/72304002', '72304002'),
|
||||
('https://vimeo.com/72304002', '72304002'),
|
||||
('http://www.vimeo.com/72304002', '72304002'),
|
||||
('https://www.vimeo.com/72304002', '72304002'),
|
||||
('http://player.vimeo.com/video/72304002', '72304002'),
|
||||
('https://player.vimeo.com/video/72304002', '72304002'),
|
||||
)
|
||||
|
||||
instance = VimeoBackend
|
||||
|
||||
def test_vimeo_get_info_exception(self):
|
||||
with self.assertRaises(VideoDoesntExistException):
|
||||
backend = VimeoBackend('http://vimeo.com/123')
|
||||
backend.get_info()
|
||||
|
||||
def test_get_thumbnail_url(self):
|
||||
backend = VimeoBackend('http://vimeo.com/72304002')
|
||||
self.assertEqual(backend.get_thumbnail_url(),
|
||||
'http://i.vimeocdn.com/video/446150690_640.jpg')
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
def test_timeout_in_get_info(self):
|
||||
backend = VimeoBackend('http://vimeo.com/72304002')
|
||||
self.assertRaises(requests.Timeout, backend.get_info)
|
||||
42
embed_video/tests/backends/tests_youtube.py
Normal file
42
embed_video/tests/backends/tests_youtube.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
from unittest import TestCase
|
||||
|
||||
from . import BackendTestMixin
|
||||
from embed_video.backends import YoutubeBackend, UnknownIdException
|
||||
|
||||
|
||||
class YoutubeBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('http://youtu.be/jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('http://youtu.be/n17B_uFF4cA', 'n17B_uFF4cA'),
|
||||
('http://youtu.be/t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('https://youtu.be/t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('http://youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('https://youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('http://www.youtube.com/v/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('https://www.youtube.com/v/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('http://www.youtube.com/embed/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('https://www.youtube.com/embed/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('http://www.youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('https://www.youtube.com/watch?v=t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('http://www.youtube.com/watch?v=iwGFalTRHDA&feature=related', 'iwGFalTRHDA'),
|
||||
('https://www.youtube.com/watch?v=iwGFalTRHDA&feature=related', 'iwGFalTRHDA'),
|
||||
('http://www.youtube.com/watch?feature=player_embedded&v=2NpZbaAIXag', '2NpZbaAIXag'),
|
||||
('https://www.youtube.com/watch?feature=player_embedded&v=2NpZbaAIXag', '2NpZbaAIXag'),
|
||||
('https://www.youtube.com/watch?v=XPk521voaOE&feature=youtube_gdata_player', 'XPk521voaOE'),
|
||||
('http://www.youtube.com/watch?v=6xu00J3-g2s&list=PLb5n6wzDlPakFKvJ69rJ9AJW24Aaaki2z', '6xu00J3-g2s'),
|
||||
('https://m.youtube.com/#/watch?v=IAooXLAPoBQ', 'IAooXLAPoBQ'),
|
||||
('https://m.youtube.com/watch?v=IAooXLAPoBQ', 'IAooXLAPoBQ'),
|
||||
('http://www.youtube.com/edit?video_id=eBea01qmnOE', 'eBea01qmnOE')
|
||||
)
|
||||
|
||||
instance = YoutubeBackend
|
||||
|
||||
def test_youtube_keyerror(self):
|
||||
""" Test for issue #7 """
|
||||
backend = self.instance('http://youtube.com/watch?id=5')
|
||||
self.assertRaises(UnknownIdException, backend.get_code)
|
||||
|
||||
def test_thumbnail(self):
|
||||
for url in self.urls:
|
||||
backend = self.instance(url[0])
|
||||
self.assertIn(url[1], backend.thumbnail)
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import re
|
||||
|
||||
from embed_video.backends import VideoBackend
|
||||
|
||||
|
||||
class CustomBackend(VideoBackend):
|
||||
re_detect = re.compile(r'http://myvideo\.com/[0-9]+')
|
||||
re_code = re.compile(r'http://myvideo\.com/(?P<code>[0-9]+)')
|
||||
|
||||
pattern_url = '{protocol}://play.myvideo.com/c/{code}/'
|
||||
pattern_thumbnail_url = '{protocol}://thumb.myvideo.com/c/{code}/'
|
||||
|
|
@ -17,7 +17,7 @@ EMBED_VIDEO_BACKENDS = (
|
|||
'embed_video.backends.YoutubeBackend',
|
||||
'embed_video.backends.VimeoBackend',
|
||||
'embed_video.backends.SoundCloudBackend',
|
||||
'embed_video.tests.custom_backend.CustomBackend',
|
||||
'embed_video.tests.backends.tests_custom_backend.CustomBackend',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
0
embed_video/tests/templatetags/__init__.py
Normal file
0
embed_video/tests/templatetags/__init__.py
Normal file
285
embed_video/tests/templatetags/tests_embed_video_tags.py
Normal file
285
embed_video/tests/templatetags/tests_embed_video_tags.py
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
from unittest import TestCase, skip
|
||||
from mock import Mock, patch
|
||||
import re
|
||||
|
||||
from django.template import TemplateSyntaxError
|
||||
from django.http import HttpRequest
|
||||
from django.template.base import Template
|
||||
from django.template.context import RequestContext
|
||||
from django.test.client import RequestFactory
|
||||
from testfixtures import log_capture
|
||||
|
||||
from embed_video.templatetags.embed_video_tags import VideoNode
|
||||
|
||||
URL_PATTERN = re.compile(r'src="?\'?([^"\'>]*)"')
|
||||
|
||||
|
||||
class EmbedTestCase(TestCase):
|
||||
def assertRenderedTemplate(self, template_string, output, context=None):
|
||||
response = RequestContext(HttpRequest(), context)
|
||||
rendered_output = Template(template_string).render(response)
|
||||
self.assertEqual(rendered_output.strip(), output.strip())
|
||||
|
||||
def test_embed(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{% video ytb 'large' %}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="960" height="720" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_embed_invalid_url(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/edit?abcd=efgh' as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(template, '')
|
||||
|
||||
def test_embed_with_none_instance(self):
|
||||
template = """
|
||||
{% with None as my_video %}
|
||||
{% load embed_video_tags %}
|
||||
{% video my_video %}{% endwith %}
|
||||
"""
|
||||
self.assertRenderedTemplate(template, '')
|
||||
|
||||
def test_embed_empty_string(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video '' 'large' %}
|
||||
"""
|
||||
self.assertRenderedTemplate(template, '')
|
||||
|
||||
def test_direct_embed_tag(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://www.youtube.com/watch?v=jsrRJyHBvzw" "large" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="960" height="720" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_direct_embed_tag_with_default_size(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://www.youtube.com/watch?v=jsrRJyHBvzw" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="480" height="360" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_direct_embed_invalid_url(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "https://soundcloud.com/xyz/foo" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(template, '')
|
||||
|
||||
def test_user_size(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{% video ytb '800x800' %}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="800" height="800" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
@skip
|
||||
def test_wrong_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' 'so x huge' %}
|
||||
""")
|
||||
request = RequestContext(HttpRequest())
|
||||
self.assertRaises(TemplateSyntaxError, template.render, request)
|
||||
|
||||
def test_tag_youtube(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{{ ytb.url }} {{ ytb.backend }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque '
|
||||
'YoutubeBackend'
|
||||
)
|
||||
|
||||
def test_tag_vimeo(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://vimeo.com/72304002' as vimeo %}
|
||||
{{ vimeo.url }} {{ vimeo.backend }} {{ vimeo.info.duration }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template, 'http://player.vimeo.com/video/72304002 VimeoBackend 176'
|
||||
)
|
||||
|
||||
def test_tag_soundcloud(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://soundcloud.com/community/soundcloud-case-study-wildlife' as soundcloud %}
|
||||
{{ soundcloud.url }} {{ soundcloud.backend }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'https://w.soundcloud.com/player/?visual=true&url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F82244706&show_artwork=true '
|
||||
'SoundCloudBackend'
|
||||
)
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
@log_capture()
|
||||
def test_empty_if_timeout(self, logs):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" as my_video %}
|
||||
{{ my_video.thumbnail }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
|
||||
self.assertRenderedTemplate(template, '')
|
||||
logs.check(
|
||||
('requests.packages.urllib3.connectionpool', 'INFO', 'Starting new HTTP connection (1): vimeo.com'),
|
||||
('embed_video.templatetags.embed_video_tags', 'ERROR', 'Timeout reached during rendering embed video (`http://vimeo.com/72304002`)')
|
||||
)
|
||||
|
||||
def test_relative_size(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" "80%x30%" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="80%" height="30%" '
|
||||
'src="http://player.vimeo.com/video/72304002" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_allow_spaces_in_size(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" "80% x 300" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="80%" height="300" '
|
||||
'src="http://player.vimeo.com/video/72304002" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_embed_with_query(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' query="rel=1&wmode=transparent" as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=transparent&rel=1'
|
||||
)
|
||||
|
||||
def test_direct_embed_with_query(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' query="rel=1&wmode=transparent" %}
|
||||
"""
|
||||
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="480" height="360" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=transparent&rel=1" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_set_options(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' "300x200" is_secure=True query="rel=1" %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="300" height="200" '
|
||||
'src="https://www.youtube.com/embed/jsrRJyHBvzw?rel=1" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
def test_size_as_variable(self):
|
||||
template = """
|
||||
{% load embed_video_tags %}
|
||||
{% with size="500x200" %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' size %}
|
||||
{% endwith %}
|
||||
"""
|
||||
self.assertRenderedTemplate(
|
||||
template,
|
||||
'<iframe width="500" height="200" '
|
||||
'src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque" '
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
)
|
||||
|
||||
|
||||
class EmbedVideoNodeTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.parser = Mock()
|
||||
self.token = Mock(methods=['split_contents'])
|
||||
|
||||
def test_repr(self):
|
||||
self.token.split_contents.return_value = (
|
||||
'video', 'http://youtu.be/v/1234', 'as', 'myvideo'
|
||||
)
|
||||
self.parser.compile_filter.return_value = u'some_url'
|
||||
|
||||
node = VideoNode(self.parser, self.token)
|
||||
self.assertEqual(str(node), '<VideoNode "some_url">')
|
||||
|
||||
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])
|
||||
|
||||
def test_get_backend_secure(self):
|
||||
class SecureRequest(RequestFactory):
|
||||
is_secure = lambda x: True
|
||||
|
||||
context = {'request': SecureRequest()}
|
||||
backend = VideoNode.get_backend('http://www.youtube.com/watch?v=jsrRJyHBvzw', context)
|
||||
self.assertTrue(backend.is_secure)
|
||||
|
||||
def test_get_backend_insecure(self):
|
||||
class InsecureRequest(RequestFactory):
|
||||
is_secure = lambda x: False
|
||||
|
||||
context = {'request': InsecureRequest()}
|
||||
backend = VideoNode.get_backend('http://www.youtube.com/watch?v=jsrRJyHBvzw', context)
|
||||
self.assertFalse(backend.is_secure)
|
||||
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
from unittest import TestCase
|
||||
from mock import patch
|
||||
import requests
|
||||
|
||||
from ..backends import detect_backend, YoutubeBackend, VimeoBackend, \
|
||||
SoundCloudBackend, UnknownBackendException, VideoDoesntExistException, \
|
||||
UnknownIdException, VideoBackend
|
||||
|
||||
|
||||
class BackendTestMixin(object):
|
||||
def test_detect(self):
|
||||
for url in self.urls:
|
||||
backend = detect_backend(url[0])
|
||||
self.assertIsInstance(backend, self.instance)
|
||||
|
||||
def test_code(self):
|
||||
for url in self.urls:
|
||||
backend = self.instance(url[0])
|
||||
self.assertEqual(backend.code, url[1])
|
||||
|
||||
|
||||
class VideoBackendTestCase(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/72304002',
|
||||
)
|
||||
|
||||
def test_detect_bad_urls(self):
|
||||
for url in self.unknown_backend_urls:
|
||||
self.assertRaises(UnknownBackendException, detect_backend, url)
|
||||
|
||||
def test_not_implemented_get_info(self):
|
||||
backend = VideoBackend('http://www.example.com')
|
||||
self.assertRaises(NotImplementedError, backend.get_info)
|
||||
|
||||
|
||||
class YoutubeBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('http://youtu.be/jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('http://youtu.be/n17B_uFF4cA', 'n17B_uFF4cA'),
|
||||
('http://youtu.be/t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('https://youtu.be/t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('http://youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('https://youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('http://www.youtube.com/v/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('https://www.youtube.com/v/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('http://www.youtube.com/embed/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('https://www.youtube.com/embed/0zM3nApSvMg?rel=0', '0zM3nApSvMg'),
|
||||
('http://www.youtube.com/watch?v=jsrRJyHBvzw', 'jsrRJyHBvzw'),
|
||||
('https://www.youtube.com/watch?v=t-ZRX8984sc', 't-ZRX8984sc'),
|
||||
('http://www.youtube.com/watch?v=iwGFalTRHDA&feature=related', 'iwGFalTRHDA'),
|
||||
('https://www.youtube.com/watch?v=iwGFalTRHDA&feature=related', 'iwGFalTRHDA'),
|
||||
('http://www.youtube.com/watch?feature=player_embedded&v=2NpZbaAIXag', '2NpZbaAIXag'),
|
||||
('https://www.youtube.com/watch?feature=player_embedded&v=2NpZbaAIXag', '2NpZbaAIXag'),
|
||||
('https://www.youtube.com/watch?v=XPk521voaOE&feature=youtube_gdata_player', 'XPk521voaOE'),
|
||||
('http://www.youtube.com/watch?v=6xu00J3-g2s&list=PLb5n6wzDlPakFKvJ69rJ9AJW24Aaaki2z', '6xu00J3-g2s'),
|
||||
('https://m.youtube.com/#/watch?v=IAooXLAPoBQ', 'IAooXLAPoBQ'),
|
||||
('https://m.youtube.com/watch?v=IAooXLAPoBQ', 'IAooXLAPoBQ'),
|
||||
('http://www.youtube.com/edit?video_id=eBea01qmnOE', 'eBea01qmnOE')
|
||||
)
|
||||
|
||||
instance = YoutubeBackend
|
||||
|
||||
def test_youtube_keyerror(self):
|
||||
""" Test for issue #7 """
|
||||
backend = self.instance('http://youtube.com/watch?id=5')
|
||||
self.assertRaises(UnknownIdException, backend.get_code)
|
||||
|
||||
def test_thumbnail(self):
|
||||
for url in self.urls:
|
||||
backend = self.instance(url[0])
|
||||
self.assertIn(url[1], backend.thumbnail)
|
||||
|
||||
|
||||
class VimeoBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('http://vimeo.com/72304002', '72304002'),
|
||||
('https://vimeo.com/72304002', '72304002'),
|
||||
('http://www.vimeo.com/72304002', '72304002'),
|
||||
('https://www.vimeo.com/72304002', '72304002'),
|
||||
('http://player.vimeo.com/video/72304002', '72304002'),
|
||||
('https://player.vimeo.com/video/72304002', '72304002'),
|
||||
)
|
||||
|
||||
instance = VimeoBackend
|
||||
|
||||
def test_vimeo_get_info_exception(self):
|
||||
with self.assertRaises(VideoDoesntExistException):
|
||||
backend = VimeoBackend('http://vimeo.com/123')
|
||||
backend.get_info()
|
||||
|
||||
def test_get_thumbnail_url(self):
|
||||
backend = VimeoBackend('http://vimeo.com/72304002')
|
||||
self.assertEqual(backend.get_thumbnail_url(),
|
||||
'http://i.vimeocdn.com/video/446150690_640.jpg')
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
def test_timeout_in_get_info(self):
|
||||
backend = VimeoBackend('http://vimeo.com/72304002')
|
||||
self.assertRaises(requests.Timeout, backend.get_info)
|
||||
|
||||
|
||||
class SoundCloudBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('https://soundcloud.com/community/soundcloud-case-study-wildlife', '82244706'),
|
||||
('https://soundcloud.com/matej-roman/jaromir-nohavica-karel-plihal-mikymauz', '7834701'),
|
||||
('https://soundcloud.com/beny97/sets/jaromir-nohavica-prazska', '960591'),
|
||||
('https://soundcloud.com/corbel-keep/norah-jones-come-away-with', '22485933'),
|
||||
)
|
||||
|
||||
instance = SoundCloudBackend
|
||||
|
||||
def setUp(self):
|
||||
class FooBackend(SoundCloudBackend):
|
||||
url = 'foobar'
|
||||
|
||||
def get_info(self):
|
||||
return {
|
||||
'width': 123,
|
||||
'height': 321,
|
||||
'thumbnail_url': 'xyz',
|
||||
'html': u'\u003Ciframe width=\"100%\" height=\"400\" '
|
||||
u'scrolling=\"no\" frameborder=\"no\" '
|
||||
u'src=\"{0}\"\u003E\u003C/iframe\u003E'.format(self.url)
|
||||
}
|
||||
|
||||
self.foo = FooBackend('abcd')
|
||||
|
||||
def test_width(self):
|
||||
self.assertEqual(self.foo.width, 123)
|
||||
|
||||
def test_height(self):
|
||||
self.assertEqual(self.foo.height, 321)
|
||||
|
||||
def test_get_thumbnail_url(self):
|
||||
self.assertEqual(self.foo.get_thumbnail_url(), 'xyz')
|
||||
|
||||
def test_get_url(self):
|
||||
self.assertEqual(self.foo.get_url(), self.foo.url)
|
||||
|
||||
def test_get_embed_code(self):
|
||||
self.assertEqual(self.foo.get_embed_code(100, 200),
|
||||
u'<iframe width="100" height="321" src="foobar"'
|
||||
u'\n frameborder="0" allowfullscreen>'
|
||||
u'</iframe>\n')
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
def test_timeout_in_get_info(self):
|
||||
backend = SoundCloudBackend('https://soundcloud.com/community/soundcloud-case-study-wildlife')
|
||||
self.assertRaises(requests.Timeout, backend.get_info)
|
||||
|
||||
def test_invalid_url(self):
|
||||
""" Check if bug #21 is fixed. """
|
||||
backend = SoundCloudBackend('https://soundcloud.com/xyz/foo')
|
||||
self.assertRaises(VideoDoesntExistException, backend.get_info)
|
||||
|
|
@ -1,341 +0,0 @@
|
|||
from unittest import TestCase
|
||||
from mock import Mock, patch
|
||||
import re
|
||||
|
||||
try:
|
||||
# Python <= 2.7
|
||||
import urlparse
|
||||
except ImportError:
|
||||
# Python 3
|
||||
import urllib.parse as urlparse
|
||||
|
||||
from django.template import TemplateSyntaxError
|
||||
from django.http import HttpRequest
|
||||
from django.template.base import Template
|
||||
from django.template.context import RequestContext
|
||||
from django.test.utils import override_settings
|
||||
from django.test.client import RequestFactory
|
||||
from testfixtures import LogCapture
|
||||
|
||||
from embed_video.templatetags.embed_video_tags import VideoNode
|
||||
|
||||
URL_PATTERN = re.compile(r'src="?\'?([^"\'>]*)"')
|
||||
|
||||
|
||||
class EmbedVideoNodeTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.parser = Mock()
|
||||
self.token = Mock(methods=['split_contents'])
|
||||
|
||||
@staticmethod
|
||||
def _grc(context=None):
|
||||
return RequestContext(HttpRequest(), context)
|
||||
|
||||
def test_embed(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{% video ytb '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_direct_embed_tag(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://www.youtube.com/watch?v=jsrRJyHBvzw" "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_direct_embed_tag_with_default_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://www.youtube.com/watch?v=jsrRJyHBvzw" %}
|
||||
""")
|
||||
rendered = u'''<iframe width="480" height="360" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque"
|
||||
frameborder="0" allowfullscreen></iframe>'''
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_user_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' as ytb %}
|
||||
{% video ytb '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_wrong_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' 'so x huge' %}
|
||||
""")
|
||||
self.assertRaises(TemplateSyntaxError, template.render, self._grc())
|
||||
|
||||
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_youtube_invalid_url(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/edit?abcd=efgh' as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
self.assertEqual(template.render(self._grc()).strip(), '')
|
||||
|
||||
def test_tag_vimeo(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'https://vimeo.com/72304002' as vimeo %}
|
||||
{{ vimeo.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://player.vimeo.com/video/72304002'
|
||||
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/72304002' 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/community/soundcloud-case-study-wildlife' 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 = []
|
||||
self.assertRaises(TemplateSyntaxError, VideoNode, self.parser, self.token)
|
||||
|
||||
def test_repr(self):
|
||||
self.token.split_contents.return_value = (
|
||||
'video', 'http://youtu.be/v/1234', 'as', 'myvideo'
|
||||
)
|
||||
self.parser.compile_filter.return_value = u'some_url'
|
||||
|
||||
node = VideoNode(self.parser, self.token)
|
||||
self.assertEqual(str(node), '<VideoNode "some_url">')
|
||||
|
||||
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])
|
||||
|
||||
def test_get_backend_secure(self):
|
||||
class SecureRequest(RequestFactory):
|
||||
is_secure = lambda x: True
|
||||
|
||||
context = {'request': SecureRequest()}
|
||||
backend = VideoNode.get_backend('http://www.youtube.com/watch?v=jsrRJyHBvzw', context)
|
||||
self.assertTrue(backend.is_secure)
|
||||
|
||||
def test_get_backend_insecure(self):
|
||||
class InsecureRequest(RequestFactory):
|
||||
is_secure = lambda x: False
|
||||
|
||||
context = {'request': InsecureRequest()}
|
||||
backend = VideoNode.get_backend('http://www.youtube.com/watch?v=jsrRJyHBvzw', context)
|
||||
self.assertFalse(backend.is_secure)
|
||||
|
||||
def test_no_video_provided(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video '' 'large' %}
|
||||
""")
|
||||
self.assertEqual(template.render(self._grc()).strip(), '')
|
||||
|
||||
@patch('embed_video.backends.EMBED_VIDEO_TIMEOUT', 0.000001)
|
||||
def test_empty_if_timeout(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" as my_video %}
|
||||
{{ my_video.thumbnail }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
with LogCapture() as logs:
|
||||
self.assertEqual(template.render(self._grc()).strip(), '')
|
||||
log = logs.records[-1]
|
||||
self.assertEqual(log.name, 'embed_video.templatetags.embed_video_tags')
|
||||
self.assertEqual(log.msg, 'Timeout reached during rendering embed video (`http://vimeo.com/72304002`)')
|
||||
|
||||
def test_relative_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" "80%x30%" %}
|
||||
""")
|
||||
rendered = '<iframe width="80%" height="30%" src="http://player.vimeo.com/video/72304002"' \
|
||||
'\n frameborder="0" allowfullscreen></iframe>'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_allow_spaces_in_size(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "http://vimeo.com/72304002" "80% x 300" %}
|
||||
""")
|
||||
rendered = '<iframe width="80%" height="300" src="http://player.vimeo.com/video/72304002"' \
|
||||
'\n frameborder="0" allowfullscreen></iframe>'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_soundcloud_invalid_url(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video "https://soundcloud.com/xyz/foo" %}
|
||||
""")
|
||||
self.assertEqual(template.render(self._grc()).strip(), '')
|
||||
|
||||
##########################################################################
|
||||
# Tests for adding GET query via KEY=VALUE pairs
|
||||
##########################################################################
|
||||
|
||||
def _validate_GET_query(self, rendered, expected):
|
||||
# Use this functioon to test the KEY=VALUE optional arguments to the
|
||||
# templatetag because there's no guarantee that they will be appended
|
||||
# to the URL query string in a particular order. By default the
|
||||
# YouTube backend adds wmode=opaque to the query string, so be sure to
|
||||
# include that in the expected querystring dict.
|
||||
url = URL_PATTERN.search(rendered).group(1)
|
||||
result = urlparse.urlparse(url)
|
||||
qs = urlparse.parse_qs(result[4])
|
||||
self.assertEqual(qs, expected)
|
||||
|
||||
@override_settings(EMBED_VIDEO_YOUTUBE_QUERY={'rel': 0, 'stop': 5})
|
||||
def test_embed_with_query_settings_override(self):
|
||||
# Test KEY=VALUE argument with default values provided by settings
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' %}
|
||||
""")
|
||||
expected = {
|
||||
'rel': ['0'],
|
||||
'stop': ['5'],
|
||||
}
|
||||
rendered = template.render(self._grc())
|
||||
self._validate_GET_query(rendered, expected)
|
||||
|
||||
def test_embed_with_query_var(self):
|
||||
# Test KEY=VALUE argument with the value resolving to a context
|
||||
# variable.
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' rel=show_related loop=5 %}
|
||||
""")
|
||||
expected = {
|
||||
'rel': ['0'],
|
||||
'loop': ['5'],
|
||||
'wmode': ['opaque']
|
||||
}
|
||||
context = {'show_related': 0}
|
||||
rendered = template.render(self._grc(context))
|
||||
self._validate_GET_query(rendered, expected)
|
||||
|
||||
def test_embed_with_query_multiple(self):
|
||||
# Test multiple KEY=VALUE arguments
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' rel=0 loop=1 end=5 %}
|
||||
""")
|
||||
expected = {
|
||||
'rel': ['0'],
|
||||
'loop': ['1'],
|
||||
'end': ['5'],
|
||||
'wmode': ['opaque']
|
||||
}
|
||||
self._validate_GET_query(template.render(self._grc()), expected)
|
||||
|
||||
def test_embed_with_query_multiple_list(self):
|
||||
# Test multiple KEY=VALUE arguments where the key is repeated multiple
|
||||
# times (this is valid in a URL query).
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' rel=0 loop=1 end=5 end=6 %}
|
||||
""")
|
||||
expected = {
|
||||
'rel': ['0'],
|
||||
'loop': ['1'],
|
||||
'end': ['5', '6'],
|
||||
'wmode': ['opaque']
|
||||
}
|
||||
self._validate_GET_query(template.render(self._grc()), expected)
|
||||
|
||||
def test_tag_youtube_with_query(self):
|
||||
# Test KEY=VALUE arguments when used as a tag block.
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' rel=0 as ytb %}
|
||||
{{ ytb.url }}
|
||||
{% endvideo %}
|
||||
""")
|
||||
rendered = 'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque&rel=0'
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_embed_with_query_rel(self):
|
||||
template = Template("""
|
||||
{% load embed_video_tags %}
|
||||
{% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' rel=0 %}
|
||||
""")
|
||||
rendered = u'''<iframe width="480" height="360" src="http://www.youtube.com/embed/jsrRJyHBvzw?wmode=opaque&rel=0"
|
||||
frameborder="0" allowfullscreen></iframe>'''
|
||||
self.assertEqual(template.render(self._grc()).strip(), rendered)
|
||||
|
||||
def test_none_variable_passed_to_tag(self):
|
||||
"""
|
||||
Checks issue #24.
|
||||
"""
|
||||
template = Template("""
|
||||
{% with None as my_video %}
|
||||
{% load embed_video_tags %}
|
||||
{% video my_video %}
|
||||
{% endwith %}
|
||||
""")
|
||||
self.assertEqual(template.render(self._grc()).strip(), '')
|
||||
|
||||
Loading…
Reference in a new issue