123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # Taken from sphinx-contrib
- # https://bitbucket.org/birkenfeld/sphinx-contrib/src/a3d904f8ab24/youtube
- # If not otherwise noted, the extensions in this package are licensed
- # under the following license.
- #
- # Copyright (c) 2009 by the contributors (see AUTHORS file).
- # All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are
- # met:
- #
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- #
- # * Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- from __future__ import division
- import re
- from docutils import nodes
- from docutils.parsers.rst import directives
- try:
- from sphinx.util.compat import Directive
- except ImportError:
- from docutils.parsers.rst import Directive
- CONTROL_HEIGHT = 30
- def get_size(d, key):
- if key not in d:
- return None
- m = re.match("(\d+)(|%|px)$", d[key])
- if not m:
- raise ValueError("invalid size %r" % d[key])
- return int(m.group(1)), m.group(2) or "px"
- def css(d):
- return "; ".join(sorted("%s: %s" % kv for kv in d.iteritems()))
- class youtube(nodes.General, nodes.Element):
- pass
- def visit_youtube_node(self, node):
- aspect = node["aspect"]
- width = node["width"]
- height = node["height"]
- if aspect is None:
- aspect = 16, 9
- if (height is None) and (width is not None) and (width[1] == "%"):
- style = {
- "padding-top": "%dpx" % CONTROL_HEIGHT,
- "padding-bottom": "%f%%" % (width[0] * aspect[1] / aspect[0]),
- "width": "%d%s" % width,
- "position": "relative",
- }
- self.body.append(self.starttag(node, "div", style=css(style)))
- style = {
- "position": "absolute",
- "top": "0",
- "left": "0",
- "width": "100%",
- "height": "100%",
- "border": "0",
- }
- attrs = {
- "src": "http://www.youtube.com/embed/%s" % node["id"],
- "style": css(style),
- }
- self.body.append(self.starttag(node, "iframe", **attrs))
- self.body.append("</iframe></div>")
- else:
- if width is None:
- if height is None:
- width = 560, "px"
- else:
- width = height[0] * aspect[0] / aspect[1], "px"
- if height is None:
- height = width[0] * aspect[1] / aspect[0], "px"
- style = {
- "width": "%d%s" % width,
- "height": "%d%s" % (height[0] + CONTROL_HEIGHT, height[1]),
- "border": "0",
- }
- attrs = {
- "src": "http://www.youtube.com/embed/%s" % node["id"],
- "style": css(style),
- }
- self.body.append(self.starttag(node, "iframe", **attrs))
- self.body.append("</iframe>")
- def depart_youtube_node(self, node):
- pass
- class YouTube(Directive):
- has_content = True
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = {
- "width": directives.unchanged,
- "height": directives.unchanged,
- "aspect": directives.unchanged,
- }
- def run(self):
- if "aspect" in self.options:
- aspect = self.options.get("aspect")
- m = re.match("(\d+):(\d+)", aspect)
- if m is None:
- raise ValueError("invalid aspect ratio %r" % aspect)
- aspect = tuple(int(x) for x in m.groups())
- else:
- aspect = None
- width = get_size(self.options, "width")
- height = get_size(self.options, "height")
- return [youtube(id=self.arguments[0], aspect=aspect, width=width, height=height)]
- def setup(app):
- app.add_node(youtube, html=(visit_youtube_node, depart_youtube_node))
- app.add_directive("youtube", YouTube)
|