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。

关键部分代码:

python 复制代码
command = [
            "ffmpeg",
            "-i", video_m4s,  # 输入视频文件
            "-i", audio_m4s,  # 输入音频文件
            '-c:v', 'copy',  # 不重新编码视频
            '-c:a', 'copy',  # 不重新编码音频
            "-y",  # 覆盖已存在的文件
            output_mp4  # 输出文件
        ]

        # 使用 subprocess.run 执行命令
        result = subprocess.run(command)

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

python 复制代码
#!/usr/bin/python3
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
import subprocess
import os
import json
import ffmpeg


def 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 False
    try:
        # 输入视频和音频
        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 True
        else:
            print(f"合并失败, 视频文件:{video_m4s}, 音频文件:{audio_m4s}")
            print(f"错误信息: {result.stderr}")
            return False
    except ffmpeg.Error as e:
        print(f"合并失败,音频文件:{audio_m4s},视频文件:{video_m4s}")
        return False


def 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()

具体效果如下:


相关推荐
早睡身体好~13 小时前
【lubancat】鲁班猫4实现开机后自动播放视频
音视频·linux开发
小幽余生不加糖13 小时前
电路方案分析(二十二)适用于音频应用的25-50W反激电源方案
人工智能·笔记·学习·音视频
胡耀超14 小时前
DataOceanAI Dolphin(ffmpeg音频转化教程) 多语言(中国方言)语音识别系统部署与应用指南
python·深度学习·ffmpeg·音视频·语音识别·多模态·asr
2301_7930868716 小时前
Redis 04 Reactor
数据库·redis·缓存
shix .19 小时前
bilibili视频总结
音视频
1892280486120 小时前
NY243NY253美光固态闪存NY257NY260
大数据·网络·人工智能·缓存
青鱼入云21 小时前
redis怎么做rehash的
redis·缓存
FFF-X21 小时前
Vue3 路由缓存实战:从基础到进阶的完整指南
vue.js·spring boot·缓存
lovep11 天前
音频-文本对比学习:LARGE-SCALE CONTRASTIVE LANGUAGE-AUDIO PRETRAINING论文翻译和理解
音视频·glap·音频理解·音频对比学习·laion-audio·音频检索
夜影风2 天前
Nginx反向代理与缓存实现
运维·nginx·缓存