Module

rendering.plugins.directives.video

Video embed directives for Bengal.

Provides directives for embedding videos from YouTube, Vimeo, and self-hosted sources with privacy-by-default, accessibility requirements, and responsive design.

Architecture:

  • VideoDirective: Abstract base class for video embeds
  • YouTubeDirective: YouTube with privacy-enhanced mode (youtube-nocookie.com)
  • VimeoDirective: Vimeo with Do Not Track mode
  • SelfHostedVideoDirective: Native HTML5 video for local files

Security:

All video IDs are validated via regex patterns to prevent XSS and injection.
Iframe embeds use appropriate sandbox attributes and CSP-friendly URLs.

Accessibility:

Title is required for all embeds to meet WCAG 2.1 AA requirements.
Fallback content provided for users without JavaScript/iframe support.

Related:

  • bengal/rendering/plugins/directives/base.py: BengalDirective
  • RFC: plan/active/rfc-media-embed-directives.md

Classes

VideoOptions dataclass
Common options for all video directives.
0

Common options for all video directives.

Inherits from DirectiveOptions

Attributes

Name Type Description
title str

Required - Accessible title for iframe/video (WCAG requirement)

aspect str

Aspect ratio for responsive container (default: 16/9)

css_class str

Additional CSS classes

autoplay bool

Auto-start video (not recommended for accessibility)

loop bool

Loop video playback

muted bool

Start video muted

_field_aliases ClassVar[dict[str, str]]
VideoDirective
Abstract base class for video embed directives. Provides common functionality for all video embeds…
3

Abstract base class for video embed directives.

Provides common functionality for all video embeds:

  • URL/ID validation via subclass patterns
  • Responsive container with aspect ratio
  • Accessibility requirements (title required)
  • Shared rendering utilities

Subclass Requirements:

ID_PATTERN: Compiled regex for validating video source
validate_source(): Validate and return error or None
build_embed_url(): Build the embed URL from source and options
Inherits from BengalDirective

Attributes

Name Type Description
ID_PATTERN ClassVar[re.Pattern[str]]

Methods 2

validate_source
Validate video source (ID or URL).
1 str | None
def validate_source(self, source: str) -> str | None

Validate video source (ID or URL).

Parameters 1
source str

Video ID or URL from directive argument

Returns

str | None

Error message if invalid, None if valid

build_embed_url
Build the embed URL from source and options.
2 str
def build_embed_url(self, source: str, options: VideoOptions) -> str

Build the embed URL from source and options.

Parameters 2
source str

Validated video source

options VideoOptions

Parsed directive options

Returns

str

Full embed URL

Internal Methods 1
_validate_title
Check that title is provided (accessibility requirement).
2 str | None
def _validate_title(self, title: str, source: str) -> str | None

Check that title is provided (accessibility requirement).

Parameters 2
title str
source str
Returns

str | None

YouTubeOptions dataclass
Options for YouTube video embed.
0

Options for YouTube video embed.

Inherits from VideoOptions

Attributes

Name Type Description
start int

Start time in seconds

end int | None

End time in seconds

privacy bool

Use youtube-nocookie.com (default: true for GDPR compliance)

controls bool

Show player controls

_field_aliases ClassVar[dict[str, str]]
title

Required - Accessible title for iframe

aspect

Aspect ratio (default: 16/9)

YouTubeDirective
YouTube video embed directive with privacy-enhanced mode. Uses youtube-nocookie.com by default for…
4

YouTube video embed directive with privacy-enhanced mode.

Uses youtube-nocookie.com by default for GDPR compliance. Validates YouTube video IDs (11 alphanumeric characters).

Syntax:

:::{youtube} dQw4w9WgXcQ
:title: Never Gonna Give You Up
:start: 30
:privacy: true
:::

Options:

:title: (required) Accessible title for iframe
:start: Start time in seconds
:end: End time in seconds
:privacy: Use youtube-nocookie.com (default: true)
:autoplay: Auto-start video (default: false)
:controls: Show player controls (default: true)
:loop: Loop video (default: false)
:muted: Start muted (default: false)
:aspect: Aspect ratio (default: 16/9)
:class: Additional CSS classes

Output:

<div class="video-embed youtube" data-aspect="16/9">
  <iframe src="https://www.youtube-nocookie.com/embed/..."
          title="..." loading="lazy" allowfullscreen></iframe>
</div>

Security:

  • Video ID validated via regex (11 alphanumeric + _ -)
  • XSS prevention via strict ID validation
  • Privacy mode uses youtube-nocookie.com domain
Inherits from VideoDirective

Attributes

Name Type Description
NAMES ClassVar[list[str]]
TOKEN_TYPE ClassVar[str]
OPTIONS_CLASS ClassVar[type[DirectiveOptions]]
DIRECTIVE_NAMES ClassVar[list[str]]
ID_PATTERN ClassVar[re.Pattern[str]]

Methods 4

validate_source
Validate YouTube video ID (11 alphanumeric chars).
1 str | None
def validate_source(self, video_id: str) -> str | None

Validate YouTube video ID (11 alphanumeric chars).

Parameters 1
video_id str
Returns

str | None

build_embed_url
Build YouTube embed URL with options.
2 str
def build_embed_url(self, video_id: str, options: YouTubeOptions) -> str

Build YouTube embed URL with options.

Parameters 2
video_id str
options YouTubeOptions
Returns

str

parse_directive
Build YouTube embed token.
5 DirectiveToken
def parse_directive(self, title: str, options: YouTubeOptions, content: str, children: list[Any], state: Any) -> DirectiveToken

Build YouTube embed token.

Parameters 5
title str
options YouTubeOptions
content str
children list[Any]
state Any
Returns

DirectiveToken

render
Render YouTube embed to HTML.
2 str
def render(self, renderer: Any, text: str, **attrs: Any) -> str

Render YouTube embed to HTML.

Parameters 2
renderer Any
text str
Returns

str

VimeoOptions dataclass
Options for Vimeo video embed.
0

Options for Vimeo video embed.

Inherits from VideoOptions

Attributes

Name Type Description
color str

Player accent color (hex without #)

autopause bool

Pause when another video starts (default: true)

dnt bool

Do Not Track mode (default: true for privacy)

background bool

Background mode - no controls (default: false)

_field_aliases ClassVar[dict[str, str]]
title

Required - Accessible title for iframe

aspect

Aspect ratio (default: 16/9)

VimeoDirective
Vimeo video embed directive with Do Not Track mode. Uses dnt=1 by default for privacy compliance. …
4

Vimeo video embed directive with Do Not Track mode.

Uses dnt=1 by default for privacy compliance. Validates Vimeo video IDs (6-11 digits).

Syntax:

:::{vimeo} 123456789
:title: My Vimeo Video
:color: ff0000
:::

Options:

:title: (required) Accessible title for iframe
:color: Player accent color (hex without #)
:autopause: Pause when another video starts (default: true)
:dnt: Do Not Track mode (default: true)
:background: Background mode - no controls (default: false)
:autoplay: Auto-start video (default: false)
:loop: Loop video (default: false)
:muted: Start muted (default: false)
:aspect: Aspect ratio (default: 16/9)
:class: Additional CSS classes

Security:

  • Video ID validated via regex (6-11 digits)
  • DNT mode respects user privacy preferences
Inherits from VideoDirective

Attributes

Name Type Description
NAMES ClassVar[list[str]]
TOKEN_TYPE ClassVar[str]
OPTIONS_CLASS ClassVar[type[DirectiveOptions]]
DIRECTIVE_NAMES ClassVar[list[str]]
ID_PATTERN ClassVar[re.Pattern[str]]

Methods 4

validate_source
Validate Vimeo video ID (6-11 digits).
1 str | None
def validate_source(self, video_id: str) -> str | None

Validate Vimeo video ID (6-11 digits).

Parameters 1
video_id str
Returns

str | None

build_embed_url
Build Vimeo embed URL with options.
2 str
def build_embed_url(self, video_id: str, options: VimeoOptions) -> str

Build Vimeo embed URL with options.

Parameters 2
video_id str
options VimeoOptions
Returns

str

parse_directive
Build Vimeo embed token.
5 DirectiveToken
def parse_directive(self, title: str, options: VimeoOptions, content: str, children: list[Any], state: Any) -> DirectiveToken

Build Vimeo embed token.

Parameters 5
title str
options VimeoOptions
content str
children list[Any]
state Any
Returns

DirectiveToken

render
Render Vimeo embed to HTML.
2 str
def render(self, renderer: Any, text: str, **attrs: Any) -> str

Render Vimeo embed to HTML.

Parameters 2
renderer Any
text str
Returns

str

SelfHostedVideoOptions dataclass
Options for self-hosted video embed.
0

Options for self-hosted video embed.

Inherits from VideoOptions

Attributes

Name Type Description
poster str

Poster image URL

controls bool

Show video controls (default: true)

preload str

Preload mode - none, metadata, auto (default: metadata)

width str

Video width (px or %)

_field_aliases ClassVar[dict[str, str]]
_allowed_values ClassVar[dict[str, list[str]]]
title

Required - Accessible title for video element

aspect

Aspect ratio (default: 16/9)

SelfHostedVideoDirective
Self-hosted video directive using HTML5 video element. Provides native video playback for local or…
5

Self-hosted video directive using HTML5 video element.

Provides native video playback for local or CDN-hosted video files. Supports poster images, controls, and accessibility requirements.

Syntax:

:::{video} /assets/demo.mp4
:title: Product Demo
:poster: /assets/demo-poster.jpg
:controls: true
:::

Options:

:title: (required) Accessible title for video
:poster: Poster image URL shown before playback
:controls: Show video controls (default: true)
:autoplay: Auto-start video (requires muted) (default: false)
:muted: Start muted (default: false)
:loop: Loop video (default: false)
:preload: Preload mode - none, metadata, auto (default: metadata)
:width: Video width (default: 100%)
:aspect: Aspect ratio (default: 16/9)
:class: Additional CSS classes

Output:

<figure class="video-embed self-hosted">
  <video title="..." controls preload="metadata">
    <source src="..." type="video/mp4">
    <p>Fallback text with download link</p>
  </video>
</figure>

Supported formats (auto-detected from extension):

  • .mp4 (video/mp4)
  • .webm (video/webm)
  • .ogg (video/ogg)
  • .mov (video/quicktime)
Inherits from VideoDirective

Attributes

Name Type Description
NAMES ClassVar[list[str]]
TOKEN_TYPE ClassVar[str]
OPTIONS_CLASS ClassVar[type[DirectiveOptions]]
DIRECTIVE_NAMES ClassVar[list[str]]
ID_PATTERN ClassVar[re.Pattern[str]]
MIME_TYPES ClassVar[dict[str, str]]

Methods 4

validate_source
Validate video path/URL.
1 str | None
def validate_source(self, video_path: str) -> str | None

Validate video path/URL.

Parameters 1
video_path str
Returns

str | None

build_embed_url
Return video path (no transformation needed for self-hosted).
2 str
def build_embed_url(self, video_path: str, options: SelfHostedVideoOptions) -> str

Return video path (no transformation needed for self-hosted).

Parameters 2
video_path str
options SelfHostedVideoOptions
Returns

str

parse_directive
Build self-hosted video token.
5 DirectiveToken
def parse_directive(self, title: str, options: SelfHostedVideoOptions, content: str, children: list[Any], state: Any) -> DirectiveToken

Build self-hosted video token.

Parameters 5
title str
options SelfHostedVideoOptions
content str
children list[Any]
state Any
Returns

DirectiveToken

render
Render self-hosted video to HTML.
2 str
def render(self, renderer: Any, text: str, **attrs: Any) -> str

Render self-hosted video to HTML.

Parameters 2
renderer Any
text str
Returns

str

Internal Methods 1
_get_mime_type
Get MIME type from video path extension.
1 str
def _get_mime_type(self, video_path: str) -> str

Get MIME type from video path extension.

Parameters 1
video_path str
Returns

str