给我的博客加上视频嵌入

我上一篇 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=ID
  • youtu.be/ID
  • youtube.com/shorts/ID
  • youtube.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 就完事了,干净。