众所周知,国内的小破站(Bilibili)汇聚了众多的技术教程,甚至还能在上面看到收费的教程。但是有些比较有价值的视频往往在一段时间后会被消失,这其中可能涉及版权问题等原因。所以,对自己需要的视频教程进行及时的离线保存是很有必要的。
当然,小破站的手机客户端有缓存视频的功能。而移动设备的屏幕尺寸往往都是较小的,对于学习视频教程来说比较不合适。所以,我决定把手机上的视频缓存移动到电脑上观看。(至于我为什么不直接用脚本下载小破站的视频以及合并处理,因为我之前已经在手机上缓存好了,而现在所处的网络环境并不理想,下载速度慢,所以就没必要这样折腾了)然而这些文件中,一般一个视频都是分段保存,或者音视频文件独立保存的。于是也就有了接下来的操作。
把整个缓存文件夹保存到电脑,这个文件夹一般是以小破站的某个a v号命名的很容易找到,一般在手机上的路径是/Android/data/tv.danmaku.bili/download
在网上对相关资料一顿乱搜后有了思路,使用python写个脚本进行文件操作,配合FFmpeg这个开源的音视频操作工具对音视频文件进行合并操作即可。
这是FFmpeg的百度百科
上代码:
import shutil
import os
import json
from natsort import natsorted
'''
请确认本脚本以及ffmpeg程序在以av号命名的文件夹下运行
'''
superPath = os.getcwd() # 获取当前路径
partDirs = [] # 保存每P视频所在的文件夹路径
paths = os.listdir(superPath) # 获取当前路径下所有的文件(包括文件夹)名称
# 获取每P视频所在的文件夹路径
for p in paths:
if os.path.isdir(p):
partDirs.append(os.path.join(superPath, p))
# 主循环,合并处理每P视频
for eatchPath in partDirs:
# eatchPath = os.path.join(superPath, i) # 保存每P视频所在的文件夹路径
videoJsonDir = eatchPath+'\\'+'entry.json' # 获取保存单P视频信息的json文件的路径
# 保存视频的标题
videoTitle = ''
with open(videoJsonDir, 'r', encoding='utf-8') as load_f:
load_dict = json.load(load_f)
videoTitle += load_dict['page_data']['part'] # 从json文件中获取单P视频标题
videoDir = ''
for root, dir, files in os.walk(eatchPath):
if dir:
videoDir = dir[0]
break
videoDir = eatchPath+'\\'+videoDir # 获取最终存放单P视频缓存文件的文件夹路径
# 构造命令行指令,用来操作ffmpeg
command1Start = 'ffmpeg.exe '
command1End = '-c copy \"{}\{}.mp4\"'.format(superPath, videoTitle)
command2Start = 'ffmpeg.exe -f concat -safe 0 '
command2End = '-c copy \"{}\{}.flv\"'.format(superPath, videoTitle)
# 遍历存放单P视频缓存文件的文件夹, 获取具体的缓存文件名称
for root, dir, files in os.walk(videoDir):
files = natsorted(files) # 对获取到的缓存文件按照文件名进行自然排序
videoFormat = 0
with open('./fs.txt', 'w+', encoding='utf-8') as textFile:
pass
# 遍历经排序后的列表
for file in files:
# 判断缓存文件夹下端缓存文件类型,一般为.blv和.m4s为后缀的缓存文件,实际上就是flv文件和mp4文件
if os.path.splitext(file)[1] == '.m4s':
videoFormat = 1
filePath = os.path.join(root, file)
command1Start += '-i {} '.format(filePath)
if os.path.splitext(file)[1] == '.blv':
videoFormat = 2
filePath = os.path.join(root, file)
with open('./fs.txt', 'r+', encoding='utf-8') as textFile:
textFile.seek(0, 2)
textFile.write('file \'{}\''.format(filePath)+'\n')
# 构造最终要执行的命令行指令
finalCommand = ''
if videoFormat == 1:
finalCommand = command1Start + command1End
if videoFormat == 2:
command2Start += '-i fs.txt '
finalCommand = command2Start + command2End
# 执行视频合并操作
print('执行{}'.format(finalCommand))
os.system(finalCommand)
# 合并后删除原缓存文件
shutil.rmtree(eatchPath, ignore_errors=True)
# print('{}已删除'.format(eatchPath))
注意: 脚本文件和FFmpeg必须放在以av号命名的文件夹下,否则无法运行