hovercraft
hovercraft copied to clipboard
[improvement] Include videos as images
I have no ideas if it is complicated to add videos support. I thing that the syntax for the images can be used. Something like the following exemple can be great.
.. video:: path/to/videos.webm
:height: 600px
:width: 800px
For the moment, I use gif as a workaround, but native support of videos can be better.
I spent some time to get the native html5 video support in hovercraft. For this you don't only have to change hovercraft but also docutils.
This is only a quick and dirty solution, feel free to adapt it to your wishes.
First you have to change the reST.xsl. I just copied the image entry and added the type-attribute:
<xsl:template match="video">
<xsl:element name="video">
<xsl:attribute name="src">
<xsl:value-of select="@uri" />
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="@type" />
</xsl:attribute>
<xsl:if test="@alt">
<xsl:attribute name="alt">
<xsl:value-of select="@alt" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@width">
<xsl:attribute name="width">
<xsl:value-of select="@width" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@height">
<xsl:attribute name="height">
<xsl:value-of select="@height" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@classes">
<xsl:attribute name="class">
<xsl:value-of select="@classes" />
</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:template>
You should think about adding support for controls, autoplay etc..
That's all for hovercraft itself. Just make a slide in your presentation.rst:
----
.. video:: path/to/video.mp4
:type: video/mp4
Now you have to fix docutils to get it working with video files. First you have to create a reStructuredText Directive. I copied the class Image
from the docutils\parsers\rst\directives\images.py
, named it class Video
, added the new option "type" and saved it as videos.py
"""
Directives for videos.
"""
__docformat__ = 'reStructuredText'
import sys
import urllib.request, urllib.parse, urllib.error
from docutils import nodes, utils
from docutils.parsers.rst import Directive
from docutils.parsers.rst import directives, states
from docutils.nodes import fully_normalize_name, whitespace_normalize_name
from docutils.parsers.rst.roles import set_classes
class Video(Directive):
align_h_values = ('left', 'center', 'right')
align_v_values = ('top', 'middle', 'bottom')
align_values = align_v_values + align_h_values
def align(argument):
# This is not callable as self.align. We cannot make it a
# staticmethod because we're saving an unbound method in
# option_spec below.
return directives.choice(argument, Video.align_values)
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {'alt': directives.unchanged,
'type': directives.unchanged,
'height': directives.length_or_unitless,
'width': directives.length_or_percentage_or_unitless,
'scale': directives.percentage,
'align': align,
'name': directives.unchanged,
'target': directives.unchanged_required,
'class': directives.class_option}
def run(self):
if 'align' in self.options:
if isinstance(self.state, states.SubstitutionDef):
# Check for align_v_values.
if self.options['align'] not in self.align_v_values:
raise self.error(
'Error in "%s" directive: "%s" is not a valid value '
'for the "align" option within a substitution '
'definition. Valid values for "align" are: "%s".'
% (self.name, self.options['align'],
'", "'.join(self.align_v_values)))
elif self.options['align'] not in self.align_h_values:
raise self.error(
'Error in "%s" directive: "%s" is not a valid value for '
'the "align" option. Valid values for "align" are: "%s".'
% (self.name, self.options['align'],
'", "'.join(self.align_h_values)))
messages = []
reference = directives.uri(self.arguments[0])
self.options['uri'] = reference
reference_node = None
if 'target' in self.options:
block = states.escape2null(
self.options['target']).splitlines()
block = [line for line in block]
target_type, data = self.state.parse_target(
block, self.block_text, self.lineno)
if target_type == 'refuri':
reference_node = nodes.reference(refuri=data)
elif target_type == 'refname':
reference_node = nodes.reference(
refname=fully_normalize_name(data),
name=whitespace_normalize_name(data))
reference_node.indirect_reference_name = data
self.state.document.note_refname(reference_node)
else: # malformed target
messages.append(data) # data is a system message
del self.options['target']
set_classes(self.options)
video_node = nodes.video(self.block_text, **self.options)
self.add_name(video_node)
if reference_node:
reference_node += video_node
return messages + [reference_node]
else:
return messages + [video_node]
I didn't spent time to understand the code in detail, maybe there is a better solution.
To get it working you also have to change the docutils/nodes.py
. I copied the class image and named it video. You also have to add video
to the node_class_names
list.
Almost done. Now you have to register the new video directive. Add the line 'video': ('videos', 'Video')
to the dictionary _directive_registry
in the file docutils/parsers/rst/directives/__init__.py
.
Finally you have to edit the language files:
Add an entry to the directives dictionary in docutils/parsers/rst/languages/en.py for the directive, mapping the English name to the canonical name (both lowercase). Usually the English name and the canonical name are the same. Update all the other language modules as well. For languages in which you are proficient, please add translations. For other languages, add the English directive name plus "(translation required)". docutils/parsers/rst/directives/init.py
With these adaptions I was able to include a mp4 video to a presentation. This comment is hopefully a good start to get an official support for including videos in presentations with hovercraft. Feel free to improve my solution, because I'm not really familiar with docutils, hovercraft and programming in html.
Interesting, thanks, I'll take a look at this.
Great !!! I just modified 2 things. One to eliminate type and other to add controls.
In reST.xls i removed the type entry and add a controls one:
<xsl:template match="video">
<xsl:element name="video">
<xsl:attribute name="src">
<xsl:value-of select="@uri" />
</xsl:attribute>
<xsl:if test="@alt">
<xsl:attribute name="alt">
<xsl:value-of select="@alt" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@width">
<xsl:attribute name="width">
<xsl:value-of select="@width" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@controls">
<xsl:attribute name="controls">
</xsl:attribute>
</xsl:if>
<xsl:if test="@height">
<xsl:attribute name="height">
<xsl:value-of select="@height" />
</xsl:attribute>
</xsl:if>
<xsl:if test="@classes">
<xsl:attribute name="class">
<xsl:value-of select="@classes" />
</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:template>
Finally in videos.py I added a line 'controls': directives.unchanged to option_sec
option_spec= {'alt': directives.unchanged,
'type': directives.unchanged,
'height': directives.length_or_unitless,
'width': directives.length_or_percentage_or_unitless,
'scale': directives.percentage,
'align': align,
'name': directives.unchanged,
'target': directives.unchanged_required,
'class': directives.class_option,
'controls': directives.unchanged}
Tx a lot agains!
I've found a simpler way to add video support to hovercraft!, and without the need to modify reST.xsl
.
It requires one change to generate.py
in hovercraft!, and the use of a .. raw::
directive in the restructured text.
See here: eadb33fd12adb75e60b273224b8d877684dfbad8
perry-bothron is rigth!
Just write:
.. raw:: html
<video width="100%" controls>
<source src="imagenes/video.ogv" type="video/mp4">
Tu navegador no soporta videos.
</video>
The general idea is great. I'm doing somthing similar, now with an audio tag.
<audio controls="controls">
<source src="my-audio-file.mp3" type="audio/mp3"></source>
</audio>
@perry-bothron's solution should be somehow generalized.
I've created a video and audio directive for hovercraft (and improved the image directive). I put them both in a new folder "local_directives" and put in the relevant hooks for people to be able to create other custom directives without having to fish around in hovercraft's or docutil's code. Anyway, the code is at https://github.com/vorpalvorpal/hovercraft. I'm new to github, so I have no idea how to request it be merged. Anyways, some of what I've done is probably overkill for live presentations but 1) I wanted to create something that could be easily reused by other projects that need a video/audio directive, because the other video directive examples I found online were limited, and 2) I want to slowly make hovercraft more suitable for non-live presentations as well, in which case things like subtitle tracks make lots of sense.
Oh, and there's no documentation yet. But I'll do some shortly. I promise...