给Markdown添加视频支持

本文转载自个人博客:https://blog.kaciras.com/article/18/add-video-support-to-markdowncss

都2020年了,如今最流行的就是什么直播弹幕短视频,你的博客要是还不支持插视频那可就OUT啦!前端

个人博客目前使用Markdown写文,惋惜它原生的语法并不支持视频,因而只能本身来实现这功能了。git

视频好处都有啥?

视频是个好东西啊,它要很差如今的直播弹幕短视频怎么火的……咳咳,扯远了,就说写博客,好比写教程啊总会遇到须要动态演示的东西吧,好比我本身的纯CSS解决图片加载的布局移动问题里一开头的动图(实际上是视频啦),要用图片或者文字来讲明文本下移的现象确定没有动态的演示好。github

另外玩过Twitter的都知道它里面插入的GIF图会转换为视频,GIF是1987年发明的东西,在我看来早是就该进入垃圾堆的技术,由于当年浏览器不支持视频才得以流行。动图这一技术彻底能被视频所替代,视频自己就不是一连串图像的序列吗(固然还包括声音)。web

在性能上,H.246编码的视频体积仅为GIF的13分之一,虽然GIF也有gifsicle能压缩一下,但效果仍不如视频。c#

从个人实际经验来看,技术类文章里大部分动态演示都来源于录屏,录屏软件生成的原本就是视频格式,把它们转GIF画蛇添足。综上所述,视频的支持是一个现代化博客必需的功能浏览器

语法的选择

Markdown版本演进已经有其它的文章写过了http://www.javashuo.com/article/p-olrbbums-kp.htmlmarkdown

主要的几个Markdown版本原生都不支持视频,我不知道它的做者是怎么想的,如此重要的功能居然能没有。既然官方没有,那就本身作呗,因而种各样的实现方案就跑了出来,按照本人强迫症的作法固然要对比一番ide

直接插HTML


这是我看到的最多的作法,其优点就是简单,现有的转换库都支持写HTML,但我认为这种方式并很差。函数

  • XSS风险:如果本身用还好说,一旦给评论之类的第三方输入用上,你都猜不到他们会搞些什么出来。
  • 扩展性差:一旦写死,之后想改动下输出的HTML可就麻烦了,须要把全部文章都扫一遍,本博客就遇到过须要改动渲染结果的状况。
  • 可读性差:Markdown做为轻量级标记语言,扫一眼便可轻松Parse是其一大优点,一旦混入重量级的HTML则可读性大打折扣。

这缺点太多,因此我决定仍是得用Markdown的方式来作。

GitLab Flavored Markdown

GitLab Flavored Markdown(下称GFM)是Markdown的一种修改版,它复用了图片的语法,以扩展名来区分媒体的类型,好比![label](foobar.mp4)由于连接是.mp4结尾因此渲染为视频。

GFM的支持也很普遍,实现又简单,还有GitLab背书,天然也是个不错的选择。

但它的缺点也很明显,强制了连接的文件名必须是视频经常使用的扩展名,然而并非全部连接都是如此,Twitter的视频连接就没有扩展名。另外既然都修改了原始的Markdown语义,何不直接另起一个新语法呢?

本身编个语法

关于自定义的语法有不少讨论,我认为比较好的一种是使用通用指令语法,它的格式是@<指令类型>[...](..){...}这样的,前面的@能够换成别的,指令类型用于区分视频、音频、GIF视频等,后面三个括号里的内容能够自由发挥。

最终我决定使用这种语法,它跟原生的图片语法同样简洁,又给足了自由发挥的余地。

一般来讲,新的语法最好仍是跟现有的保持类似,这里就以语法比较像的图片为基准。圆括号仍然跟图片同样包含视频的连接,方括号里填标签(GIF)或者poster(视频)。

通用指令语法里,花括号用来放置key = "val"这样的键值对,但它们一样能够放在连接URL的参数上,并且目前图片就是这么作的,为了保持一致,我选择不要这个花括号部分。

指令类型包含GIF视频和普通视频,另外Markdown一样不支持插入音频这里也给补上,因此最终的语法为:

  • @audio[](音频连接) 插入一个音频。
  • @gif[标签](视频连接) 插入视频,并尽量模仿GIF图。
  • @video[视频封面](视频连接) 插入普通视频。

解析器的实现

个人博客使用markdown-it来转换Markdown为HTML,markdown-it 的流程分为解析和渲染两部分,因此要给这两个地方编写本身的函数实现。

首先是怎么识别@<指令类型>[...](..)这种文本呢,若是不考虑转义的话却是一个正则就能搞定,但问题是若是标签里出现了方括号,或者连接里有圆括号咋办?固然是要转义了,Markdown对括号的转义方式有两种:配对计数和斜杠转义,其中配对计数须要一个变量来存储左括号数量挺麻烦,并且斜杠转义彻底能用于全部场景,但反过来配对计数却没法用于右括号单独出现的状况(虽然不常见)。

综上所述,我决定不支持计数了,斜杠转义用一个前向环视(?<!\\)就能解决,再给指令部分加点限制,最后的正则以下:

  • 指令部分:([a-z][a-z0-9\-_]*)
  • 标签部分:\[(.*?)(?<!\\)]
  • 连接部分:\((.*?)(?<!\\)\)

把它们三个连起来就能够匹配通用指令语法啦。

Markdown有块block和行内inline两种结构,原始的图片语法是属于行内的,这能够实现图文混排,但在使用中发现我并无图文混排的需求,我博客里的图片都是单独一行。因此我决定新的语法做为块结构,这样能够下降解析函数被调用的频率,提高点性能。

最后要注意一下的是反转义和XSS检查,这些函数在markdown-it库里已有提供。

解析器代码见kaciras-blog/web-server/packages/server/lib/markdown-media.ts

不一样的渲染目标

Markdown渲染出来的HTML是跟场景相关的,好比在RSS里渲染的结果应尽可能简单,毕竟阅读器的样式是无法由我来控制的;而在个人博客网站里,会有一些额外的样式和元素来展示更好的效果,好比提早固定宽高比防止布局移动、居中等。

在个人博客,GIF视频经过隐藏控制面板、静音、给下面加标签、以及IntersectionObserver实现的自动播放/暂停,实现了跟GIF图片同样的效果。另外因为RSS阅读器不会加载个人博客的样式表,也不会运行JS,因此RSS阅读器里的GIF视频只能跟普通视频同样。

除了这俩以外,我还准备让评论系统也使用Markdown(暂未实现),这又是一个新的渲染目标,用户评论属于第三方输入,对其的渲染必须加入一些限制以防滥用。

对没法控制的前端,渲染实现跟解析器写在一块儿,见上面的连接。

我博客的渲染实现见kaciras-blog/website/blob/master/src/markdown/media.js

最终效果

SegmentFault不支持插入视频,因此这里展现不了,能够去个人博客里看效果:

https://blog.kaciras.com/article/18/add-video-support-to-markdown#最终效果

相关文章
相关标签/搜索