diff --git a/sphinxcontrib/video.py b/sphinxcontrib/video.py index 6e176cd..560f0b8 100644 --- a/sphinxcontrib/video.py +++ b/sphinxcontrib/video.py @@ -1,13 +1,14 @@ """Video extention to embed video in a html sphinx output.""" +import urllib.parse from pathlib import Path from typing import Any, Dict, List, Tuple -from urllib.parse import urlparse from docutils import nodes from docutils.parsers.rst import directives from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment +from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util import logging from sphinx.util.docutils import SphinxDirective, SphinxTranslator from sphinx.writers.html import HTMLTranslator @@ -39,7 +40,7 @@ "List of the supported options attributes" -def get_video(src: str, env: BuildEnvironment) -> Tuple[str, str]: +def get_video(src: str, env: BuildEnvironment) -> Tuple[str, str, bool]: """Return video and suffix. Load the video to the static directory if necessary and process the suffix. Raise a warning if not supported but do not stop the computation. @@ -49,11 +50,8 @@ def get_video(src: str, env: BuildEnvironment) -> Tuple[str, str]: env: the build environment Returns: - the src file, the extention suffix + The src file, the extension suffix, whether the file is remote """ - if not bool(urlparse(src).netloc): - env.images.add_file("", src) - suffix = Path(src).suffix if suffix not in SUPPORTED_MIME_TYPES: logger.warning( @@ -61,7 +59,16 @@ def get_video(src: str, env: BuildEnvironment) -> Tuple[str, str]: ) type = SUPPORTED_MIME_TYPES.get(suffix, "") - return (src, type) + is_remote = bool(urllib.parse.urlparse(src).netloc) + if not is_remote: + # Map video paths to unique names (so that they can be put into a single + # directory). This copies what is done for images by the process_docs method of + # sphinx.environment.collectors.asset.ImageCollector. + src, fullpath = env.relfn2path(src, env.docname) + env.note_dependency(fullpath) + env.images.add_file(env.docname, src) + + return (src, type, is_remote) class video_node(nodes.General, nodes.Element): @@ -120,12 +127,11 @@ def run(self) -> List[video_node]: preload = "auto" # add the primary video files as images in the builder - primary_src = get_video(self.arguments[0], env) + sources = [get_video(self.arguments[0], env)] # add the secondary video files as images in the builder if necessary - secondary_src = None if len(self.arguments) == 2: - secondary_src = get_video(self.arguments[1], env) + sources.append(get_video(self.arguments[1], env)) elif env.config.video_enforce_extra_source is True: logger.warning( f'A secondary source should be provided for "{self.arguments[0]}"' @@ -133,8 +139,7 @@ def run(self) -> List[video_node]: return [ video_node( - primary_src=primary_src, - secondary_src=secondary_src, + sources=sources, alt=self.options.get("alt", ""), autoplay="autoplay" in self.options, controls="nocontrols" not in self.options, @@ -149,6 +154,34 @@ def run(self) -> List[video_node]: ] +class VideoPostTransform(SphinxPostTransform): + """Ensure video files are copied to build directory. + + This copies what is done for images in the post_process_image method of + sphinx.builders.Builder, except as a Transform since we can't hook into that method + directly. + """ + + default_priority = 200 + + def run(self): + """Add video files to Builder's image tracking. + + Doing so ensures that the builder copies the files to the output directory. + """ + # TODO: This check can be removed when the minimum supported docutils version + # is docutils>=0.18.1. + traverse_or_findall = ( + self.document.findall + if hasattr(self.document, "findall") + else self.document.traverse + ) + for node in traverse_or_findall(video_node): + for src, _, is_remote in node["sources"]: + if not is_remote: + self.app.builder.images[src] = self.env.images[src][1] + + def visit_video_node_html(translator: HTMLTranslator, node: video_node) -> None: """Entry point of the html video node.""" # start the video block @@ -158,10 +191,16 @@ def visit_video_node_html(translator: HTMLTranslator, node: video_node) -> None: html: str = f" diff --git a/tests/test_build/video_options.html b/tests/test_build/video_options.html index f64ff59..522f3b2 100644 --- a/tests/test_build/video_options.html +++ b/tests/test_build/video_options.html @@ -1,4 +1,4 @@ \ No newline at end of file + diff --git a/tests/test_build/video_secondary.html b/tests/test_build/video_secondary.html index 1354273..43cf07a 100644 --- a/tests/test_build/video_secondary.html +++ b/tests/test_build/video_secondary.html @@ -1,4 +1,4 @@ \ No newline at end of file + + + diff --git a/tests/test_build/video_wrong_format.html b/tests/test_build/video_wrong_format.html index f25853b..79b7fe3 100644 --- a/tests/test_build/video_wrong_format.html +++ b/tests/test_build/video_wrong_format.html @@ -1,3 +1,3 @@ \ No newline at end of file + +