從瀏覽器下載m3u8串流檔案


現在的影音市場,串流播放已經幾乎完全取代下載檔案的習慣了,所以也很難直接看到完整檔案的下載連結,取而代之的是一堆碎片化的串流檔案。

雖然網路上隨便搜尋也可以找到不少下載工具,不過這邊還是簡單紀錄一下,如果想要自己寫 Javascript 程式去下載該如何處理。

M3U8 檔

一般來說,串流播放的起點通常會下載一個附檔名為.m3u8的檔案,其內容大致上會長這樣:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:1

#EXTINF:xxxx
file-00001.ts
#EXTINF:xxxx
file-00002.ts
#EXTINF:xxxx
file-00003.ts
#EXT-X-ENDLIST

#字號開頭的行數忽略後,會得到

file-00001.ts
file-00002.ts
file-00003.ts

可以簡單地將其理解為一份串流檔案列表,也就是讓播放器知道接下來要依序下載播放哪些檔案。

有時候這些檔案列表會是使用相對路徑紀錄,像是上述的那樣,這時候要記得使用原本m3u8檔案的下載網址作為相對路徑。

m3u8 檔案路徑範例
https://example.com/music/stream.m3u8

ts 檔實際位置
https://example.com/music/file-00001.ts

理解檔案格式之後,寫成程式就很簡單了

// 自己去找到m3u8的網址,這邊不另外說明
const m3u8 = "https://example.com/music/stream.m3u8";

// 保存相對路徑資訊
let path = /https:\/\/.+\//.exec(m3u8)[0];
// 下載m3u8檔案內容
let content = await (await fetch(m3u8)).text();
// 用換行切割檔案、並忽略#字號開頭的行數,最後將檔名補上相對路徑後輸出成陣列
let arr = content
  .split("\n")
  .filter((x) => !x.startsWith("#"))
  .map((x) => path + x);

TS 檔

ts 檔就是一堆攜帶實際內容的二進位檔,這就無法直接打開了。不過有趣的事情是他們幾乎不用做任何處理,直接全部依序打包在一起,並宣告好正確的檔案類型就是完整的檔案了。

// 依序下載串流內容
let bufferList = [];
for (let i = 0; i < arr.length; i++) {
  let buffer = await (await fetch(arr[i])).arrayBuffer();
  bufferList.push(buffer);
}
// 打包檔案。
let fileBlob = new Blob(bufferList, { type: "audio/mpeg3" });

關於 Blob 的 Type 如何宣告:Common MIME types

下載

最後一步,在瀏覽器上觸發下載事件。
原理是生成一個<a><\a>,然後把剛剛打包好的檔案連結放進去並執行點擊

let a = document.createElement("a");
a.download = "music.mp3";
a.href = URL.createObjectURL(fileBlob);
document.body.appendChild(a);
a.click();
Hi 喜歡這篇文章的話 可以按個讚或請我喝杯咖啡
Buy me a coffeeBuy me a coffee