Source code for embed_video.templatetags.embed_video_tags

import logging
import re

import requests
from django.template import Library, Node, TemplateSyntaxError
from django.utils.encoding import smart_str
from django.utils.safestring import mark_safe

from embed_video.backends import (
    UnknownBackendException,
    VideoBackend,
    VideoDoesntExistException,
    detect_backend,
)

register = Library()

logger = logging.getLogger(__name__)


[docs]@register.tag("video") class VideoNode(Node): """ Template tag ``video``. It gives access to all :py:class:`~embed_video.backends.VideoBackend` variables. Usage (shortcut): .. code-block:: html+django {% video URL [SIZE] [key1=value1, key2=value2...] %} Or as a block: .. code-block:: html+django {% video URL [SIZE] [key1=value1, key2=value2...] as VAR %} ... {% endvideo %} Examples: .. code-block:: html+django {% video item.video %} {% video item.video "large" %} {% video item.video "340x200" %} {% video item.video "100% x 300" query="rel=0&wmode=opaque" %} {% video item.video is_secure=True as my_video %} URL: {{ my_video.url }} Thumbnail: {{ my_video.thumbnail }} Backend: {{ my_video.backend }} {% endvideo %} """ error_msg = ( "Syntax error. Expected: ``{% video URL " "[size] [key1=val1 key2=val2 ...] [as var] %}``" ) default_size = "small" re_size = re.compile(r'[\'"]?(?P<width>\d+%?) *x *(?P<height>\d+%?)[\'"]?') re_option = re.compile(r"^(?P<key>[\w]+)=(?P<value>.+)$") def __init__(self, parser, token): """ :param parser: Django template parser :type parser: django.template.base.Parser :param token: Django template token :type token: django.template.base.Token """ self.parser = parser self.bits = list(token.split_contents()) self.tag_name = str(self.pop_bit()) self.url = self.pop_bit() 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: self.variable_name = None self.size = self.pop_bit() if self.bits and "=" not in self.bits[0] else None self.options = self.parse_options(self.bits) def pop_bit(self, index=0): return self.parser.compile_filter(self.bits.pop(index)) 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
[docs] def render(self, context): """ Returns generated HTML. :param context: Django template RequestContext :type context: django.template.RequestContext :return: Rendered HTML with embed video. :rtype: django.utils.safestring.SafeText | str """ url = self.url.resolve(context) size = self.size.resolve(context) if self.size else None options = self.resolve_options(context) try: 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: logger.warning("Backend wasn't recognised (`{0}`)".format(url)) except VideoDoesntExistException: logger.warning("Attempt to render not existing video (`{0}`)".format(url)) return ""
[docs] def resolve_options(self, context): """ :param context: Django template RequestContext :type context: django.template.RequestContext """ options = {} for key in self.options: value = self.options[key] options[key] = value.resolve(context) return options
[docs] def render_block(self, context, backend): """ :param context: Django template RequestContext :type context: django.template.RequestContext :param backend: Given instance inherited from VideoBackend :type backend: VideoBackend :rtype: django.utils.safestring.SafeText """ context.push() context[self.variable_name] = backend output = self.nodelist_file.render(context) context.pop() return output
[docs] @staticmethod 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. A string or VideoBackend instance can be passed to the method. :param backend: Given instance inherited from VideoBackend or url :type backend_or_url: VideoBackend | str :param context: Django template RequestContext :type context: django.template.RequestContext | None :rtype: VideoBackend """ backend = ( backend_or_url if isinstance(backend_or_url, VideoBackend) else detect_backend(str(backend_or_url)) ) if context and "request" in context: backend.is_secure = context["request"].is_secure() if options: backend.set_options(options) return backend
[docs] @classmethod def embed(cls, url, size, context=None, **options): """ Direct render of embed video. :param url: URL to embed video :type url: str :param size: Size of rendered block :type size: str :param context: Django template RequestContext :type context: django.template.RequestContext | None """ 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))
[docs] @classmethod def get_size(cls, value): """ Predefined sizes: ======== ======== ========= size width height ======== ======== ========= tiny 420 315 small 480 360 medium 640 480 large 960 720 huge 1280 960 ======== ======== ========= You can also use custom size - in format ``WIDTHxHEIGHT`` (eg. ``500x400``). :type value: str :return: Returns tuple with (width, height) values. :rtype: tuple[int, int] """ sizes = { "tiny": (420, 315), "small": (480, 360), "medium": (640, 480), "large": (960, 720), "huge": (1280, 960), } value = value or cls.default_size if value in sizes: return sizes[value] try: size = cls.re_size.match(value) return size.group("width"), size.group("height") except AttributeError: raise TemplateSyntaxError( "Incorrect size.\nPossible format is WIDTHxHEIGHT or using " "predefined size ({sizes}).".format(sizes=", ".join(sizes.keys())) )
def __iter__(self): for node in self.nodelist_file: yield node def __repr__(self): return '<VideoNode "%s">' % self.url