V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dabaisuv
V2EX  ›  程序员

写了一个无限制视频下载脚本

  •  5
     
  •   dabaisuv ·
    dabaisuv · 128 天前 · 8188 次点击
    这是一个创建于 128 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在家想下载视频到本地,发现很多视频网站的video标签的src指向了 Blob: http(s)://xxx.xxx.xxx/xxx,直接进这个链接的话会显示链接已禁用。 想法:既然能播放视频,就证明视频到最后一定是被 video 拿到了的.

    谷歌一圈后发现了: 1.window.URL.createObjectURL(object)方法会返回该链接

    A File, Blob, or MediaSource object to create an object URL for.( https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

    2.window.URL.revokeObjectURL(objectURL),禁用上面返回的链接

    A string representing a object URL that was previously created by calling createObjectURL().( https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL)

    尝试:

    1.hook 了window.URL.revokeObjectURL(objectURL)来忽略禁用请求,结果没用,依旧被禁用。

    2.换个方法,直接 hook 二进制流,你缓存多少,我给你复制多少。查了下MediaSource, 他结合上面的createObjectURL(object)可以分片的方式加载视频,大概就是看多少,就加多少。 其中的音频和视频分别放在两个 sourceBuffer 中,直接 hook 住SourceBuffer.appendBuffer()就能实现视频流的截取了。再将每个分片以数组的方式保存下来,最后等视频缓存完后 new Blob(video/audio bufferArray)这样就实现了视频和音频的保存。

    3.由于播放的时候,视频和音频分在两个 SourceBuffer 中,所以最后会得到两个文件。又是一番谷歌,有如下命令:

    ffmpeg -i video.mp4 -i audio.mp4 -c:v copy -c:a aac -strict experimental output.mp4
    

    可以将其合并为一个视频。

    4.想过用 ffmpeg 的 wasm 库来在线合并,最后输出的,发现 ffmpeg-core 初始化时所需要的文件在国内下载不下来导致报错,从而导致适用的用户可能有点少,所以就没加,可能是我使用方法不对,以后有时间可以改改。

    5.发现有些网站的视频是在iframe标签下的,并且加了sandbox属性,而有该属性的话就会导致最后的下载被拦截,于是,我使用了如下代码来将页面中的所有frame替换成无sandbox属性的:

     (function (that) {
              let removeSandboxInterval = setInterval(() => {
                 if (that.document.querySelectorAll('iframe')[0] !== undefined) {
                    that.document.querySelectorAll('iframe').forEach((v, i, a) => {
                       let ifr = v;
                       ifr.removeAttribute('sandbox');
                       const parentElem = that.document.querySelectorAll('iframe')[i].parentElement;
                       a[i].remove();
                       parentElem.appendChild(ifr);
                    });
                    clearInterval(removeSandboxInterval);
                 }
              }, 1000);
           })(window);
    

    于是有了如下油猴脚本:

    英文名:Unlimited_downloader

    https://greasyfork.org/en/scripts/445751-unlimited-downloader

    Ps: 都是谷歌翻译成英文的,因为英文是个通用语言,所以不同地方的人看起来可能要方便点。

    简短说明:

    原理:直接 hook 媒体二进制流,换句话说就是你能看到,你就能下载,你能缓存多快,你就能下载多快。

    使用方法:安装后,打开任意有视频或音频的网站,等视频缓存条加载完后会自动下载下来。

    也可以自己手动开 16 倍速加速缓存,控制台输入:document.querySelector('video').playbackRate = x

    最后,免责声明:请在合法范围内使用脚本,请勿用作任何非法用途,后果与作者无关。

    第 1 条附言  ·  128 天前

    感谢分享功能类似插件,大家可以自己挑个来用,互为补充:

    @linglin0924 最近有一些不能下载的视频,我都是用这个插件,看他的运行方式,应该也是读流合并的 https://chrome.google.com/webstore/detail/video-downloader-cococut/gddbgllpilhpnjpkdbopahnpealaklle

    @hbtech 很有意思,功能跟这个扩展也有点像: https://chrome.google.com/webstore/detail/stream-recorder-download/iogidnfllpdhagebkblkgbfijkbkjdmm

    第 2 条附言  ·  128 天前

    @tammy 我都是调用 you-get 下载的(Firefox 添加“鼠标中键点击下载按钮条用 you-get.exe 下载视频” 的功能 - Ryan 快快跑),对于支持的网站不用说,一流,默认最高画质,在配合你这个搞不支持的网站,那就更舒服了

    84 条回复    2022-06-13 10:54:01 +08:00
    Louis423Lee
        1
    Louis423Lee  
       128 天前
    感谢 op ,请问能选择视频的清晰度下载吗?
    dabaisuv
        2
    dabaisuv  
    OP
       128 天前
    @Louis423Lee 可以的,原理就是 hook 播放的视频的二进制流,你只要能把视频的画质调到对应的清晰度即可。
    goodhellonice
        3
    goodhellonice  
       128 天前
    试了下哔哩哔哩。。。。结果只下载了音频
    dabaisuv
        4
    dabaisuv  
    OP
       128 天前
    @goodhellonice 我测试的时候,各大网站都行的,你看看是不是有下载被拦截了,我的谷歌浏览器在一次性弹两个下载时会自动拦截一个,这个需要你同意多个文件下载权限
    linglin0924
        5
    linglin0924  
       128 天前
    刚试了油管,看完视频自动下载了视频和一个音频。感觉自动下载有点那啥。

    可以的话让用户给选择是否下载
    linglin0924
        6
    linglin0924  
       128 天前
    最近有一些不能下载的视频,我都是用这个插件,看他的运行方式,应该也是读流合并的

    https://chrome.google.com/webstore/detail/video-downloader-cococut/gddbgllpilhpnjpkdbopahnpealaklle
    creanme
        7
    creanme  
       128 天前
    IDM 可以自动识别
    HeyWeGo
        8
    HeyWeGo  
       128 天前
    试了下油管:
    如果一个视频有 4 分钟,开头我看了 10s ,然后手动跳过一部分未缓存的,继续播 3 分之后的内容,是不是就没法完整缓存整个了,分两段下载?
    hbtech
        9
    hbtech  
       128 天前
    libook
        10
    libook  
       128 天前
    这个东西很厉害,基本能突破很多 HLS 加密方案了。
    dabaisuv
        11
    dabaisuv  
    OP
       128 天前
    @HeyWeGo 也是一段,但是最终通过 ffmpeg 合成后,播放到你跳过的那段好像会空白还是跳过,这个不太记得了
    goodhellonice
        12
    goodhellonice  
       128 天前
    @dabaisuv 好的 我再看看 是不是我开着其他脚本或扩展的问题 谢谢
    dabaisuv
        13
    dabaisuv  
    OP
       128 天前
    @linglin0924 这个可以选择,在源代码里面把 window.autoDownload 设置为 0 就行,然后想下载的话在控制台输入 window.downloadAll = 1 。我设置成自动下载,主要是因为有些视频网站是 iframe 里面播放的,这样在控制台输入 window.downloadAll = 1 的话,下载的会是空白的,因为视频的缓存是在 iframe 里面,两者的 window 指向不同 document 。以后可能会更新就算视频在 iframe 里面也能下载到的功能。现在的最佳解决办法就是自动下载,配合油猴的开关插件,在需要的时候再载入插件
    dabaisuv
        14
    dabaisuv  
    OP
       128 天前
    @linglin0924
    @hbtech
    看了下说明,没安装,他这个可能是获取 m3u8 格式的 ts 文件后合并下载的,如果是这样的话,适用范围可能不是太广。你有用它试过下载 xilixili 视频吗,如果能下载的话,可能就是直接获取二进制流的,那跟我原理差不多
    linglin0924
        15
    linglin0924  
       128 天前
    @dabaisuv 这个插件,下载 b 站的视频得用录制模式,也是得等加载完才算下载完
    teasick
        16
    teasick  
       128 天前
    以为无下限视频
    dabaisuv
        17
    dabaisuv  
    OP
       128 天前
    @linglin0924
    感谢回复,那应该是一样的。我写脚本之前搜到有人推荐类似的,不过说的是下载 m3u8 。我这才写了这个脚本,不过好像白折腾了。
    crab
        18
    crab  
       128 天前
    91 上音频没问题,视频文件大小 OK ,时间不对。
    libook
        19
    libook  
       128 天前
    目前测试了主流的 HLS 加密,以及小鹅通那种比较强一些的加密也都是可以下载下来的。

    不过小鹅通下载下来的音频有问题,声音非常低沉,不知道是不是开了 16 倍速的原因。
    dabaisuv
        20
    dabaisuv  
    OP
       128 天前
    @crab 感谢回复,能说下具体情况吗
    LiuJiang
        21
    LiuJiang  
       128 天前
    哈哈哈,最近自己也写了个,给朋友用的
    Buges
        22
    Buges  
       128 天前 via Android
    你想岔了,不是每个网站都使用同一种方式播放还没有检测的。
    真正通用的方式是 patch chromium 的源码,直接截取播放的编码流,除了 DRM 和使用非浏览器自带播放器的网站外都能获取到。
    当然具体操作最大的成本是构建 chromium 需要的大量资源。
    dabaisuv
        23
    dabaisuv  
    OP
       128 天前
    @libook 感谢回复,我对音频编码不太了解,倍速讲道理不会影响声音。是合并后的问题还是下载下来就有的问题,如果是下载下来就有问题......这个是截取的视频流音频流,会不会是他的网页播放器是定制的自动提高音频,然后服务器存的就是降频的音频。亦或者是本地播放器的问题,这个我不太能回答。如果是合并后出的问题,可能是 ffmpeg 编码的问题?
    dabaisuv
        24
    dabaisuv  
    OP
       128 天前
    @Buges 感谢回复,改源码这个复杂性就太高了。在写脚本前,我查了下,目前几乎所有前端视频都是 video.src=window.URL.createObjectURL(MediaSource),而放入 MediaSource 的 SourceBuffer 之前的视频和音频流都应该是加密的,以此来防止网络嗅探。而我只需要在网站的 js 代码自己解密视频和音频流并放入 SourceBuffer 的时候截取就行,免去了伤脑细胞的加密算法分析,更加符合了 Ulimited_Downloader 的名称。
    另外,我目前查到的资料是,视频加密的话,最终基本都会到 SourceBuffer 这一步,而不用 SourceBuffer 的视频播放,一般可以使用手动使用 document.querySelector('video').src (如果网站使用了 iframe:document.querySelectorAll(iframe).forEach(v=>{console.log(v.contentDocument.querySelector('video').src)})直接获得视频直接链接,那这个脚本自然也没用处了。
    israinbow
        25
    israinbow  
       128 天前
    有 FF 的支持么, 楼上出现的插件都不支持 FF.
    dabaisuv
        26
    dabaisuv  
    OP
       128 天前
    @dabaisuv 如果是防检测的话,可以修改 toString()方法返回 hook 之前的函数的字符串,后续可以考虑加上
    dabaisuv
        27
    dabaisuv  
    OP
       128 天前
    @israinbow 感谢回复,可以具体说一下 FF 是什么缩写吗,我不太明白
    dabaisuv
        28
    dabaisuv  
    OP
       128 天前
    @dabaisuv 这又涉及到矛与盾的问题了,网站也可以不管 hook 没 hook ,而直接替换关键函数为信任的对应函数。这我也可以 hook 住它需要替换函数所需要的函数。总的来说就跟内核一样,谁更底层,谁更先,谁赢。
    israinbow
        29
    israinbow  
       128 天前
    @dabaisuv #27 Firefox, Mozilla 的火狐浏览器.
    dabaisuv
        30
    dabaisuv  
    OP
       128 天前
    @israinbow 没测试,不过我觉得应该支持,火狐能安装油猴插件把,能的话就应该能支持的,我这脚本没用浏览器特性,油猴的特性也没使用,甚至你可以直接用 fidder 插入代码。但不排除火狐有什么权限相关的问题。
    Buges
        31
    Buges  
       128 天前 via Android   ❤️ 2
    @dabaisuv 不管怎么样这种方式终归是在 js 端和网站斗智斗勇,patch chromium 的方式论复杂到也不是多复杂,几年前某安全论坛就看到过相关的资料,媒体模块加几行代码打 log 就能把内容提取出来,具体写的很清楚,只是没有成品。对程序员来说实施起来不难,只是构建 chromium 的成本太高了。
    tammy
        32
    tammy  
       128 天前
    johnnyNg
        33
    johnnyNg  
       128 天前
    思路挺可以的
    dabaisuv
        34
    dabaisuv  
    OP
       128 天前
    @Buges 再次感谢回复,之前没接触过 chromium 源码,看了你的回复后,我觉得可以抽时间来读一读,也可以提升一下自己对浏览器的理解。
    dabaisuv
        35
    dabaisuv  
    OP
       128 天前
    @johnnyNg
    @tammy

    感谢支持
    Buges
        36
    Buges  
       128 天前 via Android
    @dabaisuv 其实 chromium 的源码并不难,基本上就纯 OO ,没啥高级特性和黑魔法,而且很规范、注释丰富。不过规模太庞大了,代码量太多。之前给某 chromium 下游项目提 pr 看过 chromium 源码,体验就是定位两小时 patch 5 分钟,还有就是编译吃的资源太多,你得有高速的国际宽带+流量+大量的 SSD 硬盘空间+大内存+多核 CPU 再加上大量时间才能尝试构建。
    kkocdko
        37
    kkocdko  
       128 天前 via Android
    (题主做了我一直想做的事

    我感觉 hook 是现在页面增强很好的一个思路,之前有见过 hook 定时器来加速跳过视频站广告。

    前端的不透明度是越来越高了。
    ijrou
        39
    ijrou  
       128 天前
    @ijrou 要是你能搞定这个页面的话,那你这插件才是神。。。
    libook
        40
    libook  
       128 天前 via Android
    @dabaisuv 合并前有问题,可能是你说的那样。
    小鹅通对 video 定制得挺变态的,但 drm 效果好,工信部在用。
    darer
        41
    darer  
       128 天前
    提个小建议 文件名可以改成 title_format
    darer
        42
    darer  
       128 天前
    @libook 倍速后音频会过一个变速不变调算法 估计是这个的缘故
    HFX3389
        43
    HFX3389  
       128 天前
    @Buges #22 知道了在哪改的话,弄个按量付费的云服务器,24G 内存的 80~100 左右一天(因为我没试过编译 chromium 需要多久所以就按一天算),而且浏览器这类应用编译完一次可以用很久的
    dabaisuv
        44
    dabaisuv  
    OP
       128 天前
    @darer 感谢回复,我一会就改成 title_format 格式。
    Buges
        45
    Buges  
       128 天前 via Android
    @HFX3389 没试过这种方式,但我盲猜国内服务器第一步代码都拉不下来。而且修改了以后还是要调试的,增量编译+链接一次也要几分钟。
    HFX3389
        46
    HFX3389  
       128 天前
    @Buges #45 那就弄香港、日本、韩国、新加坡的服务器呗,这样代码拉下来就容易多了;至于后面的修改调试就得看前期代码熟练度了,不能啥都没看就直接上服务器吧,这样太烧钱了,一天一百。应该是先在本地上看完大致有个思路、模板什么的,到时候一击必中或者只要经过很小的调试就可以用
    siknet
        47
    siknet  
       128 天前
    @libook 正在下小鹅通。分享链接到傲游 PC 端,然后扫码或者短信登录,自带的资源管理器能嗅探到文件链接,下载就行了。如果播放不了就在点播放后切换线路就行了。
    dabaisuv
        48
    dabaisuv  
    OP
       128 天前
    @ijrou 感谢回复,看了下它的 js 源码,定位到这一行是检测代码
    //(t || 1 == i || n && "auto" !== n || r && -1 === r.indexOf("360") || o) && (s.remove(), s.setStorage(), s.destroy())
    是循环检测的。注释掉就行了。但是我不打算加入到脚本,这个太有针对性了,有法律风险;
    dabaisuv
        49
    dabaisuv  
    OP
       128 天前
    @darer 感谢建议,插件更新了,目前可以简单的防止 hook 检测,并且下载的文件名会是:网站标题+audio/video.mp4
    lizhenda
        50
    lizhenda  
       128 天前
    思路不错哦
    dabaisuv
        51
    dabaisuv  
    OP
       127 天前
    @lizhenda 谢谢支持
    zhw2590582
        52
    zhw2590582  
       127 天前
    和我之前写得一个 chrome 扩展差不多原理,用来转码获取 B 站直播间的 Flv 流,后面发现直播地址会因为网络波动而变化,获取到的流不能合并在一起,后面换了个思路,直接用 MediaRecorder ,随他地址怎么切换都能录制

    https://chrome.google.com/webstore/detail/bilibili-%E5%BD%95%E6%92%AD%E5%A7%AC/nagmkdppcmenlcgelpgkjoknakghllml
    xx3122
        53
    xx3122  
       127 天前
    马了,期待支持所有网站
    dabaisuv
        54
    dabaisuv  
    OP
       127 天前
    @zhw2590582 感谢回复,MediaRecorder ,涨知识了,之前我还没查到这个函数
    dabaisuv
        55
    dabaisuv  
    OP
       127 天前
    @xx3122 感谢回复,有问题可以在这里或者 github or greasyFork 提哦
    ufan0
        56
    ufan0  
       127 天前
    很久之前捯饬过,没用到啥技术,只是扒 ie 浏览器的缓存,直接提取缓存文件拼接。

    希望楼主工具越做越好,mark ~
    neptuno
        57
    neptuno  
       127 天前 via iPhone
    @libook #40 小鹅通链接替换下就行了,很简单的
    dabaisuv
        58
    dabaisuv  
    OP
       127 天前
    @ufan0 感谢支持,会持续更新的.
    byte10
        59
    byte10  
       127 天前
    这个样的插件是不是很多?我以前好像用到过这样的脚本,也是用谷歌的插件去下载视频。可以下载腾讯课堂的视频
    hahahahahahahah
        60
    hahahahahahahah  
       127 天前 via iPhone
    a 站下载音频有问题,没有倍速
    heiyutian
        61
    heiyutian  
       127 天前
    建议可以只保存观看或缓冲的部分,有很多视频真的只需要一部分就够了,有时候并不需要整个视频,如果视频很长就比较费流量和时间了。
    Rrrrrr
        62
    Rrrrrr  
       127 天前
    b 站确实不行,只有音频。我之前都是自己去分析代码,拿到真实地址,不过比较费时间。
    zhaozhao
        63
    zhaozhao  
       127 天前
    之前看到过一个完成度挺高的工具,原理一样

    “无差别视频提取工具”
    https://segmentfault.com/a/1190000025182822
    tianyou666shen
        64
    tianyou666shen  
       127 天前
    用这个下了个视频 还不错 就是免费版两小时只能下一次文件
    Video DownloadHelper (chrome)
    root01
        65
    root01  
       127 天前
    OP 很给力,但是视频和音频下载下来是分开的,美中不足
    非常感谢 OP
    root01
        66
    root01  
       127 天前
    抱歉,没看完整,原来是分开的
    OMGZui
        67
    OMGZui  
       127 天前
    感谢,很牛逼
    FaiChou
        68
    FaiChou  
       127 天前
    这个原理不错, 前几天刚好遇到这个问题 : [Instagram 网页版视频是如何限制在 devtools 中找到视频链接进行直接下载的]( https://v2ex.com/t/852210#reply6)
    shaojz2005
        69
    shaojz2005  
       127 天前
    这些是针对什么视频网站的。我试了这几个,好像 B 站都下不回来
    dabaisuv
        70
    dabaisuv  
    OP
       127 天前
    @shaojz2005 测试的时候国内外的都行的。
    dabaisuv
        71
    dabaisuv  
    OP
       127 天前
    @zhaozhao 看了下,原理是一样的,而且他还写了界面,感觉好用的多
    dabaisuv
        72
    dabaisuv  
    OP
       127 天前
    @Rrrrrr 测试的时候都行的啊,我昨晚都能下
    dabaisuv
        73
    dabaisuv  
    OP
       127 天前
    @heiyutian 控制台输入 window.downloadAll = 1 可以提前下载
    hxz0803
        74
    hxz0803  
       127 天前
    试了一下,DMM 那种视频也可以下载
    xifangczy
        75
    xifangczy  
       126 天前
    之前我也有类似的想法,甚至经历都跟你差不多一步步试验过来,想装到 chrome 扩展里...因为扩展 manifest 升级到了 V3 然后又因为 V3 的脚本注入 API scripting 又巨难用,它甚至不能在 document-start 运行(刚刚去看了 102 版终于加上了)... 我就搁置了。。还是油猴脚本好使啊
    shaojz2005
        76
    shaojz2005  
       126 天前
    @dabaisuv 我装了你这个插件,然后打开哔哩哔哩视频时,在视频页没有右上角的捕获片段的提示,但是哔哩哔哩首页或者搜索页(即进入详情页的上一页)会有提示捕获,但最后都没下载到什么完整的视频,都是一些小片段。不知道我是不是操作流程有什么问题。。。
    shaojz2005
        77
    shaojz2005  
       126 天前
    咦,再试了下又可以了
    dabaisuv
        78
    dabaisuv  
    OP
       126 天前   ❤️ 1
    @shaojz2005 这代码没有加右上角的捕获片段提示啊,捕获到了片段会在控制台打印出来
    Rrrrrr
        79
    Rrrrrr  
       126 天前
    应该要加个按钮,点开始才下,我昨晚看 youtube 怎么突然就给我下了一个视频
    heiyutian
        80
    heiyutian  
       126 天前
    @dabaisuv 如果把只保存观看或缓冲的部分加到 Tampermonkey 的右键菜单来启用就更好了
    shaojz2005
        81
    shaojz2005  
       126 天前
    @dabaisuv 我用了这个帖子里另外一个
    dabaisuv
        82
    dabaisuv  
    OP
       126 天前
    @heiyutian 这个不太会,有时间会考虑的
    @Rrrrrr 这个。。不下的话就把插件关掉吧,自动下载主要针对 iframe 的,如果手动的话,会出现控制不了 iframe 里面视频的情况。你看打开一个视频网页,这个插件会加载多次(出现多个 start.....),这就是因为每个 iframe 也会加载一次插件,他们在不同的上下文中。手动的话只能控制最上层那个,就会出现视频下载空白的现象
    MiketsuSmasher
        83
    MiketsuSmasher  
       115 天前
    楼主的这个脚本无法下载学习通课程视频,即便在脚本文件里设置 window.autoDownload = 1 也没有用,在控制台设置 window.downloadAll = 1 下载到的是空白文件
    dabaisuv
        84
    dabaisuv  
    OP
       115 天前
    @MiketsuSmasher 它视频就没加密,直链就能下载。。。。,记得把 refer 标头改成视频页面网址就行的
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2436 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 62ms · UTC 13:58 · PVG 21:58 · LAX 06:58 · JFK 09:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.