央视视频下载2025年8月更新

央视最近又又又改加密算法了,网页段的h5e解密应该是没戏了。听说有人又搞出来了客户端的hls2解密,测试了一下可以用。当然能用多久就不好说了。毕竟现在的下载方法挂的越来越快了,且用且珍惜吧。

我自己让Ai写了个程序调用m3u8下载器,需要安装python和ffmpeg并添加环境变量

如果你不想安装python或者安不上,也可以去用GitHub上面的其他人做的版本,有GUI会更方便一点,下载地址在这里(国内网盘加速)

解密程序下载地址

https://radiance.lanzoub.com/is0Vt349pboh

把文件解压到一个没有中文名的目录下面,然后复制完整的路径

然后cd切换到这个目录

接下来输入python run.py 视频的GUID值

GUID值的获取之前说过了

遇到像这样红红的一大片不用管,会解密成功的

最后写一下等这个方法失效以后该怎么办吧

目前已经失效的方法:

HLS视频:2024年3月失效,后来有人补过一次但是2024年9月又失效了。

HLS视频(第三方域名):2024年11月失效。

MP4合并法:2024年2月被隐藏,今年年初被隐藏的更深了,但其实还能用,只是非常麻烦且有局限性。

H5E视频:8月初刚刚失效。

HLS2视频:目前有效,但估计撑不了几个月。

浏览器提取缓存法:这个方法永远不会失效,但是耗费的系统资源多,下载速度慢,而且有时会丢帧。B站上面有个软件实现了自动化可以看看

最后,CCTV在其它平台比如B站、YouTube、咪咕视频、央视频等网站上面也有账号,如果CCTV的视频下载不下来的话,不妨去这些平台看看。B站可以用bbdown油管用idm自带的视频嗅探就行。咪咕的话缓存视频改扩展名,或者f12+m3u8下载器都可。央视频的稍微麻烦点,得抓包or投屏,但也能下。而且这几个平台清晰度全比CCTV要高。

评论

  1. TH
    Android Chrome 131.0.6778.200
    1 周前
    2025-8-24 4:18:10

    h5e上VMP保护了,dhls2(央视影音缓存)不清楚还能坚持多久

    • TH
      TH
      Android Chrome 131.0.6778.200
      1 周前
      2025-8-24 4:21:12

      原先还有个能看下架视频的hls域名,但是8.1后这个域名就out了

      • Sky
        TH
        Windows Chrome 138.0.0.0
        1 周前
        2025-8-24 7:37:55

        原先那个域名是哪个啊

        • TH
          Sky
          Android Chrome 131.0.6778.200
          1 周前
          2025-8-24 14:02:16

          hls09.cntv.myhwcdn.cn

          • 博主
            TH
            Windows Chrome 138.0.0.0
            1 周前
            2025-8-24 14:16:08

            那个域名最开始就是我在GitHub上面公开的,为了防止它失效还特意屏蔽了所有中国大陆的流量,但是还是没挺过一个月。
            另外其实那批域名有好多个,我只公开了其中的两个,但是剩下的没公开的也挂了。

          • TH
            Sky
            Android Chrome 131.0.6778.200
            1 周前
            2025-8-24 18:59:01

            主要是ip138流放了这个域名

          • TH
            Sky
            Android Chrome 131.0.6778.200
            1 周前
            2025-8-24 19:08:03

            事实上去年还有一个dwk.cntv.qcloudcdn.com,那个域名当时还能看清晰的m3u8(看不了下架视频),当时10月和那个hlssnap域名也被央视网榨干了

          • 博主
            TH
            Android Chrome 140.0.7339.15
            1 周前
            2025-8-24 20:07:01

            现在其实下架视频还是能看的,只要能搞到guid并且服务器端没有删除文件就可以。目前能找到最早的视频是2005年的。

          • TH
            Sky
            Android Chrome 131.0.6778.200
            1 周前
            2025-8-25 3:27:08

            事实上hls域名的网宿cdn也是可以看下架视频的,跟看mp4和flv的方法是一样的,画质都是动了手脚的

          • 博主
            TH
            Android Chrome 140.0.7339.15
            7 天前
            2025-8-25 12:11:21

            老视频画质也没多高,本来就不清楚,用不花瓶的域名下就可以了。不过不知道它们为什么要把已经下架的视频也给转换成花屏的文件了,根本没必要啊。

  2. weaponjang
    Windows Chrome 137.0.0.0
    7 天前
    2025-8-25 12:29:57

    可能是央视cdn服务器的开销太大了,跨省结算后可能cdn涨价了,所以想方设法降本增效

    • 博主
      weaponjang
      Android Chrome 140.0.7339.15
      6 天前
      2025-8-26 8:44:23

      我之前也这么猜测过,因为23年我就抓包发现央视已经开始用PCDN了。另外央视海外的CDN已经撤光了,原来是阿卡迈,现在已经没了。

  3. weaponjang
    Windows Chrome 137.0.0.0
    7 天前
    2025-8-25 12:40:10

    这个cbox.exe是哪个时候的版本?怎么感觉大小和我从52pj论坛上下载的大小不一样呢,可惜没有版本号,不然还能知道新旧

    • 博主
      weaponjang
      Android Chrome 140.0.7339.15
      6 天前
      2025-8-26 8:43:02

      我也是从那上面下载的,应该是通用的版本吧,或者可能那边更新了我这边没更新。

      • weaponjang
        Sky
        Windows Chrome 137.0.0.0
        5 天前
        2025-8-27 10:21:01

        你的估计是旧版,我看更改时间你的是8月8日,他的是8月12日,我自己基于bun.js也写了个调用ffmpeg和ffprobe的下载器,源码如下,欢迎大佬们指摘

        // 基于bun.js,可打包成单个可执行程序文件
        const { join } = require('path');
        const { mkdir, rm } = require('fs/promises');
        const { spawn, spawnSync } = require('child_process');
        const { homedir } = require('os');
        const https = require('https');
        const readline = require('readline');
        
        const pdl = process.env.PUBLIC ? join(process.env.PUBLIC,'Downloads') : 'C:\\Users\\Public\\Downloads';
        // 配置常量 , 下载超时30分钟
        const CONFIG = {
            API_URL: "https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid={guid}&client=flash",
            PUBLIC_DOWNLOADS: pdl,
            TIMEOUT: 30 * 60 * 1000
        };
        
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });
        
        // 全局替换
        function replaceAll(source, search, replacement){
          const parts = [];
          let lastIndex = 0;
          const searchLength = search.length;
        
          while (true) {
            const index = source.indexOf(search, lastIndex);
            if (index === -1) {
              parts.push(source.slice(lastIndex));
              break;
            }
            parts.push(source.slice(lastIndex, index), replacement);
            lastIndex = index + searchLength;
          }
        
          return parts.join("");
        }
        
        // 工具函数:获取视频元数据,超时30,000秒
        async function fetchVideoMeta(guid) {
            const url = CONFIG.API_URL.replace('{guid}', guid);
            const data = await new Promise(resolve => {
                const req = https.get(url, { timeout: 30000 }, res => {
                    let rawData = '';
                    res.on('data', chunk => rawData += chunk);
                    res.on('end', () => {
                        try { resolve(JSON.parse(rawData)); }
                        catch { resolve(null); }
                    });
                });
                req.on('error', () => resolve(null));
            });
        
            if (!data?.hls_url) throw new Error('API请求失败');
        
            const is4K = data.play_channel?.includes('4K') || false;
            const m3u8main = is4K ? data.hls_url : data.manifest?.hls_enc2_url ;
            const m3u8Url = is4K ? replaceAll(m3u8main,'main','4000') : m3u8main;
            return {
                title: (data.title || guid).replace(/[\\/:*?"<>|]/g, '').trim(),
                m3u8Url: m3u8Url,
                is4K: is4K,
                guid: guid
            };
        }
        
        // 工具函数:执行FFmpeg命令
        async function runFFmpeg(args) {
            return runCommand('ffmpeg', [
                '-hide_banner', '-y',
                '-loglevel', 'panic',
                ...args
            ]);
        }
        
        // 工具函数:执行通用命令
        async function runCommand(cmd, args) {
            console.log(`→ ${cmd} ${args.join(' ')}`);
            let startTime = Date.now();
            return new Promise((resolve, reject) => {
                const proc = spawn(cmd, args, { 
                    stdio: ['inherit', 'inherit', 'inherit'],
                    windowsHide: true 
                });
        
                const progressTimer = setInterval(() => {
                    const elapsed = Math.floor((Date.now() - startTime) / 1000);
                    process.stdout.write(`\r⏱️ 已运行: ${elapsed}s `);
                }, 1000);
        
                const timer = setTimeout(() => {
                    clearInterval(progressTimer);
                    proc.kill();
                    reject(`${cmd} 执行超时`);
                }, CONFIG.TIMEOUT);
        
                proc.on('close', code => {
                    clearInterval(progressTimer);
                    clearTimeout(timer);
                    process.stdout.write('\n'); 
                    code === 0 ? resolve() : reject(`退出码 ${code}`);
                });
                proc.on('error', (err) => {
                    clearInterval(progressTimer);
                    clearTimeout(timer);
                    reject(`程序运行错误: ${err.message}`);
                });
            });
        }
        
        // 新增:获取最大码率流的索引
        async function getMaxBitrateStreamIndex(m3u8Url) {
            try {
                const probeResult = spawnSync('ffprobe', [
                    '-v' , 'panic' , '-hide_banner' ,
                    '-show_streams' , '-select_streams' , 'v' ,
                    '-of' , 'json' , '-i' ,
                    m3u8Url.replace("&","^&")
                ]);
        
                if (probeResult.status !== 0) {
                    console.warn('无法获取流信息,使用默认流');
                    return 0;
                }
        
                const probeData = JSON.parse(probeResult.stdout.toString());
                const streams = probeData.streams;
        
                if (!streams || streams.length === 0) {
                    return 0;
                }
        
                // 选择码率最大的流
                // maxSindex为从流信息获取的完整索引值
                let maxSindex = 0;
                // maxVindex为纯视频的索引值
                let maxVindex = 0;
                let maxBr = 0;
                streams.forEach((stream, n) => {
                    const sindex = stream.index;
                    if (sindex > maxSindex) {
                        maxSindex = sindex;
                        maxVindex = n;
                        maxBr = stream.tags.variant_bitrate;
                    }
                });
        
                console.log(`📊 选择最高码率流: 索引=${maxVindex}, 码率=${Math.round(maxBr / 1024000)} Mbps`);
                return maxVindex;
            } catch (error) {
                console.warn('获取流信息失败,使用默认流:', error.message);
                return 0;
            }
        }
        
        // 主处理函数
        async function processVideo(guid) {
            let tmpDir = '';
            try {
                const { title, m3u8Url, is4K, guid: fileGuid } = await fetchVideoMeta(guid);
                const safetitle = replaceAll(title,' ','_');
                const outputPath = join(CONFIG.PUBLIC_DOWNLOADS, `${safetitle}.mp4`);
                console.log(`\n${is4K ? '🟢 4K' : '🟠 标准'}视频: ${safetitle}`);
                console.log(`🔗 M3U8: ${m3u8Url}`);
        
                if (is4K) {
                    // 4K直通模式 - 选择最大码率流
                    await runFFmpeg([
                        '-protocol_whitelist', 'file,http,https,tcp,tls',
                        '-i', m3u8Url,
                        '-c', 'copy',
                        '-movflags', '+faststart',
                        outputPath
                    ]);
                } else {
                    const brbps =[450,850,1200,2000];
                    const maxVindex = await getMaxBitrateStreamIndex(m3u8Url);
                    const m3u8Max=brbps[maxVindex];
                    const m3u8MaxUri=replaceAll(m3u8Url,'main',m3u8Max);
                    // 标准处理流程 - 选择最大码率流
                    tmpDir = join(CONFIG.PUBLIC_DOWNLOADS, `tmp_${fileGuid}`);
                    await mkdir(tmpDir, { recursive: true });
        
                    const tsFile = join(tmpDir, `${fileGuid}.ts`);
                    const m2tFile = join(tmpDir, `${fileGuid}.m2t`);
        
                    // 下载时选择最大码率流
                    await runFFmpeg([
                        '-protocol_whitelist', 'file,http,https,tcp,tls',
                        '-i', m3u8MaxUri,
                        '-c', 'copy',
                        tsFile
                    ]);
        
                    await runCommand('cbox.exe', [tsFile, m2tFile]);
        
                    await runFFmpeg([
                        '-i', m2tFile,
                        '-c', 'copy',
                        '-movflags', '+faststart',
                        outputPath
                    ]);
                }
        
                console.log(`✅ 输出: ${outputPath}`);
                return true;
            } catch (e) {
                console.error(`❌ 失败: ${e.message}`);
                return false;
            } finally {
                if (tmpDir != '') {
                    try {
                        await rm(tmpDir, { recursive: true, force: true });
                        console.log(`🧹 已清理临时目录: ${tmpDir}`);
                    } catch (cleanupErr) {
                        console.warn(`⚠️ 清理临时目录失败: ${cleanupErr.message}`);
                    }
                }
            }
        }
        
        // 主交互流程
        async function main() {
            console.log(`
        ▓▓ CNTV视频下载器 ▓▓
        📊 功能: 自动选择最高码率流下载
        临时目录: tmp_[GUID]
        v1.1.0_20250826 (支持码率选择)
        ───────────────────`);
        
            while (true) {
                const input = await new Promise(resolve => 
                    rl.question('输入GUID(多GUID用逗号分隔/q退出): ', resolve));
                if (input.length < 32) break;
                if (input.toLowerCase() === 'q') break;
        
                const guids = input.split(',')
                    .map(g => g.trim())
                    .filter(g => /^[a-f0-9]{32}$/i.test(g));
        
                for (const guid of guids) {
                    await processVideo(guid);
                }
            }
        
            rl.close();
            console.log('程序结束');
        }
        
        if (require.main === module) {
            process.on('SIGINT', () => {
                console.log('\n操作已取消');
                process.exit();
            });
        
            main().catch(e => console.error('致命错误:', e));
        }
  4. weaponjang
    Windows Chrome 137.0.0.0
    5 天前
    2025-8-27 10:37:33

    GUID超简单获取办法:

     javascript:prompt("复制输入框中的GUID",guid);

发送评论 编辑评论


				
上一篇