给我的博客加上视频嵌入
我上一篇 iOS 上架 的文章里录了一段视频,挂在了 YouTube 和 Bilibili 上。当时我只能在 Markdown 里写两条普通的跳转链接,读者要点出去才能看,体验不太好。这次我顺手把视频嵌入这件事在博客里做了。
想要的效果
我的博客文章都是 .md 文件,没有用 MDX。所以我希望写法尽量简单,最好就是把视频 URL 单独放一行,构建的时候自动变成可以播放的视频。像这样:
这里有个视频:
https://www.youtube.com/watch?v=dQw4w9WgXcQ
不用引入组件,不用学新语法,存量的文章一行都不用改。
怎么实现的
Astro 处理 Markdown 是用 remark 这套工具链,我在 astro.config.mjs 里挂一个自己写的 remark 插件就可以了。
插件做的事情很简单:遍历 Markdown 的语法树,找到那种”一整段里只有一个 URL”的段落,把它替换成一个 iframe 的 HTML。
核心的逻辑就这么几行:
export default function remarkVideoEmbed() {
return (tree) => {
tree.children = tree.children.map((node) => {
const url = extractSoleUrl(node);
if (!url) return node;
const html = urlToEmbed(url);
return html ? { type: 'html', value: html } : node;
});
};
}
我特意加了”段落里只能有一个 URL”这个判断,这样我正文里夹的链接就不会被误伤。
支持的链接
YouTube 我支持了四种常见写法:
youtube.com/watch?v=IDyoutu.be/IDyoutube.com/shorts/IDyoutube.com/embed/ID
Bilibili 我只支持了一种:
bilibili.com/video/BVxxxxxxx
URL 里的 ?t= 起始时间和 ?p= 分 P 我也都处理了。YouTube 的 ?t= 有点麻烦,因为它有 ?t=90 和 ?t=1m30s 两种格式,我做了下兼容,都转成纯秒数。
一些小细节
YouTube 我默认走的是 youtube-nocookie.com,访客点播放之前不会下发 cookie,对读者友好一点。
Bilibili 的播放器我默认关掉了弹幕和自动播放,要不然一打开页面就有声音飘出来,挺扰民的。
iframe 加了 loading="lazy",进入视口才加载,省点流量。
样式上我用了 CSS 的 aspect-ratio: 16 / 9,自动按 16:9 显示,手机上看也不会变形。
效果
下面是我上一篇文章里那个视频,YouTube 和 Bilibili 各一个,可以直接点播放:
我源码里这两行就是赤裸裸的 URL,没有别的,构建的时候自动变成了上面的播放器。
一点感想
这个插件总共写了不到 100 行代码,但以后我写文章会舒服很多。
之前每次要嵌视频,我都得去 YouTube 或者 Bilibili 找 embed code,复制一段长长的 iframe HTML 进 Markdown,看着也乱。现在我直接粘 URL 就完事了,干净。