從瀏覽器下載m3u8串流檔案
25 Jul 2022現在的影音市場,串流播放已經幾乎完全取代下載檔案的習慣了,所以也很難直接看到完整檔案的下載連結,取而代之的是一堆碎片化的串流檔案。
雖然網路上隨便搜尋也可以找到不少下載工具,不過這邊還是簡單紀錄一下,如果想要自己寫 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();