安卓手机Bilibili缓存视频批量转换为MP4的方法研究

        

        不知从什么时候开始,B站缓存的视频如果后来下架或者限制大会员观看,那么本地也无法观看了,点了就显示内容无效或者需要大会员,但视频文件还在手机中存放着,找出视频文件做成普通的mp4视频还是比较有用的。

        用到的工具:Excel(仅用来编写和运行vba),Mp4box

        目前的安卓手机上B站缓存文件的保存目录为:Android\data\tv.danmaku.bili\download

        以我的红米K20Pro为例,连接电脑后的文件目录就是“计算机\Redmi K20 Pro Premium Edition\内部存储设备\Android\data\tv.danmaku.bili\download”

        这些目录我称之为“资源目录”,每一个目录都代表一个资源,里边有一个或多个视频,我选取了其中几个资源目录复制到电脑上来处理,存放在一个新建的名为"bilibili"的目录。

        打开一个资源的任意一个子目录,这个子目录我称之为“json目录”,json目录包含一个子目录和两个文件:danmaku.xml和entry.json,子目录的名字有的是“16”,有的是“lua.flv360.bili2api.16”这样的,这个子目录我称之为“视频目录”,所以资源结构可以这样表示:

        entry.json中包含了我想要找的视频信息,都是以json格式保存的,我筛选出了其中几个属性:title, index, index_title, part。例如1415480\26\entry.json里就有

"title":"【经典】周杰伦MV 【185P】"

"part":"半岛铁盒【3rd 八度空间】"

 s_12548\199612\entry.json有

"title":"让子弹飞"

"index":"普通话"

 s_29331\299818\entry.json有

 "title":"百家讲坛之易中天品三国"

"index":"1"

"index_title":"大江东去"

         可以看出title属性是整个资源的名字,index是资源中某个视频的编号,part,index_title是某个视频的名字。

        接下来看视频目录,视频目录有两种,可能是不同时期B站对缓存视频的保存方式有所改变导致的,第一种是这样的:

        有一个或多个blv文件,blv文件可以在视频播放器直接播放,但比较大的视频会拆分成为多个 blv,所以对这种视频目录的处理方式应该是连接成为一个视频。       

         第二种视频目录是这样的

        显然这种保存方式是用m4s文件分别保存了视频和音频,处理的时候就要把它们组合起来。

        处理视频用到的工具是mp4box,这个工具属于开源项目GPAC项目,GPAC的官网是GPAC | Multimedia Open Source Project,进入网站在Downloads界面选择适合自己系统的版本下载安装,我用的windows版,安装之后就可以直接在命令行中输入命令使用。本文用到了两个命令:mp4box -cat和mp4box -add

        首先看第一种视频文件,即多个blv连接起来的方法:

mp4box -cat 0.blv -cat 1.blv -cat 2.blv -cat 3.blv -cat 4.blv -cat 5.blv output.mp4

        这样就可以把这0.blv到5.blv这6个文件连接成output.mp4,mp4box的帮助信息显示可以用mp4box -cat 0.blv+1.blv output.mp4这样把各个文件加起来的形式连接的,但我尝试过会出错,不知原因,所以暂且每一个都用-cat写上。

        对于第二种视频文件:

mp4box -add audio.m4s+video.m4s output.mp4

         这样就把 audio.m4s和video.m4s组合成了output.mp4

        视频数量较少的时候直接用命令就可以了。而对于缓存了数十个资源,有些资源有数十个甚至上百个视频的情况,需求就是批量提取视频信息并处理视频文件。这需要遍历所有子目录并从每一个entry.json文件中提取有用的信息,我利用自己有限掌握的技能,想到的办法是这样的:

        第一步,用vba遍历目录,读取entry.json文件,将提取到的信息组合成mp4box命令写到bat脚本文件中。

        第二部,运行这个bat脚本文件。

        我的想法是在上一级目录新建一个Output目录,在这个目录下每一个资源新建一个以title为名称的资源目录,每一个资源目录存放这个资源的所有视频,脚本在bilibili这个目录下运行,所以生成的脚本应该是类似这样的:

mp4box -cat s_2033\43855\lua.flv360.bb2api.16\0.blv -cat s_2033\43855\lua.flv360.bb2api.16\1.blv (......) ..\Output\越狱兔 第1季\越狱兔 第1季-1-第一季.mp4

        或者

 mp4box -add s_12548\199612\16\audio.m4s+s_12548\199612\16\video.m4s ..\Output\让子弹飞\让子弹飞-普通话.mp4

         为了这个目的新建一个带宏的excel文件放到bilibili目录下,写代码前还需引用

        Microsoft Scripting Runtime

        Microsoft Script Control

        Microsoft ActiveX Data Objects x.x Library

        vba代码如下

'从json文件中找到attr对应的值,参数json表示提取的json文件,attr是属性名字例如"title"
'如果找不到则返回空字符串
Function getJsonString(json As String, attr As String) As String
    Dim valStart As Long, valLen As Long
    valStart = InStr(1, json, """" & attr & """", vbTextCompare)
    getJsonString = ""
    If valStart > 0 Then
        valStart = valStart + Len(attr) + 4
        valLen = InStr(valStart, json, """", vbTextCompare) - valStart
        getJsonString = Mid(json, valStart, valLen)
    End If
End Function

'这个函数把不能用于文件名的符号替换成"-"以免名称不合法造成创建文件失败
Function replaceIllegalChars(str As String) As String
    str = Replace(str, " ", "", , , vbTextCompare)
    str = Replace(str, "<", "-", , , vbTextCompare)
    str = Replace(str, ">", "-", , , vbTextCompare)
    str = Replace(str, ":", "-", , , vbTextCompare)
    str = Replace(str, """", "-", , , vbTextCompare)
    str = Replace(str, "/", "-", , , vbTextCompare)
    str = Replace(str, "\", "-", , , vbTextCompare)
    str = Replace(str, "|", "-", , , vbTextCompare)
    str = Replace(str, "?", "-", , , vbTextCompare)
    str = Replace(str, "*", "-", , , vbTextCompare)
    '空字符串导致的连续的"--"缩减成一个
    Do While InStr(1, str, "--", vbTextCompare) > 0
        str = Replace(str, "--", "-", , , vbTextCompare)
    Loop
    '去掉末尾的"-"
    If StrComp("-", Right(str, 1), vbTextCompare) = 0 Then
        str = Left(str, Len(str) - 1)
    End If
    replaceIllegalChars = str
End Function

'生成bat文件output.bat
Sub createBat()
    Dim blfolder As Folder
    Dim fs As FileSystemObject
    Dim resourcefolder As Folder, jsonfolder As Folder, videofolder As Folder
    Dim ts As ADODB.Stream, infots As TextStream
    Dim jsonstr As String
    Dim titlestart As Long, titlelen As Long
    Dim indexstart As Long, indexlen As Long
    Dim partstart As Long, partlen As Long
    Dim titlestr As String, destfilename As String
    Dim i As Long
    
    Set ts = New ADODB.Stream 'ADODB.Stream用来读取entry.json
    ts.Open
    ts.Charset = "utf-8" 'entry.json使用的编码是utf-8
    Set fs = New FileSystemObject
    Set blfolder = fs.GetFolder(ThisWorkbook.Path)
    Set infots = fs.CreateTextFile(blfolder.Path & "\output.bat", True, False) 'infots as TextStream用来向output.bat写入脚本
    For Each resourcefolder In blfolder.SubFolders 'resourcefolder遍历所有资源目录
        For Each jsonfolder In resourcefolder.SubFolders 'jsonfolder遍历所有json目录
            ts.LoadFromFile (jsonfolder.Path & "\entry.json")
            jsonstr = ts.ReadText(adReadAll)
            titlestr = getJsonString(jsonstr, "title")
            destfilename = titlestr & "-" & getJsonString(jsonstr, "index") & "-" _
                & getJsonString(jsonstr, "index_title") & "-" _
                & getJsonString(jsonstr, "part")
            titlestr = replaceIllegalChars(titlestr)
            destfilename = blfolder.ParentFolder.Path & "\Output\" & titlestr & "\" & replaceIllegalChars(destfilename) & ".mp4"
            For Each videofolder In jsonfolder.SubFolders 'videofolder遍历所有视频目录,其实只有一个
                If fs.FileExists(videofolder.Path & "\audio.m4s") Then
                    infots.Write ("mp4box -add """ & videofolder.Path & "\audio.m4s""+""" _
                        & videofolder.Path & "\video.m4s"" """ & destfilename & """" & vbCrLf)
                ElseIf fs.FileExists(videofolder.Path & "\0.blv") Then
                    infots.Write ("mp4box")
                    i = 0
                    Do While fs.FileExists(videofolder.Path & "\" & i & ".blv")
                        infots.Write (" -cat """ & videofolder.Path & "\" & i & ".blv""")
                        i = i + 1
                    Loop
                    infots.Write (" """ & destfilename & """" & vbCrLf)
                End If
                Exit For
            Next videofolder
        Next jsonfolder
    Next resourcefolder
    infots.Write ("pause" & vbCrLf)
    ts.Close
    infots.Close
    MsgBox "DONE."
End Sub

        运行代码以后自动写出了output.bat脚本

        编辑脚本可以看到具体内容

         文件较多,运行脚本需要一段时间,结束后打开Output目录可见

 

         播放也没问题,一切顺利。

        至于周杰伦的MV分了三个目录,应该是由于作者是分批上传导致entry.json中的title有变化,这种例外手动合并就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值