Example #1
0
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            var opencc = new OpenChineseConverter();

            var twText = "這個小丑醜歸醜但很管用,這個滑鼠,長髮散發出香氣,列印中文為何出亂碼,阿拉伯聯合大公國,義大利,尚比亞";
            var cnText = "这个小丑丑归丑但很管用,这个鼠标,长发散发出香气,打印中文为何出乱码,阿拉伯联合酋长国,意大利,赞比亚";

            // 轉台灣正體
            var openccTWText = opencc.ToTaiwanFromSimplifiedWithPhrases(cnText);

            // 轉簡體
            var openccCNText = opencc.ToSimplifiedFromTaiwanWithPhrases(twText);

            // 顯示結果
            Console.WriteLine($"===== 原文 =====\n{cnText}\n===== 轉繁體 =====\n{openccTWText}");

            Console.WriteLine($"\n===== 原文 =====\n{twText}\n===== 轉簡體 =====\n{openccCNText}");

            Console.ReadLine();
        }
Example #2
0
        public static int MuxAV(string videoPath, string audioPath, string outPath, string desc = "", string title = "", string episodeId = "", string pic = "", string lang = "", List <Subtitle> subs = null, bool audioOnly = false, bool videoOnly = false, string aid = "", string cid = "")
        {
            desc  = EscapeString(desc);
            title = EscapeString(title);

            if (outPath.Contains("/") && !Directory.Exists(Path.GetDirectoryName(outPath)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(outPath));
            }
            //----分析并生成-i参数
            StringBuilder inputArg = new StringBuilder();
            StringBuilder metaArg  = new StringBuilder();

            if (!string.IsNullOrEmpty(videoPath))
            {
                inputArg.Append($" -i \"{videoPath}\" ");
            }
            if (!string.IsNullOrEmpty(audioPath))
            {
                inputArg.Append($" -i \"{audioPath}\" ");
            }
            if (!string.IsNullOrEmpty(pic))
            {
                inputArg.Append($" -i \"{pic}\" ");
            }
            string[] files = System.IO.Directory.GetFiles(Directory.GetCurrentDirectory(), $"temp/{aid}/{aid}.{cid}.*.srt");
            if (subs != null)
            {
                for (int i = 0; i < subs.Count; i++)
                {
                    if (File.Exists(subs[i].path) && File.ReadAllText(subs[i].path) != "")
                    {
                        inputArg.Append($" -i \"{subs[i].path}\" ");
                        metaArg.Append($" -metadata:s:s:{i} handler_name=\"{SubDescDic[subs[i].lan]}\" -metadata:s:s:{i} language={SubLangDic[subs[i].lan]} -metadata:s:s:{i} title=\"{SubTitleDic[subs[i].lan]}\"");
                    }
                }
                if (files.Length > 0 && subs.Count < 1)
                {
                    Log("正在合併現有字幕...");
                    for (int e = 0; e < files.Length; e++)
                    {
                        inputArg.Append($" -i \"{files[e]}\" ");
                    }
                }
            }
            if (!string.IsNullOrEmpty(pic))
            {
                metaArg.Append(" -disposition:v:1 attached_pic ");
            }
            var inputCount = Regex.Matches(inputArg.ToString(), "-i \"").Count;

            for (int i = 0; i < inputCount; i++)
            {
                inputArg.Append($" -map {i} ");
            }
            var    converter = new OpenChineseConverter();
            string titletcov = converter.ToTaiwanFromSimplifiedWithPhrases(title);
            string desccov   = converter.ToTaiwanFromSimplifiedWithPhrases(desc);
            //----分析完毕
            var arguments = $"-loglevel warning -y " +
                            inputArg.ToString() + metaArg.ToString() + $" -metadata title=\"" + titletcov + "\" " +
                            (lang == "" ? "" : $"-metadata:s:a:0 language={lang} ") +
                            $"-metadata description=\"{desccov}\" " +
                            (episodeId == "" ? "" : $"-metadata album=\"{titletcov}\" ") +
                            (audioOnly ? " -vn " : "") + (videoOnly ? " -an " : "") +
                            $"-c copy " +
                            (subs != null ? " -c:s mov_text " : "") +
                            $"\"{outPath}\"";

            LogDebug("ffmpeg命令:{0}", arguments);
            return(ffmpeg(arguments));
        }
Example #3
0
        private static async Task DoWorkAsync(MyOption myOption)
        {
            Console.BackgroundColor = ConsoleColor.DarkBlue;
            Console.ForegroundColor = ConsoleColor.White;
            var ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

            Console.Write($"BBDown version {ver.Major}.{ver.Minor}.{ver.Build}, Bilibili Downloader.\r\n");
            Console.ResetColor();
            Console.Write("BBDown Server Edition");
            Console.WriteLine();
            //检测更新
            new Thread(async() =>
            {
                await CheckUpdateAsync();
            }).Start();
            try
            {
                //Read cookie from cookie.txt
                string cookiePath = Directory.GetCurrentDirectory();
                if (!File.Exists($"cookie.txt"))
                {
                    File.Create($"{cookiePath}/cookie.txt");
                }
                string cookieString = File.ReadAllText($"{cookiePath}/cookie.txt");
                if (cookieString != null)
                {
                    cookieString = "";
                }
                LogDebug(cookieString);
                bool interactMode = myOption.Interactive;
                bool infoMode     = myOption.OnlyShowInfo;
                bool tvApi        = myOption.UseTvApi;
                bool intlApi      = myOption.UseIntlApi;
                bool hevc         = myOption.OnlyHevc;
                bool hideStreams  = myOption.HideStreams;
                bool multiThread  = myOption.MultiThread;
                bool audioOnly    = myOption.AudioOnly;
                bool videoOnly    = myOption.VideoOnly;
                bool skipMux      = myOption.SkipMux;
                bool showAll      = myOption.ShowAll;
                bool useAria2c    = myOption.UseAria2c;
                DEBUG_LOG = myOption.Debug;
                string input      = myOption.Url;
                string lang       = myOption.Language;
                string selectPage = myOption.SelectPage.ToUpper();
                string aidOri     = ""; //原始aid
                COOKIE = cookieString;
                TOKEN  = myOption.AccessToken.Replace("access_token=", "");

                //audioOnly和videoOnly同时开启则全部忽视
                if (audioOnly && videoOnly)
                {
                    audioOnly = false;
                    videoOnly = false;
                }

                List <string> selectedPages = null;
                if (!string.IsNullOrEmpty(GetQueryString("p", input)))
                {
                    selectedPages = new List <string>();
                    selectedPages.Add(GetQueryString("p", input));
                }

                LogDebug("運行參數:{0}", myOption);
                if (string.IsNullOrEmpty(COOKIE) && File.Exists(Path.Combine(AppContext.BaseDirectory, "BBDown.data")) && !tvApi)
                {
                    Log("加載本地cookie...");
                    LogDebug("文件路徑:{0}", Path.Combine(AppContext.BaseDirectory, "BBDown.data"));
                    COOKIE = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "BBDown.data"));
                }
                if (string.IsNullOrEmpty(TOKEN) && File.Exists(Path.Combine(AppContext.BaseDirectory, "BBDownTV.data")) && tvApi)
                {
                    Log("加載本地token...");
                    LogDebug("文件路徑:{0}", Path.Combine(AppContext.BaseDirectory, "BBDownTV.data"));
                    TOKEN = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "BBDownTV.data"));
                    TOKEN = TOKEN.Replace("access_token=", "");
                }
                Log("獲取aid...");
                aidOri = await GetAvIdAsync(input);

                Log("獲取aid結束: " + aidOri);
                //-p的优先级大于URL中的自带p参数,所以先清空selectedPages
                if (!string.IsNullOrEmpty(selectPage) && selectPage != "ALL" && selectPage != "LATEST")
                {
                    selectedPages = new List <string>();
                    try
                    {
                        string tmp = selectPage;
                        tmp = tmp.Trim().Trim(',');
                        if (tmp.Contains("-"))
                        {
                            int start = int.Parse(tmp.Split('-')[0]);
                            int end   = int.Parse(tmp.Split('-')[1]);
                            for (int i = start; i <= end; i++)
                            {
                                selectedPages.Add(i.ToString());
                            }
                        }
                        else
                        {
                            foreach (var s in tmp.Split(','))
                            {
                                selectedPages.Add(s);
                            }
                        }
                    }
                    catch { LogError("解析分P參數時失敗了~"); selectedPages = null; };
                }

                if (selectPage == "ALL")
                {
                    selectedPages = null;
                }

                if (string.IsNullOrEmpty(aidOri))
                {
                    throw new Exception("輸入有誤");
                }
                Log("獲取視頻信息...");
                IFetcher fetcher = new BBDownNormalInfoFetcher();
                if (aidOri.StartsWith("cheese"))
                {
                    fetcher = new BBDownCheeseInfoFetcher();
                }
                else if (aidOri.StartsWith("ep"))
                {
                    fetcher = new BBDownBangumiInfoFetcher();
                }

                var    vInfo   = fetcher.Fetch(aidOri);
                string title   = vInfo.Title;
                string desc    = vInfo.Desc;
                string pic     = vInfo.Pic;
                string pubTime = vInfo.PubTime;
                LogColor("視頻標題: " + title);
                LogDebug("發佈時間: " + pubTime);
                List <Page>     pagesInfo    = vInfo.PagesInfo;
                List <Subtitle> subtitleInfo = new List <Subtitle>();
                bool            more         = false;
                bool            bangumi      = vInfo.IsBangumi;
                bool            cheese       = vInfo.IsCheese;

                //打印分P信息
                foreach (Page p in pagesInfo)
                {
                    if (!showAll && more && p.index != pagesInfo.Count)
                    {
                        continue;
                    }
                    if (!showAll && !more && p.index > 5)
                    {
                        Log("......");
                        more = true;
                    }
                    else
                    {
                        LogDebug($"P{p.index}: [{p.cid}] [{p.title}] [{FormatTime(p.dur)}]");
                    }
                }
                if (selectPage == "LATEST")
                {
                    selectedPages = new List <string>();
                    selectedPages.Add(pagesInfo.Count.ToString());
                    LogDebug(pagesInfo.Count.ToString());
                }
                //如果用户没有选择分P,根据epid来确定某一集
                if (selectedPages == null && selectPage != "ALL" && !string.IsNullOrEmpty(vInfo.Index) && selectPage != "LATEST")
                {
                    selectedPages = new List <string> {
                        vInfo.Index
                    };
                    Log("程序已自動選擇你輸入的集數,如果要下載其他集數請自行指定分P(可使用參數-p ALL代表全部 -p LATEST代表最新一集)");
                }

                Log($"共計 {pagesInfo.Count} 個分P, 已選擇:" + (selectedPages == null ? "ALL" : string.Join(",", selectedPages)));

                //过滤不需要的分P
                if (selectedPages != null)
                {
                    pagesInfo = pagesInfo.Where(p => selectedPages.Contains(p.index.ToString())).ToList();
                }

                foreach (Page p in pagesInfo)
                {
                    Log($"開始解析P{p.index}...");
                    if (!infoMode)
                    {
                        if (!Directory.Exists($"temp/{p.aid}"))
                        {
                            Directory.CreateDirectory($"temp/{p.aid}");
                        }
                        if (!File.Exists($"temp/{p.aid}/{p.aid}.jpg"))
                        {
                            Log("下載封面...");
                            LogDebug("下載:{0}", pic);
                            new WebClient().DownloadFile(pic, $"temp/{p.aid}/{p.aid}.jpg");
                        }
                        string[] files = System.IO.Directory.GetFiles(Directory.GetCurrentDirectory(), $"temp/{p.aid}/{p.aid}.{p.cid}.*.srt");
                        if (files.Length > 0)
                        {
                            Log("字幕已經獲取...");
                            for (int i = 0; i < files.Length; i++)
                            {
                                LogDebug(files[i]);
                            }
                        }
                        else
                        {
                            LogDebug("獲取字幕...");
                            subtitleInfo = BBDownSubUtil.GetSubtitles(p.aid, p.cid, p.epid, intlApi);
                            foreach (Subtitle s in subtitleInfo)
                            {
                                Log($"下載字幕 {s.lan} => {BBDownSubUtil.SubDescDic[s.lan]}...");
                                LogDebug("下載:{0}", s.url);
                                BBDownSubUtil.SaveSubtitle(s.url, s.path);
                            }
                        }
                    }
                    string        webJsonStr  = "";
                    List <Video>  videoTracks = new List <Video>();
                    List <Audio>  audioTracks = new List <Audio>();
                    List <string> clips       = new List <string>();
                    List <string> dfns        = new List <string>();
                    string        indexStr    = p.index.ToString("0".PadRight(pagesInfo.OrderByDescending(_p => _p.index).First().index.ToString().Length, '0'));
                    string        videoPath   = $"temp/{p.aid}/{p.aid}.P{indexStr}.{p.cid}.mp4";
                    string        audioPath   = $"temp/{p.aid}/{p.aid}.P{indexStr}.{p.cid}.m4a";
                    //处理文件夹以.结尾导致的异常情况
                    if (title.EndsWith("."))
                    {
                        title += "_fix";
                    }
                    var converter = new OpenChineseConverter();
                    title = converter.ToTaiwanFromSimplified(title);
                    Log(title);
                    string ep = p.index.ToString("D2");
                    //讀取JSON存放
                    string  jsonpath = Directory.GetCurrentDirectory();
                    string  jsonfile = File.ReadAllText($"{jsonpath}/config.json");
                    dynamic json     = JValue.Parse(jsonfile);
                    string  dirname  = json.dir;
                    title = Regex.Replace(title, @"[<>:""/\\|?*]", "-");


                    //调用解析
                    (webJsonStr, videoTracks, audioTracks, clips, dfns) = ExtractTracks(hevc, aidOri, p.aid, p.cid, p.epid, tvApi, intlApi);
                    //File.WriteAllText($"debug.json", JObject.Parse(webJsonStr).ToString());
                    JObject respJson = JObject.Parse(webJsonStr);
                    string  outPath  = dirname + (pagesInfo.Count > 1 ? $"/{json.prefix}{title}[{ep}][0000P]{json.suffix}" +
                                                  $".mp4" : $"/{json.prefix}{title}[{ep}][0000P]{json.suffix}.mp4");
                    //此处代码简直灾难,后续优化吧
                    if ((videoTracks.Count != 0 || audioTracks.Count != 0) && clips.Count == 0)   //dash
                    {
                        if (webJsonStr.Contains("\"video\":[") && videoTracks.Count == 0)

                        {
                            LogError("沒有找到符合要求的視頻流");
                            if (!audioOnly)
                            {
                                continue;
                            }
                        }
                        if (webJsonStr.Contains("\"audio\":[") && audioTracks.Count == 0)
                        {
                            LogError("沒有找到符合要求的音頻流");
                            if (!videoOnly)
                            {
                                continue;
                            }
                        }
                        //降序
                        videoTracks.Sort(Compare);
                        audioTracks.Sort(Compare);

                        if (audioOnly)
                        {
                            videoTracks.Clear();
                        }
                        if (videoOnly)
                        {
                            audioTracks.Clear();
                        }

                        int vIndex = 0;
                        int aIndex = 0;

                        if (!hideStreams)
                        {
                            //展示所有的音视频流信息
                            if (videoTracks.Count > 0)
                            {
                                Log($"共計{videoTracks.Count}條視頻流.");
                                int index = 0;
                                foreach (var v in videoTracks)
                                {
                                    int pDur = p.dur == 0 ? v.dur : p.dur;
                                    LogColor($"{index++}. [{v.dfn}] [{v.res}] [{v.codecs}] [{v.fps}] [{v.bandwith} kbps] [~{FormatFileSize(pDur * v.bandwith * 1024 / 8)}]".Replace("[] ", ""), false);
                                    if (infoMode)
                                    {
                                        Console.WriteLine(v.baseUrl);
                                    }
                                }
                            }
                            if (audioTracks.Count > 0)
                            {
                                Log($"共計{audioTracks.Count}條音頻流.");
                                int index = 0;
                                foreach (var a in audioTracks)
                                {
                                    int pDur = p.dur == 0 ? a.dur : p.dur;
                                    LogColor($"{index++}. [{a.codecs}] [{a.bandwith} kbps] [~{FormatFileSize(pDur * a.bandwith * 1024 / 8)}]", false);
                                    if (infoMode)
                                    {
                                        Console.WriteLine(a.baseUrl);
                                    }
                                }
                            }
                        }
                        if (infoMode)
                        {
                            continue;
                        }
                        if (interactMode && !hideStreams)
                        {
                            if (videoTracks.Count > 0)
                            {
                                Log("請選擇一條視頻流(輸入序號): ", false);
                                Console.ForegroundColor = ConsoleColor.Cyan;
                                vIndex = Convert.ToInt32(Console.ReadLine());
                                if (vIndex > videoTracks.Count || vIndex < 0)
                                {
                                    vIndex = 0;
                                }
                                Console.ResetColor();
                            }
                            if (audioTracks.Count > 0)
                            {
                                Log("請選擇一條音頻流(輸入序號): ", false);
                                Console.ForegroundColor = ConsoleColor.Cyan;
                                aIndex = Convert.ToInt32(Console.ReadLine());
                                if (aIndex > audioTracks.Count || aIndex < 0)
                                {
                                    aIndex = 0;
                                }
                                Console.ResetColor();
                            }
                        }

                        Log($"已選擇的流:");
                        if (videoTracks.Count > 0)
                        {
                            LogColor($"[視頻] [{videoTracks[vIndex].dfn}] [{videoTracks[vIndex].res}] [{videoTracks[vIndex].codecs}] [{videoTracks[vIndex].fps}] [{videoTracks[vIndex].bandwith} kbps] [~{FormatFileSize(videoTracks[vIndex].dur * videoTracks[vIndex].bandwith * 1024 / 8)}]".Replace("[] ", ""), false);
                        }
                        if (audioTracks.Count > 0)
                        {
                            LogColor($"[音頻] [{audioTracks[aIndex].codecs}] [{audioTracks[aIndex].bandwith} kbps] [~{FormatFileSize(audioTracks[aIndex].dur * audioTracks[aIndex].bandwith * 1024 / 8)}]", false);
                        }

                        outPath = dirname + (pagesInfo.Count > 1 ? $"/{json.prefix}{title}[{ep}][{videoTracks[vIndex].dfn}]{json.suffix}" +
                                             $".mp4" : $"/{json.prefix}{title}[{ep}][{videoTracks[vIndex].dfn}]{json.suffix}.mp4");

                        if (File.Exists(outPath) && new FileInfo(outPath).Length != 0)
                        {
                            Log($"{outPath}已存在, 跳過下載...");
                            continue;
                        }

                        if (videoTracks.Count > 0)
                        {
                            if (multiThread && !videoTracks[vIndex].baseUrl.Contains("-cmcc-"))
                            {
                                Log($"開始多線程下載P{p.index}視頻...");
                                await MultiThreadDownloadFileAsync(videoTracks[vIndex].baseUrl, 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 && videoTracks[vIndex].baseUrl.Contains("-cmcc-"))
                                {
                                    LogError("檢測到cmcc域名cdn, 已經禁用多線程");
                                }
                                Log($"開始下載P{p.index}視頻...");
                                await DownloadFile(videoTracks[vIndex].baseUrl, videoPath, useAria2c);
                            }
                        }
                        if (audioTracks.Count > 0)
                        {
                            if (multiThread && !audioTracks[aIndex].baseUrl.Contains("-cmcc-"))
                            {
                                Log($"開始多線程下載P{p.index}音頻...");
                                await MultiThreadDownloadFileAsync(audioTracks[aIndex].baseUrl, audioPath, useAria2c);

                                Log("合併音頻分片...");
                                CombineMultipleFilesIntoSingleFile(GetFiles(Path.GetDirectoryName(audioPath), ".aclip"), audioPath);
                                Log("清理分片...");
                                foreach (var file in new DirectoryInfo(Path.GetDirectoryName(videoPath)).EnumerateFiles("*.?clip"))
                                {
                                    file.Delete();
                                }
                            }
                            else
                            {
                                if (multiThread && audioTracks[aIndex].baseUrl.Contains("-cmcc-"))
                                {
                                    LogError("檢測到cmcc域名cdn, 已經禁用多線程");
                                }
                                Log($"開始下載P{p.index}音頻...");
                                await DownloadFile(audioTracks[aIndex].baseUrl, audioPath, useAria2c);
                            }
                        }

                        Log($"下載P{p.index}完畢");
                        if (videoTracks.Count == 0)
                        {
                            videoPath = "";
                        }
                        if (audioTracks.Count == 0)
                        {
                            audioPath = "";
                        }

                        if (skipMux)
                        {
                            continue;
                        }
                        Log("開始合併音視頻" + (subtitleInfo.Count > 0 ? "和字幕" : "") + "...");
                        int code = MuxAV(videoPath, audioPath, outPath,
                                         desc,
                                         title,
                                         vInfo.PagesInfo.Count > 1 ? ($"P{indexStr}.{p.title}") : "",
                                         File.Exists($"temp/{p.aid}/{p.aid}.jpg") ? $"temp/{p.aid}/{p.aid}.jpg" : "",
                                         lang,
                                         subtitleInfo, audioOnly, videoOnly, p.aid, p.cid);
                        if (code != 0 || !File.Exists(outPath) || new FileInfo(outPath).Length == 0)
                        {
                            LogError("合併失敗"); continue;
                        }
                        Log("清理臨時文件...");
                        if (videoTracks.Count > 0)
                        {
                            File.Delete(videoPath);
                        }
                        if (audioTracks.Count > 0)
                        {
                            File.Delete(audioPath);
                        }
                    }
                    else if (clips.Count > 0 && dfns.Count > 0)      //flv
                    {
                        bool flag = false;
reParse:
                        //降序
                        videoTracks.Sort(Compare);

                        if (interactMode && !flag)
                        {
                            int i = 0;
                            dfns.ForEach(key => LogColor($"{i++}.{qualitys[key]}"));
                            Log("請選擇最想要的清晰度(輸入序號): ", false);
                            Console.ForegroundColor = ConsoleColor.Cyan;
                            var vIndex = Convert.ToInt32(Console.ReadLine());
                            if (vIndex > dfns.Count || vIndex < 0)
                            {
                                vIndex = 0;
                            }
                            Console.ResetColor();
                            //重新解析
                            (webJsonStr, videoTracks, audioTracks, clips, dfns) = ExtractTracks(hevc, aidOri, p.aid, p.cid, p.epid, tvApi, intlApi, dfns[vIndex]);
                            flag = true;
                            videoTracks.Clear();
                            goto reParse;
                        }

                        Log($"共計{videoTracks.Count}條流(共有{clips.Count}個分段).");
                        int index = 0;
                        foreach (var v in videoTracks)
                        {
                            LogColor($"{index++}. [{v.dfn}] [{v.res}] [{v.codecs}] [{v.fps}] [~{(v.size / 1024 / v.dur * 8).ToString("00")} kbps] [{FormatFileSize(v.size)}]".Replace("[] ", ""), false);
                            if (infoMode)
                            {
                                clips.ForEach(delegate(string c) { Console.WriteLine(c); });
                            }
                        }
                        if (infoMode)
                        {
                            continue;
                        }
                        if (File.Exists(outPath) && new FileInfo(outPath).Length != 0)
                        {
                            Log($"{outPath}已存在, 跳過下載...");
                            continue;
                        }
                        var pad = string.Empty.PadRight(clips.Count.ToString().Length, '0');
                        for (int i = 0; i < clips.Count; i++)
                        {
                            var link = clips[i];
                            videoPath = $"temp/{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)}/{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)}/{clips.Count})...");
                                    await DownloadFile(link, videoPath, useAria2c);
                                }
                            }
                        }
                        Log($"下載P{p.index}完畢");
                        Log("開始合併分段...");
                        var files = GetFiles(Path.GetDirectoryName(videoPath), ".mp4");
                        videoPath = $"temp/{p.aid}/{p.aid}.P{indexStr}.{p.cid}.mp4";
                        MergeFLV(files, videoPath);
                        Log("開始混流視頻" + (subtitleInfo.Count > 0 ? "和字幕" : "") + "...");
                        int code = MuxAV(videoPath, "", outPath,
                                         desc,
                                         title,
                                         vInfo.PagesInfo.Count > 1 ? ($"P{indexStr}.{p.title}") : "",
                                         File.Exists($"temp/{p.aid}/{p.aid}.jpg") ? $"{p.aid}/{p.aid}.jpg" : "",
                                         lang,
                                         subtitleInfo, audioOnly, videoOnly, p.aid, p.cid);
                        if (code != 0 || !File.Exists(outPath) || new FileInfo(outPath).Length == 0)
                        {
                            LogError("合併失敗"); continue;
                        }
                        Log("清理臨時文件...");
                        if (videoTracks.Count != 0)
                        {
                            File.Delete(videoPath);
                        }
                    }
                    else
                    {
                        if (webJsonStr.Contains("平台不可观看"))
                        {
                            throw new Exception("當前(WEB)平台不可觀看,請嘗試使用TV API解析。");
                        }
                        else if (webJsonStr.Contains("购买后才能观看"))
                        {
                            throw new Exception("購買後才能觀看");
                        }
                        else if (webJsonStr.Contains("大会员专享限制"))
                        {
                            throw new Exception("大會員專享限制");
                        }
                        else if (webJsonStr.Contains("地区不可观看") || webJsonStr.Contains("地區不可觀看"))
                        {
                            throw new Exception("當前地區不可觀看,請嘗試使用代理解析。");
                        }
                        LogError("解析此分P失敗(使用--debug查看詳細信息)");
                        LogDebug("{0}", webJsonStr);
                        continue;
                    }
                }
                Log("任務完成");
            }
            catch (Exception e)
            {
                Console.BackgroundColor = ConsoleColor.Red;
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write(e.Message);
                Console.ResetColor();
                Console.WriteLine();
                Thread.Sleep(1);
            }
        }