This is a shortcode include videos hosted on any Peertube instance.
Peertube is a decentralized and federated video streaming and hosting platform: using ActivityPub protocol for federation and P2P directly in the web browser for distributed downloading of data.
At this point this shortcode is early beta and was only tested localy with Hugo 0.76.0, last Firefox and Chrome on MacOS, and with video from various instance of Peertube.
Install
Just copy the peertube.html file in the layouts/shortcodes/ directory at the root of your Hugo site. You have to create the layouts and shortcodes directories if they does not exist. You can learn more about shortcodes from Hugo documentation.
Thatâs all Folks.
Usage
Insert the Shortcode in your Markdown contentâŚ
Simplified syntax
Easy to use, but only default options.
Domain Name of instance: without https:// nor training slatch (/)
None
id
Identification Code of the video (ex: d49f95a9-b183-4f16-9341-8637ac3597ff)
None
title
Display the video Title: 0 (no) or 1 (yes)
0
warning
Display a Warning about privacy: 0 (no) or 1 (yes)
0
subtitle
Display the video subtitle if exist: langage code (ex: fr)
0
Note: The default options are hard coded, if you want du change, you have to modify the source.
Privacy
1) Peertube by itself use absolutely no cookies, no trackers.
2) The uses the BitTorrent P2P protocol to share bandwidth between users by default to help lower the load on the server induce that your IP address is being stored in the instanceâs BitTorrent tracker as long as you download or watch the video For more info read this Peertube statement.
I copied the peertube shortcode to my shortcode folder and added {{< peertube url="https://video.ploud.fr/w/bmTZ68Grh97VsArAdSJtqW" >}} to my .md post, deployed it on my server.
Here is what I have when trying to render my blog locally:
~/Bureau/hugo/blog > hugo server
port 1313 already in use, attempting to use an available port
Watching for changes in /home/arnauld/Bureau/hugo/blog/{archetypes,assets,content,data,i18n,layouts,static,themes}
Watching for config changes in /home/arnauld/Bureau/hugo/blog/hugo.toml
Start building sites âŚ
hugo v0.147.3+extended+withdeploy linux/amd64 BuildDate=unknown
WARN Raw HTML omitted while rendering â/home/arnauld/Bureau/hugo/blog/content/about.mdâ; see Configure markup
You can suppress this warning by adding the following to your site configuration:
ignoreLogs = [âwarning-goldmark-raw-htmlâ]
Built in 30 ms
Error: error building site: render: failed to render pages: render of â/home/arnauld/Bureau/hugo/blog/content/posts/popcorn-haikou.mdâ failed: â/home/arnauld/Bureau/hugo/blog/themes/archie/layouts/_default/single.html:17:13â: execute of template failed: template: single.html:17:13: executing âmainâ at <.Content>: error calling Content: â/home/arnauld/Bureau/hugo/blog/content/posts/popcorn-haikou.md:14:1â: failed to render shortcode âpeertubeâ: failed to process shortcode: â/home/arnauld/Bureau/hugo/blog/themes/archie/layouts/shortcodes/peertube.html:161:45â: execute of template failed: template: _shortcodes/peertube.html:161:45: executing â_shortcodes/peertube.htmlâ at <div 1>: error calling div: canât apply the operator to the values
The API is returning null for the aspect ratio, which is (a) unexpected and (b) not helpful. I need to think about this for a bit. API calls for other videos on the same server are fine. For example:
I edited my previous reply. The instance isnât the problem. I think itâs the API version under which the video was originally uploaded. Perhaps you can confirm that.
If this were an embedded (built-in) shortcode, I might spend some time coming up with a reliable way to determine the aspect ratio when not provided. However, I would be more inclined to throw an error, something like:
The Peertube API reported a null aspect ratio for this video, probably indicating that it was originally uploaded to an instance running Peertube v6.0.4 or earlier. This shortcode is compatible with videos uploaded to an instance running Peertube v6.1.0 or later.
So yeah, I would re-upload under the newer API. Unless thereâs a way to update-in-place.
I disagree with my previous reply. Itâs impractical and not user-friendly.
For nowâŚ
I would re-upload under the newer API. Unless thereâs a way to update-in-place.
And I will spend some time on this when I can.
Notes to self:
If aspect ratio is null, make a second call (yuck) to metadataUrl and use the display_aspect_ratio from the VideoHandler stream if present. I canât come up with another way to do this.
This problem may be specific to one or more instances. When upgrading the API, sometimes you need to manually execute a migration scrip to update video files metadata in the database. Perhaps the migration script wasnât run, or perhaps the migration script didnât handle this part of the update.
This revision of the shortcode also handles videos uploaded prior to v6.1.0 (i.e., those without an aspect ratio in the initial API response). We have to make a secondary API call (which isnât great), but (a) it shouldnât be required too often, and (b) we cache the result of the API call(s).
layouts/_shortcodes/peertube.html
{{- /*
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 -}}
Iâve also updated the example repo:
git clone --single-branch -b hugo-github-issue-13280 https://github.com/jmooring/hugo-testing hugo-github-issue-13280
cd hugo-github-issue-13280
hugo server