M3U8嗅探下载
思路与核心代码
基本思路
M3U8视频格式是一种基于HTTP Live Streaming(HLS)协议的视频文件格式。它是苹果公司开发的,目前广泛应用于iOS、macOS和tvOS等系统中。与传统的视频格式不同,M3U8视频格式将整个视频分成多个小片段进行传输,这些小片段可以根据网络情况自动调节其质量和大小。这种方式使得M3U8视频格式非常适合在网络环境不稳定或带宽不足的情况下播放视频。
示例-1就是一个m3u8文件的内容截取,一个个的ts文件就是一个个小的视频片段,所以我们拿到m3u8文件并解析内容之后,将一个个ts文件合并到一起就是完整的视频。浏览器 chrome.webRequest
API 可以观察和分析流量,以及拦截、屏蔽或修改运行中的请求。我们可以用它来嗅探网页中的m3u8文件地址。
示例 - 1:m3u8文件内容
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:8
#EXT-X-DISCONTINUITY#EXTINF:4.000000,
cf645dad0e2000000.ts
#EXTINF:4.000000,
cf645dad0e2000001.ts
#EXTINF:4.000000,
cf645dad0e2000002.ts
#EXTINF:4.000000,
cf645dad0e2000003.ts#EXT-X-ENDLIST
示例 - 2 :嗅探文件请求
var caches = {};
chrome.webRequest.onCompleted.addListener(function(details){let rul = details.url;let type = details.type;let documentId = details.documentId;if(type == 'xmlhttprequest'){let suffix = rul.substr(rul.lastIndexOf('\.'));if(suffix == '.m3u8'){if(!caches[documentId]){caches[documentId] = {list:[]};}caches[documentId].list.push(rul);}}
}, {urls: ["<all_urls>"]}, []);
- 使用
chrome.webRequest
API监听网络请求完成事件,当请求的是m3u8文件时记录请求路径。
示例 - 3 :解析m3u8并缓存ts
function cacheFile(tabId,index,url) {fetch(url).then(response => {return response.text()}).then(data => {let lines = data.trim().split("\n");let files = lines.filter(line => line.trim().endsWith('.ts')); // 需要缓存的文件列表 let baseUrl = url.substring(0,url.lastIndexOf('\/')); // 缓存视频的基本路径let fileSize = 0; // 已经缓存的文件数量files.forEach((fileName,x)=>{fetch(baseUrl+"/"+fileName).then(response => {return response.blob();}).then(blob => {let reader = new FileReader();reader.onloadend = function() {let key = tabId+""+index+""+x;chrome.storage.local.set({ [key] : reader.result }).then(() => {fileSize = fileSize+1;console.log("进度:"+fileSize+"/"+files.length);if(fileSize==files.length){ // 全部缓存之后,通知合并下载chrome.tabs.sendMessage(tabId,{ command: 'download', tabId:tabId, index:index, fileSize:fileSize });}else{ // 更新进度chrome.tabs.sendMessage(tabId,{ command: 'update-cache-progress', tabId:tabId, progress:fileSize, fileSize:files.length });}});};reader.readAsDataURL(blob);}).catch((err) => {console.error("缓存异常:["+baseUrl+"/"+fileName+"]"+err);});});});
}
示例 - 4 :环形进度条
<svg id="progressSVG" width="80" height="80"><circle cx="40" cy="40" r="30" fill="none" stroke="#ddd" stroke-width="5" /><circle class="progress" cx="40" cy="40" r="30" fill="none" stroke="#0f0" stroke-width="5" stroke-dasharray="188.5" stroke-dashoffset="190.9"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" font-size="12">0%</text>
</svg>
- 两个空心圆,第二个空心圆通过stroke、stroke-width、stroke-dasharray、stroke-dashoffset定义了轮廓,通过更新stroke-dashoffset使其绿色轮廓覆盖第一个空心圆,就实现了一个简单的环形进度条。