【C# | Unity】B站Android客户端缓存视频提取工具

【C# | Unity】B站Android客户端缓存视频提取工具

这篇文章使用了笨方法,后来在网上看到了 you-get 这款工具,可以在命令行通过URL直接下载视频,而且支持批量下载。

B站只允许使用手机缓存视频,但是缓存下来的视频分散在不同的文件夹里,而且每个视频的名称都是 0.blv ,不点开看的话根本不知道是哪个视频,所以写了一个辅助提取B站Android客户端缓存视频的小工具。
因为恰好开着Unity,所以就直接在Unity里面写了下面的这段代码,因而用了一些Unity的专用类,如果要在其他地方使用下面的代码,需要把文中提到的几个特殊类替换掉。

使用方法

这个工具是用来处理视频量比较大的视频合集的,如果是单个视频,直接手动复制视频然后重命名就好了。
用法很简单,在手机上把视频缓存好以后,手机连接电脑,打开视频的缓存文件夹,把缓存合集拖到复制到电脑上,然后再Unity的 Inspector 面板上填写视频位置信息,点击 Extract 即可完成提取。如果不想在Unity中使用,那么需要把下面提到的几个特殊类替换掉,然后调用 ExtractVideoFile() 方法提取视频。

注意:代码里处理视频用的是剪切方法,如果不把缓存的视频从手机里复制出来就直接运行代码,会把缓存的视频剪切到其他位置。如果不想剪切,可以把代码中的 File.Move() 方法改成 File.Copy() 方法。

参数示例
参数示例

备注:有些视频集里面的单集视频会被分成多个视频文件(例如:0.blv,1.blv,2.blv等),这里没写处理方法。如果遇到这种情况,可以进行多次提取,每次提取时修改一下 源文件名称参数VideoName输出文件扩展名参数OutputExt (例如: VideoName:"1.blv"OutputExt:"-1.flv" )。多次提取时,已经提取过的文件会报 找不到视频文件 的错误,可以忽略。

B站Android客户端的一些相关信息

  • 缓存视频的存放文件夹是 手机内部存储\Android\data\tv.danmaku.bili\download\
  • 具体的视频路径是 手机内部存储\Android\data\tv.danmaku.bili\download\<avid>\<index>\<lua.xxx.xxx.xxx>\<x.blv>
  • 存储每个视频的信息的文件是 手机内部存储\Android\data\tv.danmaku.bili\download\<avid>\<index>\entry.json
  • 上述说明中的 avidindexlua.xxx.xxx.xxxx.blv 需要根据下载的文件的具体名称进行修改,代码中的 domain 参数就是 lua.xxx.xxx.xxx 部分。

用到的特殊类及其方法

  • MonoBehaviour:Unity独有的类,仅起到方便调用的作用,没别的用处。
  • Debug.Log():Unity独有的日志输出方法,在控制台中可以使用Console.WriteLite()替代。
  • JsonUtility.FromJson():Unity独有的Json解析方法,可以使用其他第三方Json解析工具替代。

源代码

using System.IO;
using UnityEngine;

public class BilibiliTool : MonoBehaviour
{
    /** 说明
     * B站Android客户端缓存视频的存放文件夹是“手机内部存储\Android\data\tv.danmaku.bili\download\”;
     * 具体的视频路径是“手机内部存储\Android\data\tv.danmaku.bili\download\<avid>\<index>\<lua.xxx.xxx.xxx>\<x.blv>”;
     * 存储每个视频的信息的文件是“手机内部存储\Android\data\tv.danmaku.bili\download\<avid>\<index>\entry.json”;
     * 上述说明中的<avid>、<index>、<lua.xxx.xxx.xxx>、<x.blv>需要根据下载的文件的具体名称进行修改,代码中的“domain”参数就是“lua.xxx.xxx.xxx”部分。
     */

    // 默认值仅作示例,每个视频集的avid和视频父文件夹名称都不一样,要进行相应的修改
    public string inputFolder = @"E:\资料\视频教程\46312220\";
    public string outputFolder = @"E:\资料\视频教程\线性代数\";
    public string domain = "lua.flv720.bili2api.64";
    public int startNumber = 1;
    public int endNumber = 116;
    public string videoName = "0.blv";
    public string outputExt = ".flv";
    public string jsonName = "entry.json";

    [Header("点击勾选框执行提取")]
    public bool extract = false;

    private void OnValidate()
    {
        if (extract)
        {
            extract = false;
            ExtractVideoFile(inputFolder, outputFolder, domain, startNumber, endNumber, videoName, outputExt, jsonName);
        }
    }

    /// <summary>
    /// 提取视频文件。
    /// </summary>
    /// <param name="inputFolder">存放下载的原始视频的文件夹</param>
    /// <param name="outputFolder">提取视频的输出文件夹</param>
    /// <param name="domain">原始视频文件路径中格式为“lua.x.x.x”的文件夹的名称</param>
    /// <param name="startNumber">视频合集中视频的起始编号</param>
    /// <param name="endNumber">视频合集中视频的结束编号</param>
    /// <param name="videoName">原始视频名称(默认为0.blv)</param>
    /// <param name="outputExt">输出视频文件的扩展名(默认为flv)</param>
    /// <param name="jsonName">存储视频信息的Json文件的名称(默认为entry.json)</param>
    public void ExtractVideoFile(string inputFolder, string outputFolder, string domain, int startNumber, int endNumber, string videoName = "0.blv", string outputExt = ".flv", string jsonName = "entry.json")
    {
        // 检查输入路径
        if (!Directory.Exists(inputFolder))
        {
            Debug.LogError("文件路径<" + inputFolder + ">不存在。", this);
            return;
        }

        // 检查输出路径
        if (!Directory.Exists(outputFolder))
        {
            Directory.CreateDirectory(outputFolder);
        }

        // 移动和重命名
        for (int i = startNumber; i < endNumber + 1; i++)
        {
            // 将原始视频移动到指定位置
            string sourceFilePath = string.Format(@"{0}\{1}\{2}\{3}", inputFolder, i, domain, videoName);
            if (!File.Exists(sourceFilePath))
            {
                Debug.LogError("找不到视频文件<" + sourceFilePath + ">。", this);
                continue;
            }


            // 可能读不到文件或者格式无法正常解析
            string jsonPath = string.Format(@"{0}\{1}\{2}", inputFolder, i, jsonName);
            try
            {
                string json = File.ReadAllText(jsonPath);
                Bilibili bili = JsonUtility.FromJson<Bilibili>(json);

                // 重命名视频
                string name = bili.page_data.part;
                string outputFilePath = string.Format(@"{0}\{1}{2}", outputFolder, name, outputExt);
                File.Move(sourceFilePath, outputFilePath);
            }
            catch
            {
                Debug.LogError("无法解析文件<" + jsonPath + ">。", this);
                continue;
            }
        }

        Debug.Log("视频提取完成。", this);
    }
}

/// <summary>
/// 手机内部存储\Android\data\tv.danmaku.bili\download\avid\index\entry.json的格式。
/// </summary>
[System.Serializable]
public class Bilibili
{
    public bool is_completed;
    public int total_bytes;
    public int downloaded_bytes;
    public string title;
    public string type_tag;
    public string cover;
    public int prefered_video_quality;
    public int guessed_total_bytes;
    public int total_time_milli;
    public int danmaku_count;
    public int time_update_stamp;
    public int time_create_stamp;
    public int avid;
    public int spid;
    public int seasion_id;
    public PageData page_data;

    [System.Serializable]
    public class PageData
    {
        public int cid;
        public int page;
        public string from;
        public string part;
        public string vid;
        public bool has_alias;
        public string weblink;
        public int tid;
    }
}
发布了76 篇原创文章 · 获赞 131 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qq_21397217/article/details/88661226