将bilibili缓存的m4s音视频文件合并(基于ffmpeg/含xml弹幕转ass/附exe程序)
全水平向:萌新大佬都可食用
B站上视频资源很多,无论你是看番还是学习,它都能很大程度上满足你。可如果想下载B站上的视频方便随时观看 或是为了防止b站上的视频被删而保存到自己的设备上,又该如何操作呢?
首先下载b站上的视频官方的途径只有手机端的缓存(直接点app视频播放页面下的缓存按钮,或点击右上角“…”调出菜单再从里面点缓存)。我也比较推荐直接在手机端缓存后再复制到电脑或别的地方,毕竟官方渠道,稳定且下载速度快,操作简单。
###更新版本v1.8###
1.主程序和程序设置GUI;
2.支持xml2.0格式弹幕转换,支持自动下载封面和cc字幕;
3.通用模式(合并任意音视频文件)和兼容模式
4.现有预设加上搜索模式创建向导,软件理论上可以合并所有B站客户端的缓存视频
#################
[下面是旧版本的回答。新版本功能更加丰富,但由于代码量太大的原因不便于展示,具体的源代码可以联系软件里附的qq获取]
那么现在切入主题…(最新程序安装包的下载链接请往下翻)
现在(2020年)直接从b站缓存的视频都是video.m4s+audio.m4s音视频分开的形式,同时缓存的弹幕文件也是xml格式(仅部分视频软件可以读取显示),于是我的想法就是利用现在性能最好的通用音视频编码器ffmpeg实现快速合并,弹幕格式转换就用GitHub上一大佬@m13253 之前发布的的danmaku2ass源码。
xml转ass的python源码danmaku2ass.py:
网上关于利用ffmpeg合并视频的方法都要求使用者电脑安装了ffmpeg,直接利用cmd输入指令。这样既不便于新人操作也不便于移植,这里我直接把安装的ffmpeg复制出来,删掉一些用不上的组件后内嵌到软件里;
大小只有186MB,而且可移植,让合并软件在未安装ffmpeg的电脑上也能正常运行:
然后用python(我用的是较新的版本python3.8.1,v3以上都可)写主程序代码,实现对内嵌ffmpeg和danmaku2ass文件的调用,主程序代码如下:
1.程序只使用os,json,time 3个模组
import os
import json
import time
2.获取文件路径,检测danmaku2ass文件
if __name__ == '__main__':
path = "..\\"
save_path = "..\\bili_merge"
# 与用户交互获取对象路径
print("---自动扫描 程序文件夹 所在目录下的可合并文件(输入‘1’)\n---手动输入 需扫描文件夹 的路径(输入‘2’)\n---退出程序(输入除1,2外的任何字符):")
a = input("---")
if a == '1':pass
elif a == '2':
path = input("请在这里输入 缓存视频所在文件夹 的路径:").replace("/","\\\\")
save_path = f"{path}\\bili_merge"
else:os._exit(0)
source1_path = os.path.abspath("./ffmpeg/tools/ffmpeg/bin/ffmpeg.exe")
source2_path = "./danmaku2ass.py"
# 检测danmaku2ass.py文件是否在指定路径
try:
import danmaku2ass
switch = 1
print("danmaku2ass.py文件检测成功,自动开启弹幕转换","\n")
except ModuleNotFoundError:
print("未检测到弹幕转换资源文件!","\n")
switch = 0
3.利用os.walk()函数获取所以文件的路径
# 所有目录名和需要转换的文件名
all_title = []
all_video = []
all_audio = []
all_danma = []
# a:所在根目录,b:根目录下所有文件夹(列表形式),c:根目录下所有文件(列表形式)
for k, (a, b, c) in enumerate(os.walk(path)):
# 因为os.walk()是树检索,所以3类文件会一一对应
for i in c:
if i == 'entry.json':
title_path = os.path.join(a, i)
all_title.append(title_path)
elif i == "video.m4s":
video_path = os.path.join(a, i)
all_video.append(video_path)
elif i == "audio.m4s":
audio_path = os.path.join(a, i)
all_audio.append(audio_path)
elif i == "danmaku.xml":
danma_path = os.path.join(a, i)
all_danma.append(danma_path)
4.显示提示信息,创建bili_merge文件夹,准备开始转码
num = len(all_title)
if num == 0:
print("未找到可合并文件,请检查路径或文件格式。")
time.sleep(30)
os._exit(0)
os.makedirs(f"{save_path}", exist_ok=True)
print("共检测到 %s 个待合并文件\n合并进程已开始,请耐心等待~~~"%num,"\n")
5.按照之前获取的文件路径循环。读取entry文件对文件进行命名和分组;os.system()调用shell脚本带参执行内嵌的ffmpeg.exe进行音视频合并;调用danmaku2ass.Danmaku2ASS()函数进行xml转ass(这里的参数我已经调试过,如有其他需求可以自行修改)
failed = 0
tabel = str.maketrans("","",'''\/:*?"<>| ''')
# 一个个打开对应路径文件
for i, j in enumerate(all_title):
#解析entry.json文件
with open(j, encoding='utf-8') as data:
title_ = json.load(data)
# 目录名
title1 = title_["title"].translate(tabel)
# 视频名
try:
title2 = title_.get("ep","N/A")
if title2 == "N/A":title2 = title_["page_data"]["part"].translate(tabel)
else:
try:
index = int(title2['index'])
title2 = f"EP{index}_"+title2["index_title"].translate(tabel)
except ValueError:
title2 = title2['index']
except KeyError:
title2 = title1
print(f"输出目录:{title1}")
print(f"输出文件:{title2}.mp4......")
_path = f"{save_path}\\{title1}"
os.makedirs(_path, exist_ok=True)
cmd1 = f'{source1_path} -i {all_video[i]} -i {all_audio[i]} -c copy \"{_path}/{title2}.mp4'
# python调用Shell脚本执行cmd命令
os.system(cmd1)
# 调用danmaku2ass内建函数将xml弹幕文件转换成ass格式(弹幕参数在这里调)
if switch==1:
os.makedirs(f"{_path}/danmuAss", exist_ok=True)
danmaku2ass.Danmaku2ASS(f"{all_danma[i]}","Bilibili",f"{_path}/danmuAss/{title2}.ass",1080,720,\
reserve_blank=480,font_size=23.0, text_opacity=0.6, duration_marquee=12.0, duration_still=6.0)
#备用代码1#cmd2 = f'python {source2_path} {all_danma[i]} -o {_path}/danmuAss/{title2}.ass -s 1080x720 -a 0.5 -fs 22 -dm 12 -ds 6 -p 480'
#备用代码2#os.popen(cmd2)
#检测视频文件是否成功合并并输出
if f"{title2}.mp4" in os.listdir(_path):
print("*" * 15, f"已完成{i+1-failed}个文件", "*" * 15,"\n")
else:
print("*" * 15, "合并失败或终止", "*" * 15,"\n")
failed += 1
6.打印完成提示,并于30s后自动关闭窗口
print("当前任务已完成!")
time.sleep(30)
os._exit(0)
代码在Windows和Unix运行没有问题,其他操作系统目前还不清楚,水平高的可以针对其他系统自己改写
将程序打包成exe,没有运行环境要求
打包用的pyinstaller,很方便(利用windows powershell下的chocolatey安装,具体使用方法自行百度)
下面是我打包好可以直接使用的软件:
★★★阿里云盘下载链接★★★
▪操作图示(我是直接把程序文件夹与视频缓存文件夹放在一个目录下,这样程序会自动添加待合并视频; 你也可以选择手动输入扫描路径):
▪软件展示(还没有添加用户图形页面,所以软件运行页面就是一个shell:
第一次打包程序发文章,如果上面有错误或者程序不能正常运行请及时通过软件说明里的qq联系我或直接在这里留言。另外软件我也会定期更新,敬请关注。
更新于2022/3/17