152 lines
6.4 KiB
HTML
152 lines
6.4 KiB
HTML
{{/*
|
||
视频嵌入 shortcode(Amigo 风格)
|
||
用法:
|
||
{{< video src="xxx.mp4" >}}
|
||
{{< video src="xxx.mp4" poster="cover.jpg" caption="说明" >}}
|
||
{{< video src="xxx.gif" loop="true" muted="true" >}} ← GIF 模式
|
||
{{< bilibili BV1xx411c7mD >}}
|
||
{{< youtube dQw4w9WgXcQ >}}
|
||
*/}}
|
||
|
||
{{ if .Get "bvid" | or (.Get 0) }}
|
||
{{/* Bilibili */}}
|
||
{{ $bvid := .Get "bvid" | default (.Get 0) }}
|
||
<div class="video-wrap">
|
||
<div class="video-embed">
|
||
<iframe
|
||
src="//player.bilibili.com/player.html?bvid={{ $bvid }}&high_quality=1&danmaku=0"
|
||
scrolling="no" frameborder="0" allowfullscreen="true" loading="lazy"
|
||
></iframe>
|
||
</div>
|
||
</div>
|
||
|
||
{{ else if .Get "id" | or (and (.Get 0) (not (.Get "src"))) }}
|
||
{{/* YouTube */}}
|
||
{{ $id := .Get "id" | default (.Get 0) }}
|
||
<div class="video-wrap">
|
||
<div class="video-embed">
|
||
<iframe
|
||
src="https://www.youtube.com/embed/{{ $id }}"
|
||
frameborder="0"
|
||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||
allowfullscreen="true" loading="lazy"
|
||
></iframe>
|
||
</div>
|
||
</div>
|
||
|
||
{{ else }}
|
||
{{/* 本地/外部视频 */}}
|
||
{{ $src := .Get "src" }}
|
||
{{ $poster := .Get "poster" }}
|
||
{{ $caption := .Get "caption" }}
|
||
{{ $loop := .Get "loop" | default "false" }}
|
||
{{ $muted := .Get "muted" | default "false" }}
|
||
{{ $isGifMode := or (eq $loop "true") (eq $muted "true") }}
|
||
{{ $videoSrc := $src }}
|
||
{{ $posterSrc := $poster }}
|
||
|
||
{{- if and $src (not (findRE "^(https?://|/)" $src)) -}}
|
||
{{- with .Page.Resources.GetMatch $src -}}
|
||
{{- $videoSrc = .RelPermalink -}}
|
||
{{- end -}}
|
||
{{- end -}}
|
||
|
||
{{- if and $poster (not (findRE "^(https?://|/)" $poster)) -}}
|
||
{{- with .Page.Resources.GetMatch $poster -}}
|
||
{{- $posterSrc = .RelPermalink -}}
|
||
{{- end -}}
|
||
{{- end -}}
|
||
|
||
{{ if $isGifMode }}
|
||
{{/* GIF 模式:图片标签显示,自动循环 */}}
|
||
<div class="video-wrap">
|
||
<img src="{{ $videoSrc }}" alt="{{ $caption }}" class="gif-image" loading="lazy">
|
||
{{ with $caption }}
|
||
<figcaption class="video-caption">{{ . }}</figcaption>
|
||
{{ end }}
|
||
</div>
|
||
{{ else }}
|
||
{{/* 视频模式:自定义播放器 */}}
|
||
<div class="video-wrap">
|
||
<figure class="video-player" onclick="toggleVideo(this)">
|
||
<video preload="metadata" playsinline webkit-playsinline {{ with $posterSrc }}poster="{{ . }}"{{ end }}>
|
||
<source src="{{ $videoSrc }}">
|
||
</video>
|
||
<div class="video-play-icon">
|
||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
|
||
</div>
|
||
<div class="video-controls">
|
||
<button class="video-ctrl-btn" onclick="event.stopPropagation(); togglePlay(this)">
|
||
<svg class="icon-play" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
|
||
<svg class="icon-pause" viewBox="0 0 24 24" fill="currentColor" style="display:none"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
|
||
</button>
|
||
<div class="video-progress" onclick="event.stopPropagation(); seekVideo(event, this)">
|
||
<div class="video-progress-bar"></div>
|
||
</div>
|
||
<span class="video-time">0:00</span>
|
||
<button class="video-ctrl-btn" onclick="event.stopPropagation(); toggleMute(this)">
|
||
<svg class="icon-unmute" viewBox="0 0 24 24" fill="currentColor"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>
|
||
<svg class="icon-mute" viewBox="0 0 24 24" fill="currentColor" style="display:none"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>
|
||
</button>
|
||
<button class="video-ctrl-btn" onclick="event.stopPropagation(); fullscreenVideo(this)">
|
||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>
|
||
</button>
|
||
</div>
|
||
</figure>
|
||
{{ with $caption }}
|
||
<figcaption class="video-caption">{{ . }}</figcaption>
|
||
{{ end }}
|
||
</div>
|
||
{{ end }}
|
||
{{ end }}
|
||
|
||
<script>
|
||
function toggleVideo(el) {
|
||
var video = el.querySelector('video');
|
||
if (!video) return;
|
||
if (video.paused) { video.play(); el.classList.add('playing'); }
|
||
else { video.pause(); el.classList.remove('playing'); }
|
||
}
|
||
function togglePlay(btn) {
|
||
var video = btn.closest('.video-player').querySelector('video');
|
||
if (video.paused) { video.play(); btn.closest('.video-player').classList.add('playing'); }
|
||
else { video.pause(); btn.closest('.video-player').classList.remove('playing'); }
|
||
}
|
||
function toggleMute(btn) {
|
||
var video = btn.closest('.video-player').querySelector('video');
|
||
video.muted = !video.muted;
|
||
btn.querySelector('.icon-unmute').style.display = video.muted ? 'none' : '';
|
||
btn.querySelector('.icon-mute').style.display = video.muted ? '' : 'none';
|
||
}
|
||
function seekVideo(e, bar) {
|
||
var video = bar.closest('.video-player').querySelector('video');
|
||
var rect = bar.getBoundingClientRect();
|
||
video.currentTime = ((e.clientX - rect.left) / rect.width) * video.duration;
|
||
}
|
||
function fullscreenVideo(btn) {
|
||
var el = btn.closest('.video-player');
|
||
if (el.requestFullscreen) el.requestFullscreen();
|
||
else if (el.webkitRequestFullscreen) el.webkitRequestFullscreen();
|
||
}
|
||
document.addEventListener('timeupdate', function(e) {
|
||
var video = e.target;
|
||
if (!video.closest) return;
|
||
var player = video.closest('.video-player');
|
||
if (!player) return;
|
||
var bar = player.querySelector('.video-progress-bar');
|
||
var time = player.querySelector('.video-time');
|
||
if (bar) bar.style.width = (video.currentTime / video.duration * 100) + '%';
|
||
if (time) {
|
||
var m = Math.floor(video.currentTime / 60);
|
||
var s = Math.floor(video.currentTime % 60);
|
||
time.textContent = m + ':' + (s < 10 ? '0' : '') + s;
|
||
}
|
||
var playIcon = player.querySelector('.icon-play');
|
||
var pauseIcon = player.querySelector('.icon-pause');
|
||
if (playIcon && pauseIcon) {
|
||
playIcon.style.display = video.paused ? '' : 'none';
|
||
pauseIcon.style.display = video.paused ? 'none' : '';
|
||
}
|
||
}, true);
|
||
</script>
|