You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网站需浏览器视频下载功能:能否用JS一次性下载合并m3u8分片?

浏览器端M3U8视频下载实现咨询

问题描述

我运营一个网站,需要实现浏览器端的视频下载功能。但视频链接为返回m3u8格式的流地址,我对该文件格式了解有限,仅知晓它会将视频分割为多个分片,按顺序逐个下载。现咨询:是否可编写能在浏览器运行的脚本,一次性下载所有分片并合并为完整视频?

尝试的代码

fetch(
  'video link here',
)
  // Retrieve its body as ReadableStream
  .then(response => {
    const reader = response.body.getReader();
    return new ReadableStream({
      start(controller) {
        return pump();
        function pump() {
          return reader.read().then(({ done, value }) => {
            // When no more data needs to be consumed, close the stream
            if (done) {
              controller.close();
              return;
            }
            // Enqueue the next data chunk into our target stream
            controller.enqueue(value);
            return pump();
          });
        }
      },
    });
  })
  // Create a new response out of the stream
  .then(stream => new Response(stream))
  // Create an object URL for the response
  .then(response => response.blob())
  .then(blob => {
    console.log('finish downloading blob');
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = _filename;
    link.click();
  })
  .catch(err => console.error(err));

解决方案

可以实现,但你当前的代码仅能下载单个资源,无法处理M3U8的分片解析与合并逻辑。以下是完整的实现方案:

核心流程

  • 解析M3U8内容,提取所有分片的绝对URL
  • 批量下载所有分片的二进制数据
  • 按顺序合并分片为完整视频Blob
  • 触发浏览器下载操作

完整实现代码

async function downloadM3U8Video(m3u8Url, filename = 'video.mp4') {
  try {
    // 1. 获取并解析M3U8文件
    const m3u8Res = await fetch(m3u8Url);
    const m3u8Content = await m3u8Res.text();
    
    // 提取所有非注释的分片链接,处理相对路径
    const segmentUrls = m3u8Content.split('\n')
      .filter(line => line.trim() && !line.startsWith('#'))
      .map(url => {
        if (!url.startsWith('http')) {
          const base = new URL(m3u8Url);
          base.pathname = base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1);
          return new URL(url, base).href;
        }
        return url;
      });

    if (!segmentUrls.length) throw new Error('未找到有效视频分片');

    // 2. 批量下载分片
    const segmentBlobs = await Promise.all(
      segmentUrls.map(url => fetch(url).then(res => res.blob()))
    );

    // 3. 合并分片为完整Blob
    const fullVideoBlob = new Blob(segmentBlobs, { type: 'video/mp4' });

    // 4. 触发下载
    const downloadLink = document.createElement('a');
    downloadLink.href = URL.createObjectURL(fullVideoBlob);
    downloadLink.download = filename;
    downloadLink.click();

    // 清理URL对象,避免内存泄漏
    setTimeout(() => URL.revokeObjectURL(downloadLink.href), 1000);
    console.log('视频下载完成');
  } catch (error) {
    console.error('下载失败:', error);
    alert('视频下载失败,请检查链接有效性或网络状态');
  }
}

// 使用示例
// downloadM3U8Video('你的M3U8流地址', '自定义文件名.mp4');

注意事项

  • 跨域限制:若M3U8或分片资源的域名与当前网站不同,需目标服务器配置Access-Control-Allow-Origin响应头,否则浏览器会拦截请求
  • 加密分片:如果M3U8包含#EXT-X-KEY加密标识,需额外添加解密逻辑,上述代码仅支持未加密分片
  • 并发控制:分片数量较多时,可添加并发请求限制(如每次同时下载5个分片),避免浏览器请求队列阻塞
  • 格式适配:合并Blob时的type需与实际视频格式匹配,若为WebM等格式需修改对应类型

内容的提问来源于stack exchange,提问作者Jake Lam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 15:18:26