利用Python操控ffmpeg批量转换哔哩哔哩m4s缓存

相信不少人都知道B站吧,B站里面有大量的视频资源,像我就从那里面学到了不少东西(也看了不少番)。有时候我们想要在手机app上下载上面的视频,但是下载下来只能以缓存的形式在软件里播放。在大多数时候可能也没什么麻烦,但是有时想要在其他设备上看这些视频,就无法简单的把文件复制过去了。于是有人就研究出了把B站的缓存转换成MP4格式的方法,而这个脚本可以利用这种方法批量转换B站缓存,更为方便快捷,更符合实际的需要。
一、B站缓存机制
要想操作B站缓存,首先要知道它的缓存方式。手机bilibil的视频缓存目录为

手机存储/Android/data/tv.danmaku.bili/download

这个文件夹里有一个或多个子文件夹(名字都是数字),每一个就是一组视频,每一个子文件夹中可能有一个或多个文件夹(名字都是c_+数字),这取决于该视频是否有多集。这一级的文件夹每个代表一个视频,里面包含缓存文件与信息文件,也有一些文件夹是缓存过但是被删掉的视频,这样的文件夹就不含缓存文件,但是还会留下信息文件。
信息文件主要有两个:用于存储弹幕信息的danmaku.xml(danmaku即为日语的弹幕),还有保存视频信息的entry.json
视频缓存文件储存在一个两位数名字(16,32,64等等)的文件夹中,视频被分为视频文件video.m4s和音频文件audio.m4s两部分,该文件夹里还有一个index.json,应该是用来验证缓存文件是否有错或被修改的,而存储视频的文件夹名字(那个两位数)在entry.json中一个名为type_tag的项中保存。
直观的讲,文件结构如图(希望这样是等宽字体):

 /download /123456789 /c_123456789 /entry.json
___________________________________/danmaku.xml
___________________________________/16 /vedio.m4s
_______________________________________/audio.m4s
_______________________________________/index.json
______________________/c_987654321(同上)
___________/987654321(同上)

二、如何合并缓存文件为MP4格式
合并视频就需要用到ffmpeg了。ffmpeg是个用来处理音视频的命令行软件,功能还是很强大的。
三、批量处理节省工作量
利用python实现批量处理,使操作简单化,代码如下(解释在代码的注释中):

"""使用方法:将手机的视频缓存(/download/里面的内容)复制到一个单独的文件夹,
然后填写缓存目录、输出目录还有ffmpeg.exe所在位置,之后运行这个脚本,就能在输出目录中得到所有的缓存视频啦
"""

import os
import json
import random
import re

# 请填写:
cache_directory = 'D:\\temp1'  # 缓存文件所在目录,相当于之前的/download文件夹

# 请填写:
output_directory = 'D:\\temp2'  # 输出目录,在此输出多个按原来的组分类的视频文件夹

# 请填写:
ffmpeg_path = 'D:\\Program Files\\ffmpeg-2021-08-04-git-3b298640e1-full_build\\bin'  # ffmpeg.exe所在位置

if (os.path.exists(cache_directory)  # 先对路径进行检测,如果有错就结束运行
        and os.path.exists(output_directory)
        and os.path.exists(ffmpeg_path)):
    os.chdir(ffmpeg_path)  # 在ffmpeg所在目录下运行,以执行ffmpeg命令
    for part in os.listdir(cache_directory):  # 每一组视频
        episodes = os.listdir(cache_directory + '\\' + part)  # 一组里面的每个视频

        # 先读取一个entry.json,由此获取这组视频的名字还有分辨率
        try:  # 提高容错率,跳过空文件夹
            with open(f'{cache_directory}\\{part}\\{episodes[0]}\\entry.json', mode='rt', encoding='utf8') as fp:
                info = json.load(fp)
                part_name = info['title']
        except IndexError:
            continue
        # 没名字的解决办法
        if not part_name:
            part_name = 'NoName' + str(random.random())[2:10]
        # 去除非法字符
        part_name = ''.join(re.findall(r'[^*"/:?\\|<>]', part_name, re.S))  # 这组视频的名字
        # 判定这个文件夹里是否有视频,因为很多被删掉的视频都只剩一个文件
        if len(os.listdir(f'{cache_directory}\\{part}\\{episodes[0]}')) <= 1 and len(episodes) <= 1:
            print(part_name, '可能已经被删除了')
            continue
        # 这组视频的输出位置
        output_part_directory = f'{output_directory}\\{part_name}'  
        # 用视频组的名字创建输出文件夹
        if not os.path.exists(output_part_directory):
            os.mkdir(output_part_directory)
        else:
            print(output_part_directory, '已存在')
        for episode in episodes:  # 每集视频
            file_directory = f'{cache_directory}\\{part}\\{episode}\\'  # 每一集的文件夹
            # 读取json,获得该视频的信息
            with open(file_directory + 'entry.json', encoding='utf8')as fp:
                info = json.load(fp)
            title = info['page_data']['part']
            type_tag = info['type_tag']
            video_name = file_directory + f'{type_tag!s}\\video.m4s'  # 视频文件路径
            audio_name = file_directory + f'{type_tag!s}\\audio.m4s'  # 音频文件路径
            if os.path.exists(video_name) and os.path.exists(audio_name):  # 判定缓存是否被删除
                # 读取这一集的名字
                if not title:
                    title = 'NoName' + str(random.random())[2:11]
                title = ''.join(re.findall(r'[^*"/:?\\|<>]', title, re.S))
                # 这一集的输出位置
                output_name = output_part_directory + '\\' + title + '.mp4'
                print('执行命令:',
                      f'ffmpeg -i {video_name} -i {audio_name} -c:v copy -strict experimental {output_name}')
                # 最后一步,执行命令
                os.system(
                    f'ffmpeg -i "{video_name}" -i "{audio_name}" -c:v copy -strict experimental "{output_name}"')
                # 如果把os.system换成os.popen,则会开很多进程,速度虽会有所加快,但是会造成电脑超级卡顿(CPU占用100%),
                # 而且想要结束只能用任务管理器结束ffmpeg.exe进程,所以不推荐使用
            else:
                print(file_directory, '里的视频可能已经被删除')

        # 如果没有文件,则说明缓存被删除了,这个目录是没用的目录
        if len(os.listdir(output_part_directory)) == 0:
            os.rmdir(output_part_directory)
else:
    print('填写的路径不正确')

附录:
在网上看到还有一种格式为.blv的缓存,对于这种缓存可以直接把后缀改成.flv
但是因为我还没有遇到就不好多说了

(于2021.9.6修改,之前没考虑到分辨率不同,文件夹名字不同的问题)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容