給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#最終效果

相關文章
相關標籤/搜索