脚本-把B站缓存m4s文件转换成mp4格式

news2024/10/24 12:58:12

js脚本,自动处理视频

  • 1. 需求简介
    • 1.1 pc安装b站客户端
    • 1.2 设置视频缓存目录
    • 1.3 找个视频缓存
    • 1.4 打开缓存文件夹![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0eb346a84d5f42a7908f1d39bf410c3b.png)
    • 1.5 用notepad++编辑后缀m4s文件,删除文件内开头9个0,把文件小的保存为mp3格式,文件大的保存为mp4格式
    • 1.6 用视频软件或blender把视频和音频合并
    • 1.7 根据需要视频转换分辨率
  • 2. 脚本使用
    • 2.1 需要安装nodejs [https://nodejs.org/zh-cn](https://nodejs.org/zh-cn)
    • 2.2 需要下载ffmpeg.exe
    • 2.3 运行脚本
    • 2.4 结果

背景:需要从b站下载视频,有方法,需要手动一步步操作,繁琐,作为程序员,自然选择自动化。

1. 需求简介

自动化就是把人做的事情用工具或代码自动实现,所以需要先了解需求。

1.1 pc安装b站客户端

1.2 设置视频缓存目录

在这里插入图片描述

1.3 找个视频缓存

1.4 打开缓存文件夹在这里插入图片描述

1.5 用notepad++编辑后缀m4s文件,删除文件内开头9个0,把文件小的保存为mp3格式,文件大的保存为mp4格式

在这里插入图片描述

1.6 用视频软件或blender把视频和音频合并

1.7 根据需要视频转换分辨率

2. 脚本使用

2.1 需要安装nodejs https://nodejs.org/zh-cn

2.2 需要下载ffmpeg.exe

2.3 运行脚本

node .\main.js E:\bilibili "C:\Program Files (x86)\FormatFactory\ffmpeg.exe"
  • 参数1表示b站视频缓存目录,一般这里会有很多文件夹,每一个文件夹就是一个缓存视频
  • 在这里插入图片描述
  • 参数2表示ffmpeg.exe目录,注意路径有空格的需要用引号包起来
    main.js内容
// main.js

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

let myfiledataall = [];


// 获取文件大小,返回 Promise
function getFileSize(filePath) {
    return new Promise((resolve, reject) => {
        fs.stat(filePath, (err, stats) => {
            if (err) {
                reject(`获取文件大小失败: ${err}`);
            } else if (stats.isFile()) {
                resolve(stats.size);
            } else {
                resolve(0);
            }
        });
    });
}

// 遍历目录
async function traverseDirectory(directory) {
    try {
        const files = await fs.promises.readdir(directory);
        let myfiledata = [];
        for (const file of files) {
            const filePath = path.join(directory, file);
            const stats = await fs.promises.stat(filePath);
            if (stats.isDirectory()) {
                console.log(`文件夹: ${filePath}`);
                await traverseDirectory(filePath);
            } else if (filePath.endsWith('.m4s')) {
                const filesize = await getFileSize(filePath);
                myfiledata.push({ directory: directory, filename: filePath, filesize });
            }
        }
        myfiledataall.push(myfiledata);
    } catch (err) {
        console.error(`无法读取目录: ${err}`);
    }
}

// 读取文件
async function readFile(filePath) {
    try {
        return await fs.promises.readFile(filePath);
    } catch (err) {
        console.error(`读取文件失败: ${err}`);
        return '';
    }
}

// 写入文件
async function writeFile(filePath, content) {
    try {
        await fs.promises.writeFile(filePath, content);
        console.log('文件写入成功!');
    } catch (err) {
        console.error(`写入文件失败: ${err}`);
    }
}

// 获取命令行参数
const args = process.argv.slice(2);

let folderPath = args[0];
let ffmpegPath = args[1];
args.forEach(async (folderPath, index) => {
    console.log(`参数 ${index + 1}: ${folderPath}`);

});


async function handle() {
    await traverseDirectory(folderPath);
    // console.log("myfiledata:", myfiledataall);

    for (let myfiledata of myfiledataall) {
        console.log(myfiledata);
        if (myfiledata.length === 2) {
            const [first, second] = myfiledata;
            const largerFile = first.filesize > second.filesize ? first : second;
            const smallerFile = first === largerFile ? second : first;

            const videoFilePath = largerFile.filename.replace(".m4s", ".mp4");
            const audioFilePath = smallerFile.filename.replace(".m4s", ".mp3");

            await writeFile(videoFilePath, (await readFile(largerFile.filename)).slice(9));
            await writeFile(audioFilePath, (await readFile(smallerFile.filename)).slice(9));

            const outputFilePath = path.join(largerFile.directory, "output.mp4");
            console.log(outputFilePath);
            const outputFilePath2 = path.join(largerFile.directory, "output2.mp4");
            console.log(outputFilePath2);

            const command = `"${ffmpegPath}" -i "${videoFilePath}" -i "${audioFilePath}" -c:v copy -c:a aac -strict experimental "${outputFilePath}"`;
            console.log(command);
            exec(command, (error, stdout, stderr) => {
                if (error) {
                    console.error(`执行错误: ${error}`);
                    return;
                }
                console.log(`stdout: ${stdout}`);
                console.error(`stderr: ${stderr}`);
                console.log('合成完成!');

                const scaleCommand = `"${ffmpegPath}" -i "${outputFilePath}" -vf scale=960:544 "${outputFilePath2}"`;
                console.log(scaleCommand);
                exec(scaleCommand, (error, stdout, stderr) => {
                    if (error) {
                        console.error(`执行错误: ${error}`);
                        return;
                    }
                    console.log(`stdout: ${stdout}`);
                    console.error(`stderr: ${stderr}`);
                    console.log('分辨率转换完成!');
                });
            });
        }
    }

    console.log('处理完成!');
}

handle();

脚本最后执行2次ffmpeg,一次把mp4和mp3合成一个视频,一次把视频转换分辨率为960x544。

2.4 结果

在这里插入图片描述

  • output.mp4是第一次合成的原视频
  • output2.mp4 是分辨率为960x544的视频

如果视频很大,处理比较慢

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2222404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows系统启动MongoDB报错无法连接服务器

文章目录 发现问题解决办法 发现问题 1)、先是发现执行 mongo 命令,启动报错: error: MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017; 2)、再检查 MongoDB 进程 tasklist | findstr mongo 发现没有进程&a…

澳元/美元价格预测:不排除跌至0.6600的可能

澳元/美元一路下跌至0.6620附近。美元保持强劲上涨势头,升至创下三个月新高。汇价的下跌让关键的200日均线受到考验。 澳元/美元周三再度遭遇抛售兴趣,迅速扭转周二的多头尝试,滑落至0.6630附近的新低。这次急剧下跌也对关键的200日均线构成…

yjs机器学习常见算法01——KNN(02)Kd树

1.什么是Kd树,为什么要引入Kd树 knn是寻找k个邻近的点,在这个过程中,需要一个点一个点的与未分类点进行比较,这样的时间复杂度非常高,因此引入了一种原理类似二叉树的Kd树,以减少比较搜索的次数。 kd树的本…

PyTorch求导相关

PyTorch是动态图,即计算图的搭建和运算是同时的,随时可以输出结果;而TensorFlow是静态图。 在pytorch的计算图里只有两种元素:数据(tensor)和 运算(operation) 运算包括了&#xf…

Psychophysiology:脑-心交互如何影响个体的情绪体验?

摘要 情绪的主观体验与对身体(例如心脏)活动变化的情境感知和评估相关。情绪唤醒增加与高频心率变异性(HF-HRV)降低、EEG顶枕区α功率降低以及心跳诱发电位(HEP)振幅较高有关。本研究使用沉浸式虚拟现实(VR)技术来研究与情绪唤醒相关的脑心相互作用,以实现自然而可…

SSM考研科目学习APP-计算机毕业设计源码90377

摘 要 基于Android的考研科目学习系统的设计与实现,旨在为广大考研学子提供一个便捷、高效的学习平台。该系统充分利用Android操作系统的广泛普及与灵活定制性,结合考研科目的特点和需求,实现了个性化的学习方案、丰富的题库资源以及智能化…

【个人同步与备份】电脑(Windows)与手机/平板(Android)之间文件同步

文章目录 1. syncthing软件下载2. syncthing的使用2.1. 添加设备2.1.1. syncthing具备设备发现功能,因此安装好软件,只需确认设备信息是否对应即可2.1.2. 如果没有发现到,可以通过设备ID连接2.1.3. 设置GUI身份验证用户,让无关设备…

LeetCode: 3274. 检查棋盘方格颜色是否相同

一、题目 给你两个字符串 coordinate1 和 coordinate2,代表 8 x 8 国际象棋棋盘上的两个方格的坐标。   以下是棋盘的参考图。   如果这两个方格颜色相同,返回 true,否则返回 false。   坐标总是表示有效的棋盘方格。坐标的格式总是先…

大模型技术学习过程梳理,零基础入门到精通,收藏这一篇就够了

“ 学习是一个从围观到宏观,从宏观到微观的一个过程 ” 今天整体梳理一下大模型技术的框架,争取从大模型所涉及的理论,技术,应用等多个方面对大模型进行梳理。 01 — 大模型技术梳理 这次梳理大模型不仅仅是大模型本身的技术…

接口测试(八)jmeter——参数化(CSV Data Set Config)

一、CSV Data Set Config 需求:批量注册5个用户,从CSV文件导入用户数据 1. 【线程组】–>【添加】–>【配置元件】–>【CSV Data Set Config】 2. 【CSV数据文件设置】设置如下 3. 设置线程数为5 4. 运行后查看响应结果

vue3项目页面实现echarts图表渐变色的动态配置

完整代码可点击vue3项目页面实现echarts图表渐变色的动态配置-星林社区 https://www.jl1mall.com/forum/PostDetail?postId202410151031000091552查看 一、背景 在开发可配置业务平台时,需要实现让用户对项目内echarts图表的动态配置,让用户脱离代码也…

基于Matlab 人脸识别技术

Matlab 人脸识别技术 算法流程: 本系统运用PCA算法来实现人脸特征提取,然后通过计算欧式距离来判别待识别测试人脸,本个系统框架图如下: 图: 人脸识别系统框架图 整个系统的流程是这样的,首先通过图像采…

给哔哩哔哩bilibili电脑版做个手机遥控器

前言 bilibili电脑版可以在电脑屏幕上观看bilibili视频。然而,电脑版的bilibili不能通过手机控制视频翻页和调节音量,这意味着观看视频时需要一直坐在电脑旁边。那么,有没有办法制作一个手机遥控器来控制bilibili电脑版呢? 首先…

基于SpringBoot+Vue+uniapp的时间管理小程序的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不…

【文件加密系统】华企盾DSC服务程序启动失败解决办法

问题原因: 1.sa账户密码错误导致连接数据数据库失败无法启动DSC服务 解决方法: 用windows身份验证进入数据库更改sa用户密码:安全性>登录名>sa>右键属性>更改密码 ※如果显示请输入秘钥更改,使用更改完密码的sa账户登…

从0开始深度学习(16)——暂退法(Dropout)

上一章的过拟合是由于数据不足导致的,但如果我们有比特征多得多的样本,深度神经网络也有可能过拟合 1 扰动的稳健性 经典泛化理论认为,为了缩小训练和测试性能之间的差距,应该以简单的模型为目标,即模型以较小的维度的…

机器学习与神经网络:科技的星辰大海

前提 近日,2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者,这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家,如今却将全球范围内对机器学习和神经网络的研究和开发作为了一…

RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器

RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器 随着现代互联网应用的不断发展,实时通信已经成为许多应用程序不可或缺的功能。无论是社交网络、在线游戏还是数据监控系统,实时通信都能提供快速、无缝的信息交换。而实现实时通…

“主升筹码”,底部建仓信号+主升加仓位置,不错过任何行情

使用技巧 指标分为主图和副图 其中,主图主升筹码信号较多,副图的信号较少。这里,我说一个选股思路,就是底部主升筹码共振进场,上升过程中主图信号当作加仓信号。 选股,提供一个主升筹码共振选股&#xff0…

Redis 5.0 安装配置(Windows)

Redis 5.0之后支持Redis Stream等功能 下载地址:Releases tporadowski/redis GitHub 点击运行redis-server.exe 此外:Redis 6.0及以后版本目前都没有Windows版