M3U8 下載失敗怎麼辦?HLS 串流排查

排查 M3U8 與 HLS 下載失敗,包括播放清單偵測、CORS、過期位址、Referer、DRM 與分片問題。

M3U8 下載失敗通常是播放清單沒偵測到、線上工具受到跨網域限制,或串流媒體需要原影片頁面中的存取資訊。本文按 HLS 的實際下載流水線逐步拆解,告訴你失敗發生在哪一環、為什麼、怎麼修。


先理解:HLS 下載流水線

HLS 不是一條 URL 拉一個檔案那麼簡單。它是一條流水線,任何一環出錯,最終表現都是「下載失敗」或「檔案壞掉」。先認清這條線,排查才有方向:

① 偵測 M3U8        ② 解析清單        ③ 下載分片         ④ 解密         ⑤ 合併/轉封裝
   ↓                  ↓                  ↓                 ↓               ↓
 webRequest        m3u8-parser       Worker Pool      WebCrypto       FFmpeg WASM
 攔截請求          區分 Master/      並行拉 .ts       AES-128-CBC     TS → MP4
                   Media             重試退避          (如需要)        或直接拼接
環節失敗表現本文對應章節
① 偵測彈出視窗顯示「未偵測到媒體」偵測不到 M3U8
② 解析清單下下來了但畫質/分片列表是空的清單解析異常
③ 下載進度卡住、403、404、CORS分片下載失敗
④ 解密解密報錯或合併後沒聲音/花屏加密流解密失敗
⑤ 合併檔案生成了但無法播放、音畫不同步合併後無法播放
HLS 協定與清單結構(Master vs Media Playlist、EXT-X-KEY、多音軌)的完整說明,請參閱 影片嗅探 — HLS 串流。想看真實清單長什麼樣、為什麼「樸素下載器」會翻車,可以翻 HLS 深度篇

快速處理

在深入排查前,先跑一遍這套能解決 90% 場景的流程:

  1. 打開原影片頁面並播放幾秒(很多網站懶載入,不播就不會請求 M3U8)。
  2. 裝了擴充功能後沒重新整理過頁面的,重新整理一次(擴充功能的 webRequest 監聽是頁面載入後才生效的)。
  3. 用擴充功能重新偵測,選擇目標畫質。
  4. 選 MP4 輸出,再點一次下載。

如果還是不行,按下面的章節定位。


偵測不到 M3U8

症狀:打開 FlowPick 彈出視窗顯示「未偵測到媒體資源」,或列表裡只有縮圖/封面,沒有 .m3u8 條目。

常見原因

原因怎麼確認解決
影片還沒開始載入沒播過就打開擴充功能播放 3-5 秒再打開擴充功能
裝了擴充功能後沒重新整理頁面裝擴充功能前頁面已載入完畢重新整理頁面重新觸發請求
使用 MSE 而非原生 HLS開發人員工具裡看不到 .m3u8 請求見下方「MSE 網站」小節
清單在跨網域 iframe 裡Network 面板看得到,但擴充功能拿不到直接打開 iframe 來源頁面再偵測
廣告攔截器等擴充功能衝突暫時停用其他網路類擴充功能後能偵測到加白名單或調整載入順序
自訂/私有協定Network 裡走的是 ws://blob: 或加密流FlowPick 暫不支援,見 已知限制

用開發人員工具確認

F12Network 面板 → 在篩選框輸入 m3u8

  • 看得到請求:表示網站確實用 HLS,問題在擴充功能偵測那一側(多半是沒重新整理頁面或被其他擴充功能攔截)。
  • 看不到請求:網站可能用了 MSE(Media Source Extensions),把分片直接餵給 <video>,根本不發 .m3u8。這類網站 FlowPick 偵測不到,屬於瀏覽器層級的限制。

MSE 網站怎麼辦

如果 Network 裡看到的是一堆 .m4s / .chunk 請求但沒有清單檔,那它用的是 MSE + 自訂分片邏輯(YouTube 就是典型)。兩條出路:

  • .mpd(DASH)入口,改用 DASH 下載器,參考 DASH 沒有音訊排查
  • 找到 <video> 標籤的 src,如果是 blob: 開頭,那是 MSE 產生的,無法直接下載——只能等網站自己發原生 HLS/DASH 清單。
關於擴充功能偵測原理(webRequest.onBeforeRequest、Content-Type 辨識)和 25+ 種 MIME 類型的完整列表,請參閱 影片嗅探 — 偵測原理。偵測不到時的系統排查流程,見 常見問題排查 — 媒體偵測問題

清單解析異常

症狀:M3U8 偵測到了,但畫質列表是空的,或分片數量異常少(比如只有 1 個),下載出來只有幾 KB。

Master 還是 Media

HLS 清單分兩層。如果你在彈出視窗裡看到的是 Media Playlist(分片清單本身),可能沒有畫質選項可選;反過來如果你拿到的只是 Master Playlist 的 URL,但解析出來的變體都是空的,多半是清單內容不完整。

Master Playlist          ← 列出 360p / 720p / 1080p 變體
    └── v_720.m3u8       ← Media Playlist,列出幾百個 .ts 分片
            └── seg-001.ts, seg-002.ts, ...

自己檢查清單內容

把 M3U8 URL 複製出來,用 curl 看一眼內容(替換成你的 URL):

curl -sL "https://cdn.example.com/index.m3u8"

正常的 Master Playlist 應該看得到 #EXT-X-STREAM-INF 行:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720
v_720.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=8000000,RESOLUTION=1920x1080
v_1080.m3u8

正常的 Media Playlist 應該看得到 #EXTINF + 分片 URL:

#EXTM3U
#EXT-X-TARGETDURATION:6
#EXT-X-VERSION:3
#EXTINF:6.0,
seg-001.ts
#EXTINF:6.0,
seg-002.ts
#EXTINF:4.2,
seg-003.ts
#EXT-X-ENDLIST

常見異常

看到的內容問題處理
整個 HTML 頁面(登入頁/錯誤頁)URL 被防盜連重新導向403 與防盜連
只有 #EXTM3U 一行清單被截斷或回應不完整重新打開頁面取得新 URL
#EXT-X-KEY 但沒分片加密流金鑰失敗導致後續不輸出加密流解密失敗
#EXT-X-ENDLIST 但分片數 < 5直播流剛開播或已結束直播流需在結束後下載回放
分片 URL 是相對路徑正常,解析器會補全基址無需處理
真實 HLS 清單遠比教學範例複雜(多音軌、字幕、CODECS 欄位、不連續性標籤等),這些是「樸素下載器」翻車的高發地。完整解析邏輯見 HLS 深度篇影片嗅探 — Master Playlist vs Media Playlist

分片下載失敗

症狀:進度條走到一半報錯、卡住不動,或主控台大量 403/404/CORS 報錯。

403 與防盜連

分片或清單請求回傳 403 Forbidden,幾乎都是防盜連校驗沒過。常見三類:

類型表現FlowPick 處理
Referer 校驗直接 curl 能下,瀏覽器擴充功能有時 403v1.1.1 起擴充功能自動注入原頁面 Referer
Cookie / 登入狀態未登入時 403,登入後正常在原影片頁面使用擴充功能即可攜帶 Cookie
短時 TokenURL 裡帶 ?token=xxx&expires=yyy,過幾分鐘失效見下方「過期位址」

擴充功能版的防盜連代理(v1.1.1+)

從 v1.1.1 起,FlowPick 內建了防盜連代理預覽與下載:圖片列表、影片封面、懸停預覽、圖片/音訊/文件/字幕下載,都會自動走代理,帶上原頁面的 Referer 和 Cookie,並在儲存前檢查回應——避免把防盜連回傳的 HTML 錯誤頁當成圖片或音訊存下來。

如果你裝的是舊版本,升級到 v1.1.1+ 後 Bilibili 等帶 Referer 校驗的網站下載成功率會明顯提升。升級方法見 安裝指南 — 更新擴充功能

線上工具為什麼常常 403

線上工具跑在 flowpick.com 網域下,瀏覽器不會把目標網站的 Cookie 和原頁面 Referer 帶過去,所以只要來源站做了防盜連,線上工具基本上一定掛。帶防盜連的網站請直接用擴充功能,在原影片頁面操作。

用 curl 重現 403

確認是不是 Referer 問題最快的方法:

# 不帶 Referer,多半 403
curl -I "https://cdn.example.com/seg-001.ts"

# 帶上原頁面 Referer,應該 200
curl -I -H "Referer: https://www.example.com/watch/123" "https://cdn.example.com/seg-001.ts"

第二個能回 200,就坐實是 Referer 校驗。

過期位址(動態 Token)

直播回放和部分平台的點播用短期 Token

https://cdn.example.com/seg-001.ts?token=ab12cd34&expires=1692300000

expires 是 Unix 時間戳記,過這個時間就 403/404。表現:

  • 剛開始下載好好的,下到一半突然全部分片 403。
  • 重新打開頁面後又能下,但過一會兒又掛。

處理

  • 偵測到清單後盡快開始下載,別在彈出視窗裡猶豫太久。
  • 大檔案被 Token 截斷時,重新整理原頁面,讓擴充功能重新抓一份新清單,繼續未完成的部分(FlowPick 的失敗重試會處理臨時波動,但 Token 過期是硬性失敗,必須換新清單)。
FlowPick 的下載重試採用指數退避策略,能處理臨時網路抖動,但不能繞過 Token 過期這類硬性失敗。重試機制細節見 下載引擎架構 — 重試機制

404 分片已刪除

多見於直播回放——直播結束後平台只保留有限時間的回放分片,超期分片直接 404。

  • 換個畫質試試(不同畫質可能對應不同分片檔案)。
  • 確認回放是否仍在有效期內。

CORS 錯誤

主控台報 has been blocked by CORS policy,基本都是線上工具遇到的。擴充功能有 host_permissions,不受同源策略限制。

工具CORS 表現處理
瀏覽器擴充功能不會觸發 CORS
線上工具清單/分片跨網域拉取被攔改用擴充功能;或確認來源站是否回傳 Access-Control-Allow-Origin
CORS 是瀏覽器安全機制,不是 bug。線上工具與擴充功能的功能差異和選型建議,見 線上工具 — 與擴充功能的區別

下載途中網路中斷

臨時網路抖動由重試機制覆蓋。持續失敗時:

  • 檢查網路穩定性(特別是代理/VPN 環境,見 常見問題排查 — 代理/VPN 環境)。
  • 把並行執行緒數降到 2-3,減少同時連線數(部分 CDN 會拒絕過高並行)。
  • 檢查防火牆是否攔截了串流媒體 CDN 網域。
並行數怎麼配?預設 2 保守,桌面網路建議 4-6,CDN 限速嚴重的網站降到 2-3。設定方法見 設定參考。並行與效能關係見 下載引擎架構 — 並行數與效能的關係

加密流解密失敗

症狀:清單裡有 #EXT-X-KEY,下載能跑完,但合併後沒聲音/花屏/無法播放,或主控台報解密錯誤。

先區分 AES-128 還是 DRM

FlowPick 只支援 AES-128 這種「裸」加密。清單裡看到這些標籤的,通通下不了:

# AES-128 —— 支援
#EXT-X-KEY:METHOD=AES-128,URI="https://cdn.example.com/key.bin",IV=0x...

# SAMPLE-AES / FairPlay —— 不支援(接近 DRM)
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://..."

# Widevine / PlayReady(DASH 裡常見)—— 不支援
<ContentProtection schemeIdUri="..."/>

AES-128 解密失敗的常見原因

原因怎麼確認處理
金鑰 URL 403/404主控台報金鑰拉取失敗在原頁面用擴充功能(帶 Cookie/Referer);金鑰也可能帶 Token
金鑰需要登入狀態未登入時金鑰 403,登入後正常先登入再下載
IV 缺失清單裡 #EXT-X-KEY 沒有 IV=FlowPick 會依規範用分片序號推導 IV,無需手動處理
金鑰不是 16 位元組curl 下來長度不對來源站異常,非 FlowPick 可修

用 curl 驗證金鑰

# 看金鑰是否拿得到,注意要帶 Referer/Cookie
curl -sL -H "Referer: https://www.example.com/watch/123" \
     "https://cdn.example.com/key.bin" | wc -c
# 正常應該輸出 16

輸出不是 16,金鑰本身有問題;輸出 16 但擴充功能還是解密失敗,多半是擴充功能請求時沒帶上 Cookie/Referer(升級到 v1.1.1+,防盜連代理會自動帶)。

DRM 內容怎麼辦

Widevine、PlayReady、FairPlay、SAMPLE-AES 這些 DRM 保護內容,FlowPick 明確拒絕處理——這是特性不是 bug。聲稱能解 DRM 的下載器要不是在說謊就是違法。法律和技術底線見 串流下載合法性指南

DRM 偵測方式和完整不支援列表見 已知限制 — DRM 保護內容。AES-128 解密的 Web Crypto 實作見 影片嗅探 — 加密串流

合併後無法播放

症狀:檔案下下來了,大小也正常,但 VLC/播放器打不開,或只有畫面沒聲音,或音畫不同步。

先用 VLC 測試

VLC 是相容性最好的播放器,先用它排除「播放器問題」:

  • VLC 能播、系統播放器不能播 → 編解碼/容器相容問題,換播放器。
  • VLC 也播不了 → 檔案本身有問題。

常見原因

表現原因處理
檔案只有幾 KB下到了清單不是影片重新選擇資源,確認選的是影片不是 .m3u8
有畫面沒聲音多音軌清單只下了影片軌道見下方「多音軌」
音畫不同步HLS 分片 PTS 不連續切 TS 輸出格式,或用 FFmpeg 重新編碼
花屏/損壞個別分片下載失敗導致合並不完整重新下載,確保所有分片完整
MP4 打不開但 TS 能播轉封裝時 stsd box 寫錯見下方「TS vs MP4」

多音軌清單

真實 HLS 清單(Netflix、Disney+ 那種)常把音訊和影片分開放:

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-128",NAME="English",DEFAULT=YES,URI="audio/eng_128.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=3000000,...,AUDIO="aac-128"
v_720.m3u8

如果你的下載器只抓 v_720.m3u8 然後拼分片,得到的就會是無聲影片。FlowPick 會自動同時拉音訊軌道並合併,但前提是你選了包含音訊的變體而不是只選影片流。多音軌清單的完整處理見 HLS 深度篇 — EXT-X-MEDIA

TS vs MP4 輸出格式

遇到 MP4 打不開的情況,先切到 TS 輸出格式試試。原因:

  • TS 分片是裸拼接,MPEG-TS 自帶 codec 資訊,幾乎不會錯。
  • MP4 轉封裝需要解析 CODECS 欄位、寫對 stsd box,遇到非標準 codec 標示會翻車。

TS 能播、MP4 不能播,多半是轉封裝問題,可以先用 TS 救急;要 MP4 的話用 FFmpeg 命令列手動轉一次:

ffmpeg -i output.ts -c copy output.mp4

-c copy 不重新編碼,秒級完成。

TS/MP4 轉封裝原理和 FFmpeg WASM 實作見 格式轉換。瀏覽器內合併的完整流程見 瀏覽器內合併深度篇

大檔案 / 瀏覽器卡死

症狀:下載大檔案(>1GB)時瀏覽器卡頓、崩潰,或下載到一定比例直接中斷。

這是寫入策略問題,不是 HLS 本身的問題。FlowPick 三級寫入策略:

策略觸發條件上限
File System Access APIChrome/Edge 86+無硬上限
StreamSaver.js支援 Service Worker 的瀏覽器無硬上限
Blob 備援其他情況1.5GB 硬限制

Blob 模式下超過 1.5GB 會被直接拒絕。解決方案:

  • 用 Chrome 86+ 或 Edge 86+,啟用「選擇儲存目錄」功能。
  • Firefox 不支援 FSA,大檔案走 StreamSaver 或 OPFS 暫存儲存(v1.1.1+ 優化)。
  • 實在不行,把並行數降到 1-2,減少記憶體佔用。
三級寫入策略對比和降級邏輯見 下載引擎架構 — 策略對比總結。大檔案排查見 常見問題排查 — 大檔案下載失敗。Firefox 的 OPFS 暫存儲存行為見 安裝指南 — Firefox

診斷工具速查

排查時按 F12 打開開發人員工具,下面是幾個最常用的檢查點:

檢查面板操作
M3U8 有沒有被請求Network篩選框輸入 m3u8,重新整理頁面播放影片
分片請求狀態碼Network篩選框輸入 .ts.m4s,看 Status 欄
請求帶了什麼標頭Network → 選中請求 → Headers看 Request Headers 的 Referer/Cookie
解密報錯主控台搜尋 decryptAES
合併報錯主控台搜尋 ffmpegwasm

產生環境診斷報告

複雜問題可以在主控台跑下面這段,產生環境資訊便於回報:

const report = {
  ua: navigator.userAgent,
  fsa: 'showDirectoryPicker' in window,
  sab: typeof SharedArrayBuffer !== 'undefined',
  coi: self.crossOriginIsolated,
  storage: await navigator.storage?.estimate().catch(() => null),
  ts: new Date().toISOString(),
}
console.log(JSON.stringify(report, null, 2))

報告只含瀏覽器環境資訊,不含任何瀏覽記錄或個人資料。


什麼時候真的下不了

FlowPick 適合公開的標準 HLS 播放清單。以下場景是設計上不支援,不是 bug:

  • DRM 保護(Widevine / PlayReady / FairPlay / SAMPLE-AES)
  • 需要破解登入或付費牆的內容
  • 使用 MSE 自訂分片、不發原生 M3U8/MPD 的網站
  • 私有協定、WebSocket、WebRTC 傳輸的媒體

碰到這些,正確的行為是報錯而不是默默產出損壞檔案——這也是 FlowPick 的態度。法律和技術底線詳見 串流下載合法性指南


相關文件