public async Task <BBDownVInfo> FetchAsync(string id)
        {
            string api  = $"https://api.bilibili.com/x/web-interface/view?aid={id}";
            string json = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var    data    = infoJson.RootElement.GetProperty("data");
            string title   = data.GetProperty("title").ToString();
            string desc    = data.GetProperty("desc").ToString();
            string pic     = data.GetProperty("pic").ToString();
            string pubTime = data.GetProperty("pubdate").ToString();

            pubTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString();
            bool bangumi = false;

            var         pages     = data.GetProperty("pages").EnumerateArray().ToList();
            List <Page> pagesInfo = new List <Page>();

            foreach (var page in pages)
            {
                Page p = new Page(page.GetProperty("page").GetInt32(),
                                  id,
                                  page.GetProperty("cid").ToString(),
                                  "", //epid
                                  page.GetProperty("part").ToString().Trim(),
                                  page.GetProperty("duration").GetInt32(),
                                  page.GetProperty("dimension").GetProperty("width").ToString() + "x" + page.GetProperty("dimension").GetProperty("height").ToString());
                pagesInfo.Add(p);
            }

            try
            {
                if (data.GetProperty("redirect_url").ToString().Contains("bangumi"))
                {
                    bangumi = true;
                    string epId = Regex.Match(data.GetProperty("redirect_url").ToString(), "ep(\\d+)").Groups[1].Value;
                    //番剧内容通常不会有分P,如果有分P则不需要epId参数
                    if (pages.Count == 1)
                    {
                        pagesInfo.ForEach(p => p.epid = epId);
                    }
                }
            }
            catch { }

            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = pic;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = bangumi;

            return(info);
        }
Exemple #2
0
        public BBDownVInfo Fetch(string id)
        {
            id = id.Substring(3);
            string      index     = "";
            string      api       = $"https://api.bilibili.com/pgc/view/web/season?ep_id={id}";
            string      json      = GetWebSource(api);
            JObject     infoJson  = JObject.Parse(json);
            string      cover     = infoJson["result"]["cover"].ToString();
            string      title     = infoJson["result"]["title"].ToString();
            string      desc      = infoJson["result"]["evaluate"].ToString();
            string      pubTime   = infoJson["result"]["publish"]["pub_time"].ToString();
            JArray      pages     = JArray.Parse(infoJson["result"]["episodes"].ToString());
            List <Page> pagesInfo = new List <Page>();
            int         i         = 1;

            foreach (JObject page in pages)
            {
                string res = "";
                try
                {
                    res = page["dimension"]["width"].ToString() + "x" + page["dimension"]["height"].ToString();
                }
                catch (Exception) { }
                string _title = page["long_title"].ToString();
                if (string.IsNullOrEmpty(_title))
                {
                    _title = page["title"].ToString();
                }
                Page p = new Page(i++,
                                  page["aid"].ToString(),
                                  page["cid"].ToString(),
                                  page["id"].ToString(),
                                  GetValidFileName(_title),
                                  0, res);
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }

            var info = new BBDownVInfo();

            info.Title     = GetValidFileName(title).Trim();
            info.Desc      = GetValidFileName(desc).Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
        public BBDownVInfo Fetch(string id)
        {
            string  api      = $"https://api.bilibili.com/x/web-interface/view?aid={id}";
            string  json     = GetWebSource(api);
            JObject infoJson = JObject.Parse(json);
            string  title    = infoJson["data"]["title"].ToString();
            string  desc     = infoJson["data"]["desc"].ToString();
            string  pic      = infoJson["data"]["pic"].ToString();
            string  pubTime  = infoJson["data"]["pubdate"].ToString();

            pubTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString();
            bool bangumi = false;

            JArray      pages     = JArray.Parse(infoJson["data"]["pages"].ToString());
            List <Page> pagesInfo = new List <Page>();

            foreach (JObject page in pages)
            {
                Page p = new Page(page["page"].Value <int>(),
                                  id,
                                  page["cid"].ToString(),
                                  "", //epid
                                  page["part"].ToString().Trim(),
                                  page["duration"].Value <int>(),
                                  page["dimension"]["width"] + "x" + page["dimension"]["height"]);
                pagesInfo.Add(p);
            }

            try
            {
                if (infoJson["data"]["redirect_url"].ToString().Contains("bangumi"))
                {
                    bangumi = true;
                    string epId = Regex.Match(infoJson["data"]["redirect_url"].ToString(), "ep(\\d+)").Groups[1].Value;
                    //番剧内容通常不会有分P,如果有分P则不需要epId参数
                    if (pages.Count == 1)
                    {
                        pagesInfo.ForEach(p => p.epid = epId);
                    }
                }
            }
            catch { }

            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = pic;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = bangumi;

            return(info);
        }
        public async Task <BBDownVInfo> FetchAsync(string id)
        {
            id = id.Substring(7);
            string index = "";
            string api   = $"https://api.bilibili.com/pugv/view/web/season?ep_id={id}";
            string json  = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var         data      = infoJson.RootElement.GetProperty("data");
            string      cover     = data.GetProperty("cover").ToString();
            string      title     = data.GetProperty("title").ToString();
            string      desc      = data.GetProperty("subtitle").ToString();
            var         pages     = data.GetProperty("episodes").EnumerateArray().ToList();
            List <Page> pagesInfo = new List <Page>();

            foreach (var page in pages)
            {
                Page p = new Page(page.GetProperty("index").GetInt32(),
                                  page.GetProperty("aid").ToString(),
                                  page.GetProperty("cid").ToString(),
                                  page.GetProperty("id").ToString(),
                                  page.GetProperty("title").ToString().Trim(),
                                  page.GetProperty("duration").GetInt32(), "");
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }
            string pubTime = pagesInfo.Count > 0 ? pages[0].GetProperty("release_date").ToString() : "";

            pubTime = pubTime != "" ? (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString()) : "";

            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
        public BBDownVInfo Fetch(string id)
        {
            id = id.Substring(7);
            string      index     = "";
            string      api       = $"https://api.bilibili.com/pugv/view/web/season?ep_id={id}";
            string      json      = GetWebSource(api);
            JObject     infoJson  = JObject.Parse(json);
            string      cover     = infoJson["data"]["cover"].ToString();
            string      title     = infoJson["data"]["title"].ToString();
            string      desc      = infoJson["data"]["subtitle"].ToString();
            JArray      pages     = JArray.Parse(infoJson["data"]["episodes"].ToString());
            List <Page> pagesInfo = new List <Page>();

            foreach (JObject page in pages)
            {
                Page p = new Page(page["index"].Value <int>(),
                                  page["aid"].ToString(),
                                  page["cid"].ToString(),
                                  page["id"].ToString(),
                                  page["title"].ToString().Trim(),
                                  page["duration"].Value <int>(), "");
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }
            string pubTime = pagesInfo.Count > 0 ? pages[0]["release_date"].ToString() : "";

            pubTime = pubTime != "" ? (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString()) : "";

            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
        public BBDownVInfo Fetch(string id)
        {
            id = id.Substring(3);
            string index = "";
            //string api = $"https://api.global.bilibili.com/intl/gateway/ogv/m/view?ep_id={id}&s_locale=ja_JP";
            string  api      = $"https://api.global.bilibili.com/intl/gateway/v2/ogv/view/app/season?ep_id={id}&platform=android&s_locale=zh_SG&mobi_app=bstar_a" + (Program.TOKEN != "" ? $"&access_key={Program.TOKEN}" : "");
            string  json     = GetWebSource(api);
            JObject infoJson = JObject.Parse(json);
            string  seasonId = infoJson["result"]["season_id"].ToString();
            string  cover    = infoJson["result"]["cover"].ToString();
            string  title    = infoJson["result"]["title"].ToString();
            string  desc     = infoJson["result"]["evaluate"].ToString();


            if (cover == "")
            {
                string animeUrl = $"https://bangumi.bilibili.com/anime/{seasonId}";
                var    web      = GetWebSource(animeUrl);
                if (web != "")
                {
                    Regex  regex = new Regex("window.__INITIAL_STATE__=([\\s\\S].*?);\\(function\\(\\)");
                    string _json = regex.Match(web).Groups[1].Value;
                    cover = JObject.Parse(_json)["mediaInfo"]["cover"].ToString();
                    title = JObject.Parse(_json)["mediaInfo"]["title"].ToString();
                    desc  = JObject.Parse(_json)["mediaInfo"]["evaluate"].ToString();
                }
            }

            string      pubTime   = infoJson["result"]["publish"]["pub_time"].ToString();
            JArray      pages     = infoJson["result"]["episodes"].ToString() != "" ? JArray.Parse(infoJson["result"]["episodes"].ToString()) : new JArray();
            List <Page> pagesInfo = new List <Page>();
            int         i         = 1;

            if (infoJson["result"]["modules"] != null)
            {
                foreach (JObject section in JArray.Parse(infoJson["result"]["modules"].ToString()))
                {
                    if (section.ToString().Contains($"/{id}"))
                    {
                        pages = JArray.Parse(section["data"]["episodes"].ToString());
                        break;
                    }
                }
            }

            /*if (pages.Count == 0)
             * {
             *  if (web != "")
             *  {
             *      string epApi = $"https://api.bilibili.com/pgc/web/season/section?season_id={seasonId}";
             *      var _web = GetWebSource(epApi);
             *      pages = JArray.Parse(JObject.Parse(_web)["result"]["main_section"]["episodes"].ToString());
             *  }
             *  else if (infoJson["data"]["modules"] != null)
             *  {
             *      foreach (JObject section in JArray.Parse(infoJson["data"]["modules"].ToString()))
             *      {
             *          if (section.ToString().Contains($"ep_id={id}"))
             *          {
             *              pages = JArray.Parse(section["data"]["episodes"].ToString());
             *              break;
             *          }
             *      }
             *  }
             * }*/

            foreach (JObject page in pages)
            {
                string res = "";
                try
                {
                    res = page["dimension"]["width"].ToString() + "x" + page["dimension"]["height"].ToString();
                }
                catch (Exception) { }
                string _title = page["long_title"].ToString().Trim();
                if (string.IsNullOrEmpty(_title))
                {
                    _title = page["title"].ToString();
                }
                Page p = new Page(i++,
                                  page["aid"].ToString(),
                                  page["cid"].ToString(),
                                  page["id"].ToString(),
                                  _title,
                                  0, res);
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }


            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
Exemple #7
0
        public async Task <BBDownVInfo> FetchAsync(string id)
        {
            id = id.Substring(6);
            var favId = id.Split(':')[0];
            var mid   = id.Split(':')[1];

            //查找默认收藏夹
            if (favId == "")
            {
                var favListApi = $"https://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid={mid}&jsonp=jsonp";
                favId = JsonDocument.Parse(await GetWebSourceAsync(favListApi)).RootElement.GetProperty("data").GetProperty("list").EnumerateArray().First().GetProperty("id").ToString();
            }

            int         pageSize  = 20;
            int         index     = 1;
            List <Page> pagesInfo = new List <Page>();

            var api  = $"https://api.bilibili.com/x/v3/fav/resource/list?media_id={favId}&pn=1&ps={pageSize}&keyword=&order=mtime&type=0&tid=0&platform=web&jsonp=jsonp";
            var json = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var    data       = infoJson.RootElement.GetProperty("data");
            int    totalCount = data.GetProperty("info").GetProperty("media_count").GetInt32();
            int    totalPage  = (int)Math.Ceiling((double)totalCount / pageSize);
            var    title      = GetValidFileName(data.GetProperty("info").GetProperty("title").ToString());
            var    intro      = GetValidFileName(data.GetProperty("info").GetProperty("intro").GetString());
            string pubTime    = data.GetProperty("info").GetProperty("ctime").ToString();

            pubTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString();
            var userName = GetValidFileName(data.GetProperty("info").GetProperty("upper").GetProperty("name").ToString());
            var medias   = data.GetProperty("medias").EnumerateArray().ToList();

            for (int page = 2; page <= totalPage; page++)
            {
                api  = $"https://api.bilibili.com/x/v3/fav/resource/list?media_id={favId}&pn={page}&ps={pageSize}&keyword=&order=mtime&type=0&tid=0&platform=web&jsonp=jsonp";
                json = await GetWebSourceAsync(api);

                var jsonDoc = JsonDocument.Parse(json);
                data = jsonDoc.RootElement.GetProperty("data");
                medias.AddRange(data.GetProperty("medias").EnumerateArray().ToList());
            }

            foreach (var m in medias)
            {
                var pageCount = m.GetProperty("page").GetInt32();
                if (pageCount > 1)
                {
                    var tmpInfo = await new BBDownNormalInfoFetcher().FetchAsync(m.GetProperty("id").ToString());
                    foreach (var item in tmpInfo.PagesInfo)
                    {
                        Page p = new Page(index++, item);
                        p.title = m.GetProperty("title").ToString() + $"_P{item.index}_{item.title}";
                        p.cover = tmpInfo.Pic;
                        p.desc  = m.GetProperty("intro").ToString();
                        if (!pagesInfo.Contains(p))
                        {
                            pagesInfo.Add(p);
                        }
                    }
                }
                else
                {
                    Page p = new Page(index++,
                                      m.GetProperty("id").ToString(),
                                      m.GetProperty("ugc").GetProperty("first_cid").ToString(),
                                      "", //epid
                                      m.GetProperty("title").ToString(),
                                      m.GetProperty("duration").GetInt32(),
                                      "",
                                      m.GetProperty("cover").ToString(),
                                      m.GetProperty("intro").ToString());
                    if (!pagesInfo.Contains(p))
                    {
                        pagesInfo.Add(p);
                    }
                }
            }

            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = intro.Trim();
            info.Pic       = "";
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = false;

            return(info);
        }
        public async Task <BBDownVInfo> FetchAsync(string id)
        {
            id = id.Substring(3);
            string index = "";
            //string api = $"https://api.global.bilibili.com/intl/gateway/ogv/m/view?ep_id={id}&s_locale=ja_JP";
            string api  = $"https://api.bilibili.tv/intl/gateway/v2/ogv/view/app/season?ep_id={id}&platform=android&s_locale=zh_SG&mobi_app=bstar_a" + (Program.TOKEN != "" ? $"&access_key={Program.TOKEN}" : "");
            string json = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var    result   = infoJson.RootElement.GetProperty("result");
            string seasonId = result.GetProperty("season_id").ToString();
            string cover    = result.GetProperty("cover").ToString();
            string title    = result.GetProperty("title").ToString();
            string desc     = result.GetProperty("evaluate").ToString();


            if (cover == "")
            {
                string animeUrl = $"https://bangumi.bilibili.com/anime/{seasonId}";
                var    web      = await GetWebSourceAsync(animeUrl);

                if (web != "")
                {
                    Regex  regex = new Regex("window.__INITIAL_STATE__=([\\s\\S].*?);\\(function\\(\\)");
                    string _json = regex.Match(web).Groups[1].Value;
                    using var _tempJson = JsonDocument.Parse(_json);
                    cover = _tempJson.RootElement.GetProperty("mediaInfo").GetProperty("cover").ToString();
                    title = _tempJson.RootElement.GetProperty("mediaInfo").GetProperty("title").ToString();
                    desc  = _tempJson.RootElement.GetProperty("mediaInfo").GetProperty("evaluate").ToString();
                }
            }

            string pubTime = result.GetProperty("publish").GetProperty("pub_time").ToString();
            var    pages   = new List <JsonElement>();

            if (result.TryGetProperty("episodes", out _))
            {
                pages = result.GetProperty("episodes").EnumerateArray().ToList();
            }
            List <Page> pagesInfo = new List <Page>();
            int         i         = 1;

            JsonElement modules;

            if (result.TryGetProperty("modules", out modules))
            {
                foreach (var section in modules.EnumerateArray())
                {
                    if (section.ToString().Contains($"/{id}"))
                    {
                        pages = section.GetProperty("data").GetProperty("episodes").EnumerateArray().ToList();
                        break;
                    }
                }
            }

            /*if (pages.Count == 0)
             * {
             *  if (web != "")
             *  {
             *      string epApi = $"https://api.bilibili.com/pgc/web/season/section?season_id={seasonId}";
             *      var _web = GetWebSource(epApi);
             *      pages = JArray.Parse(JObject.Parse(_web)["result"]["main_section"]["episodes"].ToString());
             *  }
             *  else if (infoJson["data"]["modules"] != null)
             *  {
             *      foreach (JObject section in JArray.Parse(infoJson["data"]["modules"].ToString()))
             *      {
             *          if (section.ToString().Contains($"ep_id={id}"))
             *          {
             *              pages = JArray.Parse(section["data"]["episodes"].ToString());
             *              break;
             *          }
             *      }
             *  }
             * }*/

            foreach (var page in pages)
            {
                //跳过预告
                JsonElement badge;
                if (page.TryGetProperty("badge", out badge) && badge.ToString() == "预告")
                {
                    continue;
                }
                string res = "";
                try
                {
                    res = page.GetProperty("dimension").GetProperty("width").ToString() + "x" + page.GetProperty("dimension").GetProperty("height").ToString();
                }
                catch (Exception) { }
                string _title = page.GetProperty("title").ToString() + " " + page.GetProperty("long_title").ToString();
                _title = _title.Trim();
                Page p = new Page(i++,
                                  page.GetProperty("aid").ToString(),
                                  page.GetProperty("cid").ToString(),
                                  page.GetProperty("id").ToString(),
                                  _title,
                                  0, res);
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }


            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
Exemple #9
0
        public async Task <BBDownVInfo> FetchAsync(string id)
        {
            id = id.Substring(3);
            string index = "";
            string api   = $"https://api.bilibili.com/pgc/view/web/season?ep_id={id}";
            string json  = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var         result    = infoJson.RootElement.GetProperty("result");
            string      cover     = result.GetProperty("cover").ToString();
            string      title     = result.GetProperty("title").ToString();
            string      desc      = result.GetProperty("evaluate").ToString();
            string      pubTime   = result.GetProperty("publish").GetProperty("pub_time").ToString();
            var         pages     = result.GetProperty("episodes").EnumerateArray().ToList();
            List <Page> pagesInfo = new List <Page>();
            int         i         = 1;

            //episodes为空; 或者未包含对应epid,番外/花絮什么的
            if (pages.Count == 0 || !result.GetProperty("episodes").ToString().Contains($"/ep{id}"))
            {
                JsonElement sections;
                if (result.TryGetProperty("section", out sections))
                {
                    foreach (var section in sections.EnumerateArray())
                    {
                        if (section.ToString().Contains($"/ep{id}"))
                        {
                            title += "[" + section.GetProperty("title").ToString() + "]";
                            pages  = section.GetProperty("episodes").EnumerateArray().ToList();
                            break;
                        }
                    }
                }
            }

            foreach (var page in pages)
            {
                //跳过预告
                JsonElement badge;
                if (page.TryGetProperty("badge", out badge) && badge.ToString() == "预告")
                {
                    continue;
                }
                string res = "";
                try
                {
                    res = page.GetProperty("dimension").GetProperty("width").ToString() + "x" + page.GetProperty("dimension").GetProperty("height").ToString();
                }
                catch (Exception) { }
                string _title = page.GetProperty("title").ToString() + " " + page.GetProperty("long_title").ToString();
                _title = _title.Trim();
                Page p = new Page(i++,
                                  page.GetProperty("aid").ToString(),
                                  page.GetProperty("cid").ToString(),
                                  page.GetProperty("id").ToString(),
                                  _title,
                                  0, res);
                if (p.epid == id)
                {
                    index = p.index.ToString();
                }
                pagesInfo.Add(p);
            }


            var info = new BBDownVInfo();

            info.Title     = title.Trim();
            info.Desc      = desc.Trim();
            info.Pic       = cover;
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = true;
            info.IsCheese  = true;
            info.Index     = index;

            return(info);
        }
        public static async Task DownloadFlvFile(BBDownVInfo vInfo, List <Subtitle> subtitleInfo, Page p, List <Video> videoTracks, Video video, MyOption myOption, string indexStr)
        {
            string videoPath = $"{p.aid}/{p.aid}.P{indexStr}.{p.cid}.mp4";

            bool multiThread = myOption.MultiThread;
            bool infoMode    = myOption.OnlyShowInfo;
            bool useAria2c   = myOption.UseAria2c;
            bool skipMux     = myOption.SkipMux;
            bool audioOnly   = myOption.AudioOnly;
            bool videoOnly   = myOption.VideoOnly;

            List <Page> pagesInfo = vInfo.PagesInfo;
            string      title     = vInfo.Title;
            string      desc      = vInfo.Desc;
            string      pic       = vInfo.Pic;
            string      pubTime   = vInfo.PubTime;
            bool        bangumi   = vInfo.IsBangumi;
            bool        cheese    = vInfo.IsCheese;

            //处理文件夹以.结尾导致的异常情况
            if (title.EndsWith("."))
            {
                title += "_fix";
            }
            string outPath = GetValidFileName(title) + (vInfo.PagesInfo.Count > 1 ? $"/[P{indexStr}]{GetValidFileName(p.title)}" : (vInfo.PagesInfo.Count > 1 ? $"[P{indexStr}]{GetValidFileName(p.title)}" : "")) + ".mp4";

            //降序
            videoTracks.Sort(Compare);
            //TODO 下载
            Log($"共计{videoTracks.Count}条流({video.Format}, 共有{video.Clips.Count}个分段).");
            int index = 0;

            foreach (var v in videoTracks)
            {
                LogColor($"{index++}. [{v.dfn}] [{v.res}] [{v.codecs}] [{v.fps}] [~{(video.Size / 1024 / (video.Length / 1000) * 8).ToString("00")} kbps] [{FormatFileSize(video.Size)}]".Replace("[] ", ""), false);
                if (infoMode)
                {
                    video.Clips.ForEach(delegate(string c) { Console.WriteLine(c); });
                }
            }
            if (infoMode)
            {
                return;
            }
            if (File.Exists(outPath) && new FileInfo(outPath).Length != 0)
            {
                Log($"{outPath}已存在, 跳过下载...");
                return;
            }
            var pad = string.Empty.PadRight(video.Clips.Count.ToString().Length, '0');

            for (int i = 0; i < video.Clips.Count; i++)
            {
                var link = video.Clips[i];
                videoPath = $"{p.aid}/{p.aid}.P{indexStr}.{p.cid}.{i.ToString(pad)}.mp4";
                if (multiThread && !link.Contains("-cmcc-"))
                {
                    if (videoTracks.Count != 0)
                    {
                        Log($"开始多线程下载P{p.index}视频, 片段({(i + 1).ToString(pad)}/{video.Clips.Count})...");
                        await MultiThreadDownloadFileAsync(link, videoPath, useAria2c);

                        Log("合并视频分片...");
                        CombineMultipleFilesIntoSingleFile(GetFiles(Path.GetDirectoryName(videoPath), ".vclip"), videoPath);
                    }
                    Log("清理分片...");
                    foreach (var file in new DirectoryInfo(Path.GetDirectoryName(videoPath)).EnumerateFiles("*.?clip"))
                    {
                        file.Delete();
                    }
                }
                else
                {
                    if (multiThread && link.Contains("-cmcc-"))
                    {
                        LogError("检测到cmcc域名cdn, 已经禁用多线程");
                    }
                    if (videoTracks.Count != 0)
                    {
                        Log($"开始下载P{p.index}视频, 片段({(i + 1).ToString(pad)}/{video.Clips.Count})...");
                        await DownloadFile(link, videoPath, useAria2c);
                    }
                }
            }
            Log($"下载P{p.index}完毕");
            Log("开始合并分段...");
            var files = GetFiles(Path.GetDirectoryName(videoPath), ".mp4");

            videoPath = $"{p.aid}/{p.aid}.P{indexStr}.{p.cid}.mp4";
            MergeFLV(files, videoPath);
            if (skipMux)
            {
                return;
            }
            Log("开始混流视频" + (subtitleInfo.Count > 0 ? "和字幕" : "") + "...");
            int code = MuxAV(videoPath, "", outPath,
                             desc,
                             title,
                             vInfo.PagesInfo.Count > 1 ? ($"P{indexStr}.{p.title}") : "",
                             File.Exists($"{p.aid}/{p.aid}.jpg") ? $"{p.aid}/{p.aid}.jpg" : "",
                             subtitleInfo, audioOnly, videoOnly);

            if (code != 0 || !File.Exists(outPath) || new FileInfo(outPath).Length == 0)
            {
                LogError("合并失败"); return;
            }
            Log("清理临时文件...");
            if (videoTracks.Count != 0)
            {
                File.Delete(videoPath);
            }
            foreach (var s in subtitleInfo)
            {
                File.Delete(s.path);
            }
            if (pagesInfo.Count == 1 || p.index == pagesInfo.Last().index || p.aid != pagesInfo.Last().aid)
            {
                File.Delete($"{p.aid}/{p.aid}.jpg");
            }
            if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0)
            {
                Directory.Delete(p.aid, true);
            }
        }
        public async Task <BBDownVInfo> FetchAsync(string id)
        {
            id = id.Substring(10);
            var api  = $"https://api.bilibili.com/x/v1/medialist/info?type=8&biz_id={id}&tid=0";
            var json = await GetWebSourceAsync(api);

            using var infoJson = JsonDocument.Parse(json);
            var    data      = infoJson.RootElement.GetProperty("data");
            var    listTitle = GetValidFileName(data.GetProperty("title").GetString());
            var    intro     = data.GetProperty("intro").GetString();
            string pubTime   = data.GetProperty("ctime").ToString();

            pubTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(pubTime)).ToLocalTime().ToString();

            List <Page> pagesInfo = new List <Page>();
            bool        hasMore   = true;
            var         oid       = "";
            int         index     = 1;

            while (hasMore)
            {
                var listApi = $"https://api.bilibili.com/x/v2/medialist/resource/list?type=8&oid={oid}&otype=2&biz_id={id}&bvid=&with_current=true&mobi_app=web&ps=20&direction=false&sort_field=1&tid=0&desc=false";
                json = await GetWebSourceAsync(listApi);

                using var listJson = JsonDocument.Parse(json);
                data    = listJson.RootElement.GetProperty("data");
                hasMore = data.GetProperty("has_more").GetBoolean();
                foreach (var m in data.GetProperty("media_list").EnumerateArray())
                {
                    var pageCount = m.GetProperty("page").GetInt32();
                    var desc      = m.GetProperty("intro").GetString();
                    foreach (var page in m.GetProperty("pages").EnumerateArray())
                    {
                        Page p = new Page(index++,
                                          m.GetProperty("id").ToString(),
                                          page.GetProperty("id").ToString(),
                                          "",                                                                                                                                                             //epid
                                          pageCount == 1 ? m.GetProperty("title").ToString() : $"{m.GetProperty("title").ToString()}_P{page.GetProperty("page").ToString()}_{page.GetProperty("title")}", //单P使用外层标题 多P则拼接内层子标题
                                          page.GetProperty("duration").GetInt32(),
                                          page.GetProperty("dimension").GetProperty("width").ToString() + "x" + page.GetProperty("dimension").GetProperty("height").ToString(),
                                          m.GetProperty("cover").ToString(),
                                          desc);
                        if (!pagesInfo.Contains(p))
                        {
                            pagesInfo.Add(p);
                        }
                        else
                        {
                            index--;
                        }
                    }
                    oid = m.GetProperty("id").ToString();
                }
            }

            var info = new BBDownVInfo();

            info.Title     = listTitle.Trim();
            info.Desc      = intro.Trim();
            info.Pic       = "";
            info.PubTime   = pubTime;
            info.PagesInfo = pagesInfo;
            info.IsBangumi = false;

            return(info);
        }