iOS 原生 HLS,而是在「伺服器端的 m3u8 代理」這個環節:它對 master playlist 和子流做了 URL 重寫,但你的 filterAdsFromM3U8 只在「瀏覽器端」跑,iOS 的原生播放器走代理拿到的 m3u8,跟 PC 走 hls.js 拿到的 m3u8,是兩條不同的路徑。**
看 src/app/api/proxy/m3u8/route.ts 這段(就是它害的):
// 处理嵌套的 M3U8 文件 (EXT-X-STREAM-INF)
if (line.startsWith('#EXT-X-STREAM-INF:')) {
rewrittenLines.push(line);
...
const proxyUrl = ${proxyBase}/m3u8?url=${encodeURIComponent(resolvedUrl)}${sourceParam}${refererParam};
rewrittenLines.push(proxyUrl);
continue;
}
這段把 master 裡的子流 URL,重寫成指向你們自己站的一條代理鏈:/api/proxy/m3u8?url=...。當 iOS 原生播放器去抓這條代理 URL 時,伺服器端用 rewriteM3U8Content 又把它轉回上游,但這個伺服器端函式 rewriteM3U8Content 裡完全沒有呼叫你的 filterAdsFromM3U8 — 它只做了 URI 重寫(把 ts/key/m3u8 網址改指向自己的 segment proxy),根本沒做任何去廣告。
這就是為什麼三端結果分裂:
| 平台 |
播放路徑 |
你的過濾有沒有生效 |
| PC Chrome |
hls.js 走 MSE,直接抓 m3u8 |
有(瀏覽器端 filterAdsFromM3U8 被呼叫) |
| Android |
hls.js 走 MSE |
有 |
| iOS Safari |
原生 AVPlayer 抓 /api/proxy/m3u8 |
無(伺服器端重寫時沒有呼叫你的函式) |
所以你之前辛苦改的、現在已經改對的 regex 版本,其實在 iOS 上根本沒機會執行——iOS 播的是伺服器端代理出來的、未過濾的列表。
iOS 原生 HLS,而是在「伺服器端的 m3u8 代理」這個環節:它對 master playlist 和子流做了 URL 重寫,但你的
filterAdsFromM3U8只在「瀏覽器端」跑,iOS 的原生播放器走代理拿到的 m3u8,跟 PC 走 hls.js 拿到的 m3u8,是兩條不同的路徑。**看
src/app/api/proxy/m3u8/route.ts這段(就是它害的):// 处理嵌套的 M3U8 文件 (EXT-X-STREAM-INF)
if (line.startsWith('#EXT-X-STREAM-INF:')) {
rewrittenLines.push(line);
...
const proxyUrl =
${proxyBase}/m3u8?url=${encodeURIComponent(resolvedUrl)}${sourceParam}${refererParam};rewrittenLines.push(proxyUrl);
continue;
}
這段把 master 裡的子流 URL,重寫成指向你們自己站的一條代理鏈:
/api/proxy/m3u8?url=...。當 iOS 原生播放器去抓這條代理 URL 時,伺服器端用rewriteM3U8Content又把它轉回上游,但這個伺服器端函式rewriteM3U8Content裡完全沒有呼叫你的filterAdsFromM3U8— 它只做了 URI 重寫(把 ts/key/m3u8 網址改指向自己的 segment proxy),根本沒做任何去廣告。這就是為什麼三端結果分裂:
所以你之前辛苦改的、現在已經改對的 regex 版本,其實在 iOS 上根本沒機會執行——iOS 播的是伺服器端代理出來的、未過濾的列表。