Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[improvement] Include videos as images #65

Open
robinmoussu opened this issue Feb 2, 2015 · 7 comments
Open

[improvement] Include videos as images #65

robinmoussu opened this issue Feb 2, 2015 · 7 comments

Comments

@robinmoussu
Copy link

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.

@501337
Copy link

501337 commented May 21, 2015

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.

@regebro
Copy link
Owner

regebro commented May 22, 2015

Interesting, thanks, I'll take a look at this.

@einar-lanfranco
Copy link

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!

@perry-bothron
Copy link

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: eadb33f

@einar-lanfranco
Copy link

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>

@Nagasaki45
Copy link

Nagasaki45 commented Nov 15, 2016

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.

@vorpalvorpal
Copy link

vorpalvorpal commented Oct 4, 2017

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants