当前位置: 首页 > article >正文

B站缓存视频数据m4s转mp4

B站缓存视频数据m4s转mp4

  • 结构分析

结构分析

在没有改变数据存储目录的情况下,b站默认数据保存目录为:
`Android->data->tv.danmaku.bili->download`

在这里插入图片描述
每个文件夹代表一个集合的视频,比如,我下载的”java从入门到精通“,那么就会保存到一个目录里面:
在这里插入图片描述
每个以c_开头的都是一个小章节。
在这里插入图片描述
每个小章节包含entry.json(视频标题及章节名称等信息),danmaku.xml(弹幕),64或80等(视频文件及音频文件等)
在这里插入图片描述
将audio.m4s以及video.m4s合成后就是一个完整的视频。本地得安装ffmpeg或者使用python-ffmpeg。
关键部分代码:

command = ["ffmpeg","-i", video_m4s,  # 输入视频文件"-i", audio_m4s,  # 输入音频文件'-c:v', 'copy',  # 不重新编码视频'-c:a', 'copy',  # 不重新编码音频"-y",  # 覆盖已存在的文件output_mp4  # 输出文件]# 使用 subprocess.run 执行命令result = subprocess.run(command)

将整个标题的视频转换出来。

#!/usr/bin/python3
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
import subprocess
import os
import json
import ffmpegdef select_source():# 选择视频源目录dir_path = filedialog.askdirectory(title="选择视频源目录")if dir_path:source_entry.delete(0, END)source_entry.insert(0, dir_path)def select_target():# 选择保存目录dir_path = filedialog.askdirectory(title="选择视频保存目录")if dir_path:target_entry.delete(0, END)target_entry.insert(0, dir_path)def convert_with_ffmpeg(video_m4s, audio_m4s, output_mp4):if os.path.getsize(video_m4s) < 0 or os.path.getsize(audio_m4s) <= 0:print("非法的音视频文件,{audio_m4s},视频文件:{video_m4s}")return Falsetry:# 输入视频和音频video = ffmpeg.input(video_m4s)audio = ffmpeg.input(audio_m4s)# 构造 FFmpeg 命令command = ["ffmpeg","-i", video_m4s,  # 输入视频文件"-i", audio_m4s,  # 输入音频文件'-c:v', 'copy',  # 不重新编码视频'-c:a', 'copy',  # 不重新编码音频"-y",  # 覆盖已存在的文件output_mp4  # 输出文件]# 使用 subprocess.run 执行命令result = subprocess.run(command)# 检查命令是否成功执行if result.returncode == 0:print(f"{output_mp4} -> 合并成功!")return Trueelse:print(f"合并失败, 视频文件:{video_m4s}, 音频文件:{audio_m4s}")print(f"错误信息: {result.stderr}")return Falseexcept ffmpeg.Error as e:print(f"合并失败,音频文件:{audio_m4s},视频文件:{video_m4s}")return Falsedef batch_convert_vedio(source_path, target_path):for dir in os.listdir(source_path):dir_path = os.path.join(source_path, dir)entry_file = os.path.join(dir_path, "entry.json")data_dir = os.listdir(dir_path).pop(0)audio_path = os.path.join(dir_path, data_dir, "audio.m4s")vedio_path = os.path.join(dir_path, data_dir, "video.m4s")with open(entry_file, 'r', encoding='utf-8') as f:entry_sjon = f.read()json_data = json.loads(entry_sjon)part_content = json_data.get("page_data", {}).get("part")title = json_data.get("title")if not os.path.exists(os.path.join(target_path, f'{title}')):os.makedirs(os.path.join(target_path, f'{title}'))target_vedio_path = os.path.join(target_path, f'{title}/{part_content}.mp4')convert_with_ffmpeg(vedio_path, audio_path, target_vedio_path)print(target_vedio_path)def convert_video():source_path = source_entry.get()target_path = target_entry.get()if not source_path or not target_path:messagebox.showerror("错误", "请选择源目录和目标目录!")else:batch_convert_vedio(source_path, target_path)messagebox.showinfo("成功", f"视频将从 {source_path} 转换保存到 {target_path}")root = Tk()
root.title("bili视频转换工具")# 设置窗口大小并居中
window_width = 500  # 稍微加宽窗口
window_height = 200
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x = (screen_width - window_width) // 2
y = (screen_height - window_height) // 2
root.geometry(f"{window_width}x{window_height}+{x}+{y}")# 配置网格布局权重
for i in range(5):root.grid_columnconfigure(i, weight=1)
for i in range(4):root.grid_rowconfigure(i, weight=1)# 视频源目录选择
source_label = Label(root, text="视频源目录:")
source_label.grid(row=0, column=0, sticky="e", padx=5, pady=5)source_entry = Entry(root)
source_entry.grid(row=0, column=1, columnspan=3, sticky="ew", padx=5, pady=5)source_button = Button(root, text="浏览...", command=select_source)
source_button.grid(row=0, column=4, sticky="ew", padx=5, pady=5)# 视频保存目录选择
target_label = Label(root, text="视频保存目录:")
target_label.grid(row=1, column=0, sticky="e", padx=5, pady=5)target_entry = Entry(root)
target_entry.grid(row=1, column=1, columnspan=3, sticky="ew", padx=5, pady=5)target_button = Button(root, text="浏览...", command=select_target)
target_button.grid(row=1, column=4, sticky="ew", padx=5, pady=5)# 转换按钮
button_convert = Button(root, text="立即转换", command=convert_video)
button_convert.grid(row=2, column=1, columnspan=3, sticky="ew", padx=50, pady=20)# 进入消息循环
root.mainloop()

具体效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

http://www.lryc.cn/news/2401579.html

相关文章:

  • DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)
  • 【机器学习】主成分分析 (PCA)
  • 二叉树-104.二叉树的最大深度-力扣(LeetCode)
  • 物料转运人形机器人适合应用于那些行业?解锁千行百业的智慧物流革命
  • k8s开发webhook使用certmanager生成证书
  • 时序预测模型测试总结
  • 第四十五天打卡
  • springboot mysql/mariadb迁移成oceanbase
  • npm install 报错:npm error: ...node_modules\deasync npm error command failed
  • Filebeat收集nginx日志到elasticsearch,最终在kibana做展示(二)
  • halcon c# 自带examples报错 Matching
  • 服务器重启后配置丢失怎么办?
  • Postgresql常用函数操作
  • 用 NGINX 搭建高效 IMAP 代理`ngx_mail_imap_module`
  • 湖北理元理律所债务优化实践:法律技术与人文关怀的双轨服务
  • Springboot——整合websocket并根据type区别处理
  • Qiskit:量子计算模拟器
  • 龙虎榜——20250605
  • PDF 转 HTML5 —— HTML5 填充图形不支持 Even-Odd 奇偶规则?(第二部分)
  • 大数据离线同步工具 DataX 深度实践与 DataX Web 可视化指南
  • 记一个判决书查询API接口的开发文档
  • 残月个人拟态主页
  • 热门消息中间件汇总
  • AiPy实战:10分钟用AI造了个音乐游戏!
  • Python Rio 【图像处理】库简介
  • 贪心算法应用:分数背包问题详解
  • PHP舆情监控分析系统(9个平台)
  • 金孚媒重磅推出德国顶级媒体原生广告整合服务,覆盖12家主流媒体
  • Mnist手写数字
  • 《一生一芯》数字实验三:加法器与ALU