Embed PeerTube videos
Hugo lacks a native shortcode for PeerTube embeds. Using a custom shortcode allows you to display videos by providing a URL and optional parameters instead of pasting raw HTML into Markdown files. This keeps the source code clean and centralizes the embed logic in one template file.
Example
Use the following syntax in your Markdown files to display a Peertube video.
{{< peertube url="https://toobnix.org/w/5jBegFpNbffA1nhmp32kqR" >}}Arguments
Use these arguments to configure the video player.
- url
- (
string) The URL of the PeerTube video. - start
- (
string) The time, from the start of the video, when the player should start playing the video (e.g.,42s,6m7s). - stop
- (
string) The time, from the start of the video, when the player should stop playing the video (e.g.,42s,6m7s). - loading
- (
string) The loading attribute of theiframeelement, eithereagerorlazy. Default iseager. - width
- (
int) The width of the video in pixels. Responsive if0. Default is0. - allowFullScreen
- (
bool) Whether to allow full screen playback. Default istrue. - autoplay
- (
bool) Whether to automatically play the video. Forcesmutetotrue. Default isfalse. - controls
- (
bool) Whether to display the video controls. Default istrue. - displayLink
- (
bool) Whether to display the video link. Default istrue. - displayTitle
- (
bool) Whether to display the video title. Default istrue. - displayWarning
- (
bool) Whether to display the privacy warning. Default istrue. - loop
- (
bool) Whether to indefinitely repeat the video. Default isfalse. - mute
- (
bool) Whether to mute the video. Alwaystruewhenautoplayistrue. Default isfalse. - p2p
- (
bool) Whether to enable peer-to-peer bandwidth sharing. Default istrue.
Source
Add this shortcode template to your project.
layouts/_shortcodes/peertube.html
{{- /* Last modified: 2026-03-15T10:30:19-07:00 */}}
{{- /*
Copyright 2025 Veriphor, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
*/}}
{{- /*
Embeds a PeerTube video.
@param {string} url The URL of the PeerTube video.
@param {string} [start] The time, from the start of the video, when the player should start playing the video (e.g., 42s, 6m7s).
@param {string} [stop] The time, from the start of the video, when the player should stop playing the video (e.g., 42s, 6m7s).
@param {string} [loading=eager] The loading attribute of the iframe element, either eager or lazy. Default is eager.
@param {int} [width=0] The width of the video in pixels. Responsive if `0`.
@param {bool} [allowFullScreen=true] Whether to allow full screen playback.
@param {bool} [autoplay=false] Whether to automatically play the video. Forces mute to true.
@param {bool} [controls=true] Whether to display the video controls.
@param {bool} [displayLink=true] Whether to display the PeerTube link.
@param {bool} [displayTitle=true] Whether to display the video title.
@param {bool} [displayWarning=true] Whether to display the privacy warning.
@param {bool} [loop=false] Whether to indefinitely repeat the video.
@param {bool} [mute=false] Whether to mute the video. Always true when autoplay is true.
@param {bool} [p2p=true] Whether to enable peer-to-peer bandwidth sharing.
@returns {template.HTML}
@link https://docs.joinpeertube.org/api/embed-player
@example {{< peertube url="https://toobnix.org/w/5jBegFpNbffA1nhmp32kqR" >}}
*/}}
{{- /* Set constants. */}}
{{- $trueValues := slice "true" true 1 }}
{{- $falseValues := slice "false" false 0 }}
{{- $sandbox := "allow-same-origin allow-scripts allow-popups allow-forms" }}
{{- /* Set defaults. */}}
{{- $url := "" }}
{{- $start := "" }}
{{- $stop := "" }}
{{- $loading := "eager" }}
{{- $width := 0 }}
{{- $height := 0 }}
{{- $allowFullScreen := true }}
{{- $autoplay := false }}
{{- $controls := true }}
{{- $displayLink := true }}
{{- $displayTitle := true }}
{{- $displayWarning := true }}
{{- $loop := false }}
{{- $mute := false }}
{{- $p2p := true }}
{{- /* Get parameters. */}}
{{- $url = or (.Get "url") $url }}
{{- $start := or (.Get "start") $start }}
{{- $stop := or (.Get "stop") $stop }}
{{- $width = or (.Get "width") $width | int }}
{{- $loading := or (.Get "loading") $loading }}
{{- if in $trueValues (.Get "allowFullScreen") }}
{{- $allowFullScreen = true }}
{{- else if in $falseValues (.Get "allowFullScreen") }}
{{- $allowFullScreen = false }}
{{- end }}
{{- if in $trueValues (.Get "autoplay") }}
{{- $autoplay = true }}
{{- else if in $falseValues (.Get "autoplay") }}
{{- $autoplay = false }}
{{- end }}
{{- if in $trueValues (.Get "controls") }}
{{- $controls = true }}
{{- else if in $falseValues (.Get "controls") }}
{{- $controls = false }}
{{- end }}
{{- if in $trueValues (.Get "displayLink") }}
{{- $displayLink = true }}
{{- else if in $falseValues (.Get "displayLink") }}
{{- $displayLink = false }}
{{- end }}
{{- if in $trueValues (.Get "displayTitle") }}
{{- $displayTitle = true }}
{{- else if in $falseValues (.Get "displayTitle") }}
{{- $displayTitle = false }}
{{- end }}
{{- if in $trueValues (.Get "displayWarning") }}
{{- $displayWarning = true }}
{{- else if in $falseValues (.Get "displayWarning") }}
{{- $displayWarning = false }}
{{- end }}
{{- if in $trueValues (.Get "loop") }}
{{- $loop = true }}
{{- else if in $falseValues (.Get "loop") }}
{{- $loop = false }}
{{- end }}
{{- if in $trueValues (.Get "mute") }}
{{- $mute = true }}
{{- else if in $falseValues (.Get "mute") }}
{{- $mute = false }}
{{- end }}
{{- if in $trueValues (.Get "p2p") }}
{{- $p2p = true }}
{{- else if in $falseValues (.Get "p2p") }}
{{- $p2p = false }}
{{- end }}
{{- /* Mute if autoplay enabled. */}}
{{- if $autoplay }}
{{- $mute = true }}
{{- end }}
{{- if $url }}
{{- /* Determine API URL. */}}
{{- $u := urls.Parse $url }}
{{- $pathSegments := strings.Split $u.Path "/" }}
{{- $shortUUID := index $pathSegments (sub (len $pathSegments) 1) }}
{{- $api := fmt.Printf "%s://%s/api/v1/videos/%s" $u.Scheme $u.Host $shortUUID }}
{{- /* Get data from API. */}}
{{- $data := "" }}
{{- with try (resources.GetRemote $api) }}
{{- with .Err }}
{{- errorf "%s" . }}
{{- else with .Value }}
{{- $data = . | transform.Unmarshal }}
{{- /* Handle null aspect ratio for videos uploaded prior to PeerTube API v6.1.0. */}}
{{- if not $data.aspectRatio }}
{{- $aspectRatio := partial "inline/peertube/get-aspect-ratio.html" (dict "data" $data "name" $.Name "position" $.Position) }}
{{- $data = merge $data (dict "aspectRatio" $aspectRatio) }}
{{- end }}
{{- else }}
{{- warnidf "shortcode-peertube" "The %q shortcode was unable to retrieve the remote data. See %s" $.Name $.Position }}
{{- end }}
{{- end }}
{{- if $data }}
{{- /* Build src attribute. */}}
{{- $qsp := dict
"autoplay" (cond $autoplay 1 0)
"controlBar" (cond $controls 1 0)
"loop" (cond $loop 1 0)
"muted" (cond $mute 1 0)
"peertubeLink" (cond $displayLink 1 0)
"p2p" (cond $p2p 1 0)
"title" (cond $displayTitle 1 0)
"warningTitle" (cond $displayWarning 1 0)
}}
{{- with $start }}
{{- $qsp = merge $qsp (dict "start" .) }}
{{- end }}
{{- with $stop }}
{{- $qsp = merge $qsp (dict "stop" .) }}
{{- end }}
{{- $qs := collections.Querify $qsp }}
{{- $src := fmt.Printf "%s://%s%s?%s" $u.Scheme $u.Host $data.embedPath $qs }}
{{- /* Render. */}}
{{- if $width }}
{{- $height = div $width $data.aspectRatio | math.Round }}
<iframe
{{- if $allowFullScreen }} allowfullscreen {{- end }}
width="{{ $width }}"
height="{{ $height }}"
frameborder="0"
loading="{{ $loading }}"
title="{{ $data.name }}"
sandbox="{{ $sandbox }}"
src="{{ $src }}"
></iframe>
{{- else }}
{{- $width = "100%" }}
{{- $height = "100%" }}
{{- $paddingTop := $data.aspectRatio | div 1 | mul 100 | fmt.Printf "%2.2f%%" }}
<div style="position: relative; padding-top: {{ $paddingTop }};">
<iframe
{{- if $allowFullScreen }} allowfullscreen {{- end }}
width="{{ $width }}"
height="{{ $height }}"
frameborder="0"
loading="{{ $loading }}"
title="{{ $data.name }}"
sandbox="{{ $sandbox }}"
style="position: absolute; inset: 0px;"
src="{{ $src }}"
></iframe>
</div>
{{- end }}
{{- end }}
{{- else }}
{{- errorf "The %q shortcode requires a %q argument. See %s" .Name "url" .Position }}
{{- end -}}
{{- define "_partials/inline/peertube/get-aspect-ratio.html" }}
{{- $aspectRatio := 0 }}
{{- $metadataUrl := "" }}
{{- range .data.streamingPlaylists }}
{{- range .files }}
{{- if .hasVideo }}
{{- $metadataUrl = .metadataUrl }}
{{- break }}
{{- end }}
{{- end }}
{{- if $metadataUrl }}
{{- break }}
{{- end }}
{{- end }}
{{- with $metadataUrl }}
{{- with try (resources.GetRemote .) }}
{{- with .Err }}
{{- errorf "%s" . }}
{{- else with .Value }}
{{- with . | transform.Unmarshal }}
{{- range .streams }}
{{- if and .width .height }}
{{- $aspectRatio = div .width .height }}
{{- break }}
{{- end }}
{{- end }}
{{- if not $aspectRatio }}
{{- errorf "The %q shortcode was unable to determine the aspect ratio. See %s" $.name $.position }}
{{ end }}
{{- end }}
{{- else }}
{{- errorf "The %q shortcode was unable to retrieve the metadata. See %s" $.name $.position }}
{{- end }}
{{- end }}
{{- else }}
{{- errorf "The %q shortcode was unable to determine the metadata URL. See %s" $.name $.position }}
{{- end }}
{{- return $aspectRatio }}
{{- end -}}
Last modified:
