Apple 推出 实况照片 (Live Photos) 很多年了,它会在手机拍摄一张照片的同时,记录下数秒时间的有声影像,使得定格的瞬间可以有更多的「现场感」和「故事感」。后来 Google 推出了自己的 动态照片 (Motion Photos),尽管他们在实现原理上还存在着一些不同,但基本上都可以将它们理解为一张静态图片 + 一段有声的瞬间 + 一些其他信息。
今年,随着各个社交平台对实况照片的支持,我们可能越来越喜欢这种更生动有趣的记录方式。本文主要介绍在 Hugo 静态博客网站上优雅地展示 Live Photos 或 Motion Photos 的方式。
值得注意的是,目前在 Web 网站上,.JPG 和 .MP4 仍然是兼容性最好的格式。iOS 设备上的 Live Photos 会在备份导出到非 Apple 设备时,自动拆分为 .HEIC 静态图片和一段 .MOV 视频,因此,如果想在网页上展示 Live Photos,可能还需要进行格式转换,可以使用的工具太多了,本文对此不作展开说明。
目前我已经知道的 Samsung、小米/红米、OPPO/OnePlus 等主流 Android 手机基本都遵循了 Google 的 Motion Photos 规范,细节上的差异不在本文讨论范围内。
至此,我们仍需要将 Motion Photos 手动「拆」成静态图片 + 视频,这里推荐使用 GoMoPho (Google motion photos video extractor) 工具进行拆包。
下面演示的是一张 Motion Photos 在本文最终实现的效果,你可以尝试:
我们首先要对 Motion Photos 中的静态图片和视频资源进行提取,下面介绍两款工具,一款直接在浏览器中使用,另一款需下载后在命令行中使用。
MotionFlow 是我用 AI 辅助构建的一款纯静态的在线 Web 应用,支持批量处理 Motion Photos 并打包下载。你可以 在线体验 ,它是开箱即用的,所有处理操作只在浏览器中进行以保证隐私和安全。

GoMoPho 是一款跨平台的 Google Motion Photos 提取工具, 下载 后解压直接在终端运行(需指定参数)
GoMoPhoConsole.exe d <输入路径> s "<输出路径>" p "*.<文件后缀名>"
举个例子

解压完成

一张 Motion Photo 解包后会得到一张照片和一个视频,它们体积较大,建议上传到图床或对象存储上,并确保其可以通过 直链访问。
以 Hugo PaperMod 主题为例,新建一个短代码 motionPhotos.html
{{- $videoSrc := .Get "video" -}}
{{- $imageSrc := .Get "image" -}}
{{- $altText := .Get "alt" | default "Motion Photo" -}}
{{- $uniqueId := now.UnixNano | string | md5 -}}
{{- $imageResource := "" -}}
{{- $localResource := "" -}}
{{- if $imageSrc -}}
{{- $isRemote := or (hasPrefix $imageSrc "http://") (hasPrefix $imageSrc "https://") -}}
{{- if not $isRemote -}}
{{- if hugo.IsProduction -}}
{{- $localResource = resources.Get $imageSrc -}}
{{- end -}}
{{- if $localResource -}}
{{- $imageResource = $localResource -}}
{{- else -}}
{{- $imageResource = resources.GetRemote $imageSrc -}}
{{- end -}}
{{- else -}}
{{- $imageResource = resources.GetRemote $imageSrc -}}
{{- end -}}
{{- end -}}
<div class="live-photo-container" id="mp-{{ $uniqueId }}"
{{- with $imageResource -}}
{{- if and .Width .Height -}}
style="aspect-ratio: {{ .Width }} / {{ .Height }}; max-width: min(100%, {{ .Width }}px);"
{{- else -}}
style="aspect-ratio: 4/3; max-width: min(100%, 700px);"
{{- end -}}
{{- else -}}
style="aspect-ratio: 4/3; max-width: min(100%, 700px);"
{{- end -}}>
<video class="live-photo-video" data-src="{{ $videoSrc }}" poster="{{ $imageSrc }}" muted playsinline loop>
您的浏览器不支持 HTML5 视频。
</video>
<div class="live-photo-controls-group">
<button class="live-photo-control-btn live-photo-toggle-btn" data-state="static" aria-label="Toggle Motion Photo">
<i class="icon-live"></i><span>LIVE</span>
</button>
<button class="live-photo-control-btn live-photo-mute-btn" data-muted="true" aria-label="Toggle Mute">
<i class="icon-muted"></i>
</button></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
var container=document.getElementById('mp-{{ $uniqueId }}');
if(!container)return;
var video=container.querySelector('.live-photo-video');
var toggleBtn=container.querySelector('.live-photo-toggle-btn');
var muteBtn=container.querySelector('.live-photo-mute-btn');
var playTimeout;
const HOVER_DELAY=500;
var isManuallyControlled=false;
function updateMuteButtonUI(isMuted){
muteBtn.setAttribute('data-muted',isMuted.toString());
var icon=muteBtn.querySelector('i');
icon.className=isMuted?'icon-muted':'icon-unmuted';
}
function startVideo(autoUnmute){
if(toggleBtn.getAttribute('data-state')==='static'){
if(!video.src){
video.src=video.getAttribute('data-src');
video.load();
}
video.style.opacity=1;
if(autoUnmute){
video.muted=false;
updateMuteButtonUI(false);
}
video.play().catch(e=>{
if(e.name!=='AbortError'){console.error("Video play failed:",e);}
});
toggleBtn.setAttribute('data-state','playing');
}
}
function stopVideo(){
if(toggleBtn.getAttribute('data-state')==='playing'){
video.pause();
video.currentTime=0;
toggleBtn.setAttribute('data-state','static');
if(!video.muted){
video.muted=true;
updateMuteButtonUI(true);
}
}
}
container.addEventListener('mouseenter',function(){
clearTimeout(playTimeout);
if(isManuallyControlled)return;
playTimeout=setTimeout(()=>startVideo(true),HOVER_DELAY);
});
container.addEventListener('mouseleave',function(){
clearTimeout(playTimeout);
if(!isManuallyControlled)stopVideo();
});
toggleBtn.addEventListener('click',function(event){
event.stopPropagation();
var state=toggleBtn.getAttribute('data-state');
if(state==='static'){
isManuallyControlled=true;
startVideo(true);
}else{
isManuallyControlled=false;
stopVideo();
}
});
muteBtn.addEventListener('click',function(event){
event.stopPropagation();
video.muted=!video.muted;
updateMuteButtonUI(video.muted);
});
video.addEventListener('ended',function(){
isManuallyControlled=false;
stopVideo();
});
});
</script>
<style>
.live-photo-container{position:relative;margin:var(--gap) auto;overflow:hidden;border-radius:var(--radius);cursor:pointer;background-color:var(--code-block-bg);max-height:70vh;}.live-photo-video{position:absolute;top:0;left:0;width:100%;height:100%;display:block;object-fit:cover;}.live-photo-controls-group{position:absolute;bottom:8px;right:8px;display:flex;align-items:center;gap:5px;}.live-photo-control-btn{position:static;background-color:rgba(0,0,0,0.6);border:none;color:white;cursor:pointer;transition:background-color 0.2s,opacity 0.2s;box-shadow:0 1px 3px rgba(0,0,0,0.4);display:flex;align-items:center;justify-content:center;white-space:nowrap;}.live-photo-control-btn:hover{background-color:rgba(0,0,0,0.8);}.live-photo-toggle-btn{border-radius:20px;padding:5px 9px;font-size:0.85em;}.live-photo-toggle-btn i.icon-live{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAMAAAAOusbgAAAAM1BMVEX///+OjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpMym3PHAAAAEXRSTlMAMEAQsP/AIKDggHDQkPBQYHOKyH4AAAUWSURBVHgBYhg6gJEJQgNoMcPsWEEYCguQCKiB/a/2lecp1hgm4sx8v3La1huSG0CdB0C3x3b+vm4AiKYGCX4INTKxBl9mqXKxRlgjrNFao+VbghhMk4OzMLTIBPxwAhsA0LxXGoDqj3KNco2oRttPMNMefBCopN9nl91RW9h9Vn6zSlD5jvDklmQvRk+Lm94W5o+cm3/spGDhh7VG85LMO7qtiAaB0qSSCNAcDXkOtVkdoVnwOW1QBsF3mx2bp8ZIbZt5iIltPx7C4b6xDuMCrXmXfmjOeR+BvMbgRntkp7exox4B1c0D7oaPCZuSPK7wnxV9yuZjwr5bapMQrpBfTLfUfsRcCTELqluELjEJ15CMmNz0JmUFBZbs2Bz19uQS4Qax9Pbw4PQ5Krrsilv6z4asDquVzxrAB5uzQTigwI1kF09w4N2DrRskGyZo0NYZnRwObeKt9rrwdp0jh4d5yk3zBXedqk27TfqzrqEmq99AsHX6XBjrh2+fpflVkWUmJN6Sp7rp7jxuUGGzoSUbnKw7dLba2FF2AWK+d4IVNiAazI1FP2vbzIi6afw03DHXUd1uCBu9WYo1yFyEk36CzaTp6sqru3HWWn8+wVZdV1f27Ky1k0pS+qsRHuZt4N17l4cKzdMYyHs0jIus2BIbn9XC5oFjk8cIENEn+/Juy+zk8DRRC6+qo1cNtoHgDxTsK5vES+cXVtfOv3ByhAsxvyh2kS8azQd0WbC0kBlBBCUT5Uv+dG67ZXUtLTFOIehApWvRwkpp/3bNF/52ClY0YZ9N9BdbQfHBKjOM/c2/Q+gt2QxtOlnX1ZVLpxYyJFu6gEpRnsUoaXGsMUKWhkBB2iC3S63dkspRwVX4Wway0Q0p5xTYUKPsl8ROvXD8qrDzMHYLza66GV8XO7J8cluW5TnJPolwQMvpKk5wELV389RG1dG5slbMPMMBmRfdz2Kl7Ln25GqYCaiwEwO4S3xXlyl7scnLafOj3H19Ar7fw8EifrdvOPnDrw5K7sx943LLZ/l5Oqi8qfIH88QSb5IuLJeGrYj6u90OijnLnw8x3xcOsrC7Ldw+MyIzsSgsV1LuhSI879lxIVW4yML/qjeLHAliGIqGisL3P+2smtyy5F9J2pqsCx0w/OcufnF8rH21F9PscZmpaT7szysCiyuML669nl5rO+kfIPpH5riTMGInYa9fu8XLGs1AQC30GQz2HBLsPZ9j9cJbIKDfJgf0C1IYaukKJW1uRtLWoKTN0Q25JE3lE/ODeTOcmGcmMedKEefCUgRefLFI8cXxxRe+3MS6lC4uNxmu3PT5nvBdYEvTC2yBPLZQFCAx5wFSUrRkb5OSIjMyXY/w8PlpV42y8QazbZEaCr9fyJe5fYE0sH9KA8GZ34ghlYohIt2pLZF/AMELf3N83ijVnfZvL46vbR+kEt/zKAye8Ub5wMAkVtQUG68840rUzFufJCBnB2i4jJeEpHp3S6q/GKkegROOLCRb+hvFIIMTABzj4nAMWypNNCAcg4nK80ck32nulM7KByM00ACRmypFbq52C7nxgYGMfKxjkFHwK7Eqfg+tBMnKOEgGo3PbPgmdw2DBjsGC+nikPhBKPNhQB4S1BCBSgX7xsY9gzlkf7NZH2XF43++imKLXbfcz4H3jYrzXrhCjm9+gYYEGjSUtKWdZ2JJCm3AK14RzAk04Om1H+o1W+NlQ7TMSPh+F8t0sH9Z52kznnTX/ZvwBSmxeg6qlDAUAAAAASUVORK5CYII");background-size:16px 16px;background-repeat:no-repeat;background-position:center center;display:inline-block;width:16px;height:16px;flex-shrink:0;margin-right:4px;content:none;font-size:0;}.live-photo-mute-btn{border-radius:50%;width:32px;height:32px;padding:0;opacity:0.9;display:flex;}.live-photo-mute-btn i{display:block;width:100%;height:100%;font-size:0;content:none;color:transparent;background-repeat:no-repeat;background-position:center center;background-size:18px 18px;}.live-photo-mute-btn[data-muted="true"] i.icon-muted{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27white%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%20stroke-width%3D%272%27%20d%3D%27M15%208a5%205%200%200%201%201.912%204.934m-1.377%202.602A5%205%200%200%201%2015%2016m2.7-11a9%209%200%200%201%202.362%2011.086m-1.676%202.299A9%209%200%200%201%2017.7%2019M9.069%205.054L9.5%204.5A.8.8%200%200%201%2011%205v2m0%204v8a.8.8%200%200%201-1.5.5L6%2015H4a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1h2l1.294-1.664M3%203l18%2018%27%2F%3E%3C%2Fsvg%3E");}.live-photo-mute-btn[data-muted="false"] i.icon-unmuted{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27white%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%20stroke-width%3D%272%27%20d%3D%27M15%208a5%205%200%200%201%200%208m2.7-11a9%209%200%200%201%200%2014M6%2015H4a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1h2l3.5-4.5A.8.8%200%200%201%2011%205v14a.8.8%200%200%201-1.5.5z%27%2F%3E%3C%2Fsvg%3E");}
</style>
下面的 \\ 用于文中转义短代码的渲染,实际使用时请去掉
{{\\< motionPhotos
video="https://s3.dejavu.moe/blog/<Live Photos 视频>.mp4"
image="https://s3.dejavu.moe/blog/<live Photos 照片>.jpg"
alt="我的实况照片" >\\}}
由 Gemini AI 提供修改和完善 Hugo 短代码的建议
LIVE 按钮的图标来自于 Apple 网站
音量图标来自于 ChronoFrame
可供参考的资料:
参考资料:
Apple 推出 实况照片 (Live Photos) 很多年了,它会在手机拍摄一张照片的同时,记录下数秒时间的有声影像,使得定格的瞬间可以有更多的「现场感」和「故事感」。后来 Google 推出了自己的 动态照片 (Motion Photos),尽管他们在实现原理上还存在着一些不同,但基本上都可以将它们理解为一张静态图片 + 一段有声的瞬间 + 一些其他信息。
今年,随着各个社交平台对实况照片的支持,我们可能越来越喜欢这种更生动有趣的记录方式。本文主要介绍在 Hugo 静态博客网站上优雅地展示 Live Photos 或 Motion Photos 的方式。
值得注意的是,目前在 Web 网站上,.JPG 和 .MP4 仍然是兼容性最好的格式。iOS 设备上的 Live Photos 会在备份导出到非 Apple 设备时,自动拆分为 .HEIC 静态图片和一段 .MOV 视频,因此,如果想在网页上展示 Live Photos,可能还需要进行格式转换,可以使用的工具太多了,本文对此不作展开说明。
目前我已经知道的 Samsung、小米/红米、OPPO/OnePlus 等主流 Android 手机基本都遵循了 Google 的 Motion Photos 规范,细节上的差异不在本文讨论范围内。
至此,我们仍需要将 Motion Photos 手动「拆」成静态图片 + 视频,这里推荐使用 GoMoPho (Google motion photos video extractor) 工具进行拆包。
下面演示的是一张 Motion Photos 在本文最终实现的效果,你可以尝试:
我们首先要对 Motion Photos 中的静态图片和视频资源进行提取,下面介绍两款工具,一款直接在浏览器中使用,另一款需下载后在命令行中使用。
MotionFlow 是我用 AI 辅助构建的一款纯静态的在线 Web 应用,支持批量处理 Motion Photos 并打包下载。你可以 在线体验 ,它是开箱即用的,所有处理操作只在浏览器中进行以保证隐私和安全。

GoMoPho 是一款跨平台的 Google Motion Photos 提取工具, 下载 后解压直接在终端运行(需指定参数)
GoMoPhoConsole.exe d <输入路径> s "<输出路径>" p "*.<文件后缀名>"
举个例子

解压完成

一张 Motion Photo 解包后会得到一张照片和一个视频,它们体积较大,建议上传到图床或对象存储上,并确保其可以通过 直链访问。
以 Hugo PaperMod 主题为例,新建一个短代码 motionPhotos.html
{{- $videoSrc := .Get "video" -}}
{{- $imageSrc := .Get "image" -}}
{{- $altText := .Get "alt" | default "Motion Photo" -}}
{{- $uniqueId := now.UnixNano | string | md5 -}}
{{- $imageResource := "" -}}
{{- $localResource := "" -}}
{{- if $imageSrc -}}
{{- $isRemote := or (hasPrefix $imageSrc "http://") (hasPrefix $imageSrc "https://") -}}
{{- if not $isRemote -}}
{{- if hugo.IsProduction -}}
{{- $localResource = resources.Get $imageSrc -}}
{{- end -}}
{{- if $localResource -}}
{{- $imageResource = $localResource -}}
{{- else -}}
{{- $imageResource = resources.GetRemote $imageSrc -}}
{{- end -}}
{{- else -}}
{{- $imageResource = resources.GetRemote $imageSrc -}}
{{- end -}}
{{- end -}}
<div class="live-photo-container" id="mp-{{ $uniqueId }}"
{{- with $imageResource -}}
{{- if and .Width .Height -}}
style="aspect-ratio: {{ .Width }} / {{ .Height }}; max-width: min(100%, {{ .Width }}px);"
{{- else -}}
style="aspect-ratio: 4/3; max-width: min(100%, 700px);"
{{- end -}}
{{- else -}}
style="aspect-ratio: 4/3; max-width: min(100%, 700px);"
{{- end -}}>
<video class="live-photo-video" data-src="{{ $videoSrc }}" poster="{{ $imageSrc }}" muted playsinline loop>
您的浏览器不支持 HTML5 视频。
</video>
<div class="live-photo-controls-group">
<button class="live-photo-control-btn live-photo-toggle-btn" data-state="static" aria-label="Toggle Motion Photo">
<i class="icon-live"></i><span>LIVE</span>
</button>
<button class="live-photo-control-btn live-photo-mute-btn" data-muted="true" aria-label="Toggle Mute">
<i class="icon-muted"></i>
</button></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
var container=document.getElementById('mp-{{ $uniqueId }}');
if(!container)return;
var video=container.querySelector('.live-photo-video');
var toggleBtn=container.querySelector('.live-photo-toggle-btn');
var muteBtn=container.querySelector('.live-photo-mute-btn');
var playTimeout;
const HOVER_DELAY=500;
var isManuallyControlled=false;
function updateMuteButtonUI(isMuted){
muteBtn.setAttribute('data-muted',isMuted.toString());
var icon=muteBtn.querySelector('i');
icon.className=isMuted?'icon-muted':'icon-unmuted';
}
function startVideo(autoUnmute){
if(toggleBtn.getAttribute('data-state')==='static'){
if(!video.src){
video.src=video.getAttribute('data-src');
video.load();
}
video.style.opacity=1;
if(autoUnmute){
video.muted=false;
updateMuteButtonUI(false);
}
video.play().catch(e=>{
if(e.name!=='AbortError'){console.error("Video play failed:",e);}
});
toggleBtn.setAttribute('data-state','playing');
}
}
function stopVideo(){
if(toggleBtn.getAttribute('data-state')==='playing'){
video.pause();
video.currentTime=0;
toggleBtn.setAttribute('data-state','static');
if(!video.muted){
video.muted=true;
updateMuteButtonUI(true);
}
}
}
container.addEventListener('mouseenter',function(){
clearTimeout(playTimeout);
if(isManuallyControlled)return;
playTimeout=setTimeout(()=>startVideo(true),HOVER_DELAY);
});
container.addEventListener('mouseleave',function(){
clearTimeout(playTimeout);
if(!isManuallyControlled)stopVideo();
});
toggleBtn.addEventListener('click',function(event){
event.stopPropagation();
var state=toggleBtn.getAttribute('data-state');
if(state==='static'){
isManuallyControlled=true;
startVideo(true);
}else{
isManuallyControlled=false;
stopVideo();
}
});
muteBtn.addEventListener('click',function(event){
event.stopPropagation();
video.muted=!video.muted;
updateMuteButtonUI(video.muted);
});
video.addEventListener('ended',function(){
isManuallyControlled=false;
stopVideo();
});
});
</script>
<style>
.live-photo-container{position:relative;margin:var(--gap) auto;overflow:hidden;border-radius:var(--radius);cursor:pointer;background-color:var(--code-block-bg);max-height:70vh;}.live-photo-video{position:absolute;top:0;left:0;width:100%;height:100%;display:block;object-fit:cover;}.live-photo-controls-group{position:absolute;bottom:8px;right:8px;display:flex;align-items:center;gap:5px;}.live-photo-control-btn{position:static;background-color:rgba(0,0,0,0.6);border:none;color:white;cursor:pointer;transition:background-color 0.2s,opacity 0.2s;box-shadow:0 1px 3px rgba(0,0,0,0.4);display:flex;align-items:center;justify-content:center;white-space:nowrap;}.live-photo-control-btn:hover{background-color:rgba(0,0,0,0.8);}.live-photo-toggle-btn{border-radius:20px;padding:5px 9px;font-size:0.85em;}.live-photo-toggle-btn i.icon-live{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAMAAAAOusbgAAAAM1BMVEX///+OjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpOOjpMym3PHAAAAEXRSTlMAMEAQsP/AIKDggHDQkPBQYHOKyH4AAAUWSURBVHgBYhg6gJEJQgNoMcPsWEEYCguQCKiB/a/2lecp1hgm4sx8v3La1huSG0CdB0C3x3b+vm4AiKYGCX4INTKxBl9mqXKxRlgjrNFao+VbghhMk4OzMLTIBPxwAhsA0LxXGoDqj3KNco2oRttPMNMefBCopN9nl91RW9h9Vn6zSlD5jvDklmQvRk+Lm94W5o+cm3/spGDhh7VG85LMO7qtiAaB0qSSCNAcDXkOtVkdoVnwOW1QBsF3mx2bp8ZIbZt5iIltPx7C4b6xDuMCrXmXfmjOeR+BvMbgRntkp7exox4B1c0D7oaPCZuSPK7wnxV9yuZjwr5bapMQrpBfTLfUfsRcCTELqluELjEJ15CMmNz0JmUFBZbs2Bz19uQS4Qax9Pbw4PQ5Krrsilv6z4asDquVzxrAB5uzQTigwI1kF09w4N2DrRskGyZo0NYZnRwObeKt9rrwdp0jh4d5yk3zBXedqk27TfqzrqEmq99AsHX6XBjrh2+fpflVkWUmJN6Sp7rp7jxuUGGzoSUbnKw7dLba2FF2AWK+d4IVNiAazI1FP2vbzIi6afw03DHXUd1uCBu9WYo1yFyEk36CzaTp6sqru3HWWn8+wVZdV1f27Ky1k0pS+qsRHuZt4N17l4cKzdMYyHs0jIus2BIbn9XC5oFjk8cIENEn+/Juy+zk8DRRC6+qo1cNtoHgDxTsK5vES+cXVtfOv3ByhAsxvyh2kS8azQd0WbC0kBlBBCUT5Uv+dG67ZXUtLTFOIehApWvRwkpp/3bNF/52ClY0YZ9N9BdbQfHBKjOM/c2/Q+gt2QxtOlnX1ZVLpxYyJFu6gEpRnsUoaXGsMUKWhkBB2iC3S63dkspRwVX4Wway0Q0p5xTYUKPsl8ROvXD8qrDzMHYLza66GV8XO7J8cluW5TnJPolwQMvpKk5wELV389RG1dG5slbMPMMBmRfdz2Kl7Ln25GqYCaiwEwO4S3xXlyl7scnLafOj3H19Ar7fw8EifrdvOPnDrw5K7sx943LLZ/l5Oqi8qfIH88QSb5IuLJeGrYj6u90OijnLnw8x3xcOsrC7Ldw+MyIzsSgsV1LuhSI879lxIVW4yML/qjeLHAliGIqGisL3P+2smtyy5F9J2pqsCx0w/OcufnF8rH21F9PscZmpaT7szysCiyuML669nl5rO+kfIPpH5riTMGInYa9fu8XLGs1AQC30GQz2HBLsPZ9j9cJbIKDfJgf0C1IYaukKJW1uRtLWoKTN0Q25JE3lE/ODeTOcmGcmMedKEefCUgRefLFI8cXxxRe+3MS6lC4uNxmu3PT5nvBdYEvTC2yBPLZQFCAx5wFSUrRkb5OSIjMyXY/w8PlpV42y8QazbZEaCr9fyJe5fYE0sH9KA8GZ34ghlYohIt2pLZF/AMELf3N83ijVnfZvL46vbR+kEt/zKAye8Ub5wMAkVtQUG68840rUzFufJCBnB2i4jJeEpHp3S6q/GKkegROOLCRb+hvFIIMTABzj4nAMWypNNCAcg4nK80ck32nulM7KByM00ACRmypFbq52C7nxgYGMfKxjkFHwK7Eqfg+tBMnKOEgGo3PbPgmdw2DBjsGC+nikPhBKPNhQB4S1BCBSgX7xsY9gzlkf7NZH2XF43++imKLXbfcz4H3jYrzXrhCjm9+gYYEGjSUtKWdZ2JJCm3AK14RzAk04Om1H+o1W+NlQ7TMSPh+F8t0sH9Z52kznnTX/ZvwBSmxeg6qlDAUAAAAASUVORK5CYII");background-size:16px 16px;background-repeat:no-repeat;background-position:center center;display:inline-block;width:16px;height:16px;flex-shrink:0;margin-right:4px;content:none;font-size:0;}.live-photo-mute-btn{border-radius:50%;width:32px;height:32px;padding:0;opacity:0.9;display:flex;}.live-photo-mute-btn i{display:block;width:100%;height:100%;font-size:0;content:none;color:transparent;background-repeat:no-repeat;background-position:center center;background-size:18px 18px;}.live-photo-mute-btn[data-muted="true"] i.icon-muted{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27white%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%20stroke-width%3D%272%27%20d%3D%27M15%208a5%205%200%200%201%201.912%204.934m-1.377%202.602A5%205%200%200%201%2015%2016m2.7-11a9%209%200%200%201%202.362%2011.086m-1.676%202.299A9%209%200%200%201%2017.7%2019M9.069%205.054L9.5%204.5A.8.8%200%200%201%2011%205v2m0%204v8a.8.8%200%200%201-1.5.5L6%2015H4a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1h2l1.294-1.664M3%203l18%2018%27%2F%3E%3C%2Fsvg%3E");}.live-photo-mute-btn[data-muted="false"] i.icon-unmuted{background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27white%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%20stroke-width%3D%272%27%20d%3D%27M15%208a5%205%200%200%201%200%208m2.7-11a9%209%200%200%201%200%2014M6%2015H4a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1h2l3.5-4.5A.8.8%200%200%201%2011%205v14a.8.8%200%200%201-1.5.5z%27%2F%3E%3C%2Fsvg%3E");}
</style>
下面的 \\ 用于文中转义短代码的渲染,实际使用时请去掉
{{\\< motionPhotos
video="https://s3.dejavu.moe/blog/<Live Photos 视频>.mp4"
image="https://s3.dejavu.moe/blog/<live Photos 照片>.jpg"
alt="我的实况照片" >\\}}
由 Gemini AI 提供修改和完善 Hugo 短代码的建议
LIVE 按钮的图标来自于 Apple 网站
音量图标来自于 ChronoFrame
可供参考的资料:
参考资料: