From 81d98085e7696aa8fbe4bd2492bf85b64944e22f Mon Sep 17 00:00:00 2001 From: My-Responsitories <email.youxiang.alpha@gmail.com> Date: Fri, 16 Dec 2022 13:02:04 +0800 Subject: [PATCH 1/2] make biliplus support ss/md & replace upos host --- BBDown.Core/Parser.cs | 2 +- BBDown/BBDownUtil.cs | 136 +++++++++++++++++------------------ BBDown/CommandLineInvoker.cs | 3 + BBDown/MyOption.cs | 1 + BBDown/Program.cs | 90 +++++++++++++---------- 5 files changed, 126 insertions(+), 106 deletions(-) diff --git a/BBDown.Core/Parser.cs b/BBDown.Core/Parser.cs index 5495f00bc..bb57bb3d3 100644 --- a/BBDown.Core/Parser.cs +++ b/BBDown.Core/Parser.cs @@ -384,7 +384,7 @@ private static string GetTimeStamp(bool bflag) private static string GetSign(string parms, bool isBiliPlus) { string toEncode = parms + (isBiliPlus ? "acd495b248ec528c2eed1e862d393126" : "59b43e04ad6965f34319062b478f83dd"); - return string.Join("", MD5.HashData(Encoding.UTF8.GetBytes(toEncode)).Select(i => i.ToString("x2")).ToArray()); + return string.Concat(MD5.HashData(Encoding.UTF8.GetBytes(toEncode)).Select(i => i.ToString("x2")).ToArray()); } [GeneratedRegex("window.__playinfo__=([\\s\\S]*?)<\\/script>")] diff --git a/BBDown/BBDownUtil.cs b/BBDown/BBDownUtil.cs index 743bc00bf..74b7e4b35 100644 --- a/BBDown/BBDownUtil.cs +++ b/BBDown/BBDownUtil.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; @@ -53,14 +53,10 @@ public static async Task<string> GetAvIdAsync(string input) { avid = AvRegex().Match(input).Groups[1].Value; } - else if (input.Contains("video/BV")) + else if (input.ToLower().Contains("video/bv")) { avid = await GetAidByBVAsync(BVRegex().Match(input).Groups[1].Value); } - else if (input.Contains("video/bv")) - { - avid = await GetAidByBVAsync(BvRegex().Match(input).Groups[1].Value); - } else if (input.Contains("/cheese/")) { string epId = ""; @@ -79,6 +75,11 @@ public static async Task<string> GetAvIdAsync(string input) string epId = EpRegex().Match(input).Groups[1].Value; avid = $"ep:{epId}"; } + else if (input.Contains("/ss")) + { + string epId = await GetEpIdByBangumiSSIdAsync(SsRegex().Match(input).Groups[1].Value); + avid = $"ep:{epId}"; + } else if (input.Contains("/medialist/") && input.Contains("business_id=") && input.Contains("business=space_collection")) //列表类型是合集 { string bizId = GetQueryString("business_id", input); @@ -135,11 +136,7 @@ public static async Task<string> GetAvIdAsync(string input) avid = $"ep:{epId}"; } } - else if (input.StartsWith("BV")) - { - avid = await GetAidByBVAsync(input[2..]); - } - else if (input.StartsWith("bv")) + else if (input.ToLower().StartsWith("bv")) { avid = await GetAidByBVAsync(input[2..]); } @@ -154,31 +151,14 @@ public static async Task<string> GetAvIdAsync(string input) } else if (input.StartsWith("ss")) { - string web = await GetWebSourceAsync("https://www.bilibili.com/bangumi/play/" + input); - Regex regex = StateRegex(); - string json = regex.Match(web).Groups[1].Value; - try - { - using var jDoc = JsonDocument.Parse(json); - string epId = jDoc.RootElement.GetProperty("epList").EnumerateArray().First().GetProperty("id").ToString(); - avid = $"ep:{epId}"; - } - catch (JsonException) - { - throw new Exception("输入有误"); - } + string epId = await GetEpIdByBangumiSSIdAsync(input[2..]); + avid = $"ep:{epId}"; } else if (input.StartsWith("md")) { string mdId = MdRegex().Match(input).Groups[1].Value; - try - { - avid = await GetAvIdAsync(await GetSSIdByMDAsync(mdId)); - } - catch (JsonException) - { - throw new Exception("输入有误"); - } + string epId = await GetEpIdByMDAsync(mdId); + avid = $"ep:{epId}"; } else { @@ -209,7 +189,7 @@ public static string FormatTime(int time, bool absolute = false) } /// <summary> - /// 通过avid检测是否为版权内容,如果是的话返回ep:xx格式 + /// 通过avid检测是否为版权内容, 如果是的话返回ep:xx格式 /// </summary> /// <param name="avid"></param> /// <returns></returns> @@ -238,11 +218,31 @@ public static async Task<string> FixAvidAsync(string avid) public static async Task<string> GetAidByBVAsync(string bv) { - string api = $"https://api.bilibili.com/x/web-interface/archive/stat?bvid={bv}"; - string json = await GetWebSourceAsync(api); - using var jDoc = JsonDocument.Parse(json); - string aid = jDoc.RootElement.GetProperty("data").GetProperty("aid").ToString(); - return aid; + if (bv.Length == 10) + { + // 能在本地就在本地 + string TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF"; + var BVChange = new Dictionary<char, byte>(); + byte[] S = { 9, 8, 1, 6, 2, 4 }; + long XOR = 177451812; + long ADD = 8728348608; + for (byte i = 0; i < 58; i++) BVChange.Add(TABLE[i], i); + + long T = 0; + for (byte i = 0; i < 6; i++) + { + T += (long)Math.Pow(58, i) * BVChange[bv[S[i]]]; + } + return ((T - ADD) ^ XOR).ToString(); + } + else + { + string api = $"https://api.bilibili.com/x/web-interface/archive/stat?bvid={bv}"; + string json = await GetWebSourceAsync(api); + using var jDoc = JsonDocument.Parse(json); + string aid = jDoc.RootElement.GetProperty("data").GetProperty("aid").ToString(); + return aid; + } } public static async Task<string> GetEpidBySSIdAsync(string ssid) @@ -254,13 +254,22 @@ public static async Task<string> GetEpidBySSIdAsync(string ssid) return epId; } - public static async Task<string> GetSSIdByMDAsync(string mdId) + public static async Task<string> GetEpIdByBangumiSSIdAsync(string ssId) + { + string api = $"https://{Core.Config.EPHOST}/pgc/view/web/season?season_id={ssId}"; + string json = await GetWebSourceAsync(api); + using var jDoc = JsonDocument.Parse(json); + string epId = jDoc.RootElement.GetProperty("result").GetProperty("episodes").EnumerateArray().First().GetProperty("id").ToString(); + return epId; + } + + public static async Task<string> GetEpIdByMDAsync(string mdId) { - var api = $"https://api.bilibili.com/pgc/review/user?media_id={mdId}"; - var json = await GetWebSourceAsync(api); + string api = $"https://api.bilibili.com/pgc/review/user?media_id={mdId}"; + string json = await GetWebSourceAsync(api); using var jDoc = JsonDocument.Parse(json); - var ssId = "ss" + jDoc.RootElement.GetProperty("result").GetProperty("media").GetProperty("season_id").ToString(); - return ssId; + string epId = jDoc.RootElement.GetProperty("result").GetProperty("media").GetProperty("new_ep").GetProperty("id").ToString(); + return epId; } private static async Task RangeDownloadToTmpAsync(int id, string url, string tmpName, long fromPosition, long? toPosition, Action<int, long, long> onProgress, bool failOnRangeNotSupported = false) @@ -402,7 +411,7 @@ await RangeDownloadToTmpAsync(clip.index, url, tmp, clip.from, clip.to == -1 ? n } catch (NotSupportedException) { - if (++retry == 3) throw new Exception($"服务器可能并不支持多线程下载,请使用 --multi-thread false 关闭多线程"); + if (++retry == 3) throw new Exception($"服务器可能并不支持多线程下载, 请使用 --multi-thread false 关闭多线程"); goto reDown; } catch (Exception) @@ -448,7 +457,7 @@ private static List<Clip> GetAllClips(string url, long fileSize) } /// <summary> - /// 输入一堆已存在的文件,合并到新文件 + /// 输入一堆已存在的文件, 合并到新文件 /// </summary> /// <param name="files"></param> /// <param name="outputFilePath"></param> @@ -564,7 +573,7 @@ public static string GetValidFileName(string input, string re = ".", bool filter /// <summary> - /// 获取url字符串参数,返回参数值字符串 + /// 获取url字符串参数, 返回参数值字符串 /// </summary> /// <param name="name">参数名称</param> /// <param name="url">url字符串</param> @@ -605,22 +614,13 @@ public static string GetSession(string buvid3) public static string GetSign(string parms) { string toEncode = parms + "59b43e04ad6965f34319062b478f83dd"; - byte[] bs = Encoding.UTF8.GetBytes(toEncode); - byte[] hs = MD5.HashData(bs); - StringBuilder sb = new(); - foreach (byte b in hs) - { - sb.Append(b.ToString("x2")); - } - return sb.ToString(); + return string.Concat(MD5.HashData(Encoding.UTF8.GetBytes(toEncode)).Select(i => i.ToString("x2")).ToArray()); } public static string GetTimeStamp(bool bflag) { - TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); - string ret = bflag ? Convert.ToInt64(ts.TotalSeconds).ToString() : Convert.ToInt64(ts.TotalMilliseconds).ToString(); - - return ret; + DateTimeOffset ts = DateTimeOffset.Now; + return bflag ? ts.ToUnixTimeSeconds().ToString() : ts.ToUnixTimeMilliseconds().ToString(); } //https://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings @@ -750,7 +750,7 @@ public static async Task<List<ViewPoint>> FetchPointsAsync(string cid, string ai } /// <summary> - /// 生成metadata文件,用于ffmpeg混流章节信息 + /// 生成metadata文件, 用于ffmpeg混流章节信息 /// </summary> /// <param name="points"></param> /// <returns></returns> @@ -772,7 +772,7 @@ public static string GetFFmpegMetaString(List<ViewPoint> points) } /// <summary> - /// 生成metadata文件,用于mp4box混流章节信息 + /// 生成metadata文件, 用于mp4box混流章节信息 /// </summary> /// <param name="points"></param> /// <returns></returns> @@ -810,17 +810,15 @@ public static async Task<bool> CheckLogin(string cookie) } } - [GeneratedRegex("av(\\d{1,})")] + [GeneratedRegex("av(\\d+)")] private static partial Regex AvRegex(); - [GeneratedRegex("BV(\\w+)")] + [GeneratedRegex("[Bb][Vv](\\w+)")] private static partial Regex BVRegex(); - [GeneratedRegex("bv(\\w+)")] - private static partial Regex BvRegex(); - [GeneratedRegex("/ep(\\d{1,})")] + [GeneratedRegex("/ep(\\d+)")] private static partial Regex EpRegex(); - [GeneratedRegex("/ss(\\d{1,})")] + [GeneratedRegex("/ss(\\d+)")] private static partial Regex SsRegex(); - [GeneratedRegex("space\\.bilibili\\.com/(\\d{1,})")] + [GeneratedRegex("space\\.bilibili\\.com/(\\d+)")] private static partial Regex UidRegex(); [GeneratedRegex("global\\.bilibili\\.com/play/\\d+/(\\d+)")] private static partial Regex GlobalEpRegex(); @@ -828,9 +826,9 @@ public static async Task<bool> CheckLogin(string cookie) private static partial Regex BangumiMdRegex(); [GeneratedRegex("window.__INITIAL_STATE__=([\\s\\S].*?);\\(function\\(\\)")] private static partial Regex StateRegex(); - [GeneratedRegex("ep(\\d{1,})")] + [GeneratedRegex("ep(\\d+)")] private static partial Regex EpRegex2(); - [GeneratedRegex("md(\\d{1,})")] + [GeneratedRegex("md(\\d+)")] private static partial Regex MdRegex(); [GeneratedRegex("^\\d+$")] private static partial Regex NumRegex(); diff --git a/BBDown/CommandLineInvoker.cs b/BBDown/CommandLineInvoker.cs index a800d3e62..47f625104 100644 --- a/BBDown/CommandLineInvoker.cs +++ b/BBDown/CommandLineInvoker.cs @@ -44,6 +44,7 @@ internal class CommandLineInvoker private readonly static Option<string> FFmpegPath = new(new string[] { "--ffmpeg-path" }, "设置ffmpeg的路径"); private readonly static Option<string> Mp4boxPath = new(new string[] { "--mp4box-path" }, "设置mp4box的路径"); private readonly static Option<string> Aria2cPath = new(new string[] { "--aria2c-path" }, "设置aria2c的路径"); + private readonly static Option<string> UposHost = new(new string[] { "--upos-host" }, "自定义upos服务器"); private readonly static Option<string> DelayPerPage = new(new string[] { "--delay-per-page" }, "设置下载合集分P之间的下载间隔时间(单位: 秒, 默认无间隔)"); private readonly static Option<string> FilePattern = new(new string[] { "--file-pattern", "-F" }, $"使用内置变量自定义单P存储文件名:\r\n\r\n" + $"<videoTitle>: 视频主标题\r\n" + $"<pageNumber>: 视频分P序号\r\n" + $"<pageNumberWithZero>: 视频分P序号(前缀补零)\r\n" + $"<pageTitle>: 视频分P标题\r\n" + $"<aid>: 视频aid\r\n" + $"<cid>: 视频cid\r\n" + $"<dfn>: 视频清晰度\r\n" + $"<res>: 视频分辨率\r\n" + $"<fps>: 视频帧率\r\n" + $"<videoCodecs>: 视频编码\r\n" + $"<videoBandwidth>: 视频码率\r\n" + $"<audioCodecs>: 音频编码\r\n" + $"<audioBandwidth>: 音频码率\r\n" + $"<ownerName>: 上传者名称\r\n" + $"<ownerMid>: 上传者mid\r\n\r\n" + $"默认为: {Program.SinglePageDefaultSavePath}\r\n"); private readonly static Option<string> MultiFilePattern = new(new string[] { "--multi-file-pattern", "-M" }, $"使用内置变量自定义多P存储文件名:\r\n\r\n" + $"默认为: {Program.MultiPageDefaultSavePath}\r\n"); @@ -102,6 +103,7 @@ protected override MyOption GetBoundValue(BindingContext bindingContext) if (bindingContext.ParseResult.HasOption(FFmpegPath)) option.FFmpegPath = bindingContext.ParseResult.GetValueForOption(FFmpegPath)!; if (bindingContext.ParseResult.HasOption(Mp4boxPath)) option.Mp4boxPath = bindingContext.ParseResult.GetValueForOption(Mp4boxPath)!; if (bindingContext.ParseResult.HasOption(Aria2cPath)) option.Aria2cPath = bindingContext.ParseResult.GetValueForOption(Aria2cPath)!; + if (bindingContext.ParseResult.HasOption(UposHost)) option.UposHost = bindingContext.ParseResult.GetValueForOption(UposHost)!; if (bindingContext.ParseResult.HasOption(DelayPerPage)) option.DelayPerPage = bindingContext.ParseResult.GetValueForOption(DelayPerPage)!; if (bindingContext.ParseResult.HasOption(Host)) option.Host = bindingContext.ParseResult.GetValueForOption(Host)!; if (bindingContext.ParseResult.HasOption(EpHost)) option.EpHost = bindingContext.ParseResult.GetValueForOption(EpHost)!; @@ -156,6 +158,7 @@ public static RootCommand GetRootCommand(Func<MyOption, Task> action) FFmpegPath, Mp4boxPath, Aria2cPath, + UposHost, DelayPerPage, Host, EpHost, diff --git a/BBDown/MyOption.cs b/BBDown/MyOption.cs index 773e84662..e8629bb2b 100644 --- a/BBDown/MyOption.cs +++ b/BBDown/MyOption.cs @@ -43,6 +43,7 @@ internal class MyOption public string FFmpegPath { get; set; } = ""; public string Mp4boxPath { get; set; } = ""; public string Aria2cPath { get; set; } = ""; + public string UposHost { get; set; } = ""; public string DelayPerPage { get; set; } = "0"; public string Host { get; set; } = "api.bilibili.com"; public string EpHost { get; set; } = "api.bilibili.com"; diff --git a/BBDown/Program.cs b/BBDown/Program.cs index 73c6d58f7..dcf2c7e17 100644 --- a/BBDown/Program.cs +++ b/BBDown/Program.cs @@ -110,7 +110,7 @@ private static async Task DoWorkAsync(MyOption myOption) //兼容旧版本命令行参数并给出警告 if (myOption.AddDfnSubfix) { - LogWarn("--add-dfn-subfix 已被弃用,建议使用 --file-pattern/-F 或 --multi-file-pattern/-M 来自定义输出文件名格式"); + LogWarn("--add-dfn-subfix 已被弃用, 建议使用 --file-pattern/-F 或 --multi-file-pattern/-M 来自定义输出文件名格式"); if (string.IsNullOrEmpty(myOption.FilePattern) && string.IsNullOrEmpty(myOption.MultiFilePattern)) { SinglePageDefaultSavePath += "[<dfn>]"; @@ -120,27 +120,27 @@ private static async Task DoWorkAsync(MyOption myOption) } if (myOption.Aria2cProxy != "") { - LogWarn("--aria2c-proxy 已被弃用,请使用 --aria2c-args 来设置aria2c代理,本次执行已添加该代理"); + LogWarn("--aria2c-proxy 已被弃用, 请使用 --aria2c-args 来设置aria2c代理, 本次执行已添加该代理"); myOption.Aria2cArgs += $" --all-proxy=\"{myOption.Aria2cProxy}\""; } if (myOption.OnlyHevc) { - LogWarn("--only-hevc/-hevc 已被弃用,请使用 --encoding-priority 来设置编码优先级,本次执行已将hevc设置为最高优先级"); + LogWarn("--only-hevc/-hevc 已被弃用, 请使用 --encoding-priority 来设置编码优先级, 本次执行已将hevc设置为最高优先级"); myOption.EncodingPriority = "hevc"; } if (myOption.OnlyAvc) { - LogWarn("--only-avc/-avc 已被弃用,请使用 --encoding-priority 来设置编码优先级,本次执行已将avc设置为最高优先级"); + LogWarn("--only-avc/-avc 已被弃用, 请使用 --encoding-priority 来设置编码优先级, 本次执行已将avc设置为最高优先级"); myOption.EncodingPriority = "avc"; } if (myOption.OnlyAv1) { - LogWarn("--only-av1/-av1 已被弃用,请使用 --encoding-priority 来设置编码优先级,本次执行已将av1设置为最高优先级"); + LogWarn("--only-av1/-av1 已被弃用, 请使用 --encoding-priority 来设置编码优先级, 本次执行已将av1设置为最高优先级"); myOption.EncodingPriority = "av1"; } if (myOption.NoPaddingPageNum) { - LogWarn("--no-padding-page-num 已被弃用,建议使用 --file-pattern/-F 或 --multi-file-pattern/-M 来自定义输出文件名格式"); + LogWarn("--no-padding-page-num 已被弃用, 建议使用 --file-pattern/-F 或 --multi-file-pattern/-M 来自定义输出文件名格式"); if (string.IsNullOrEmpty(myOption.FilePattern) && string.IsNullOrEmpty(myOption.MultiFilePattern)) { MultiPageDefaultSavePath = MultiPageDefaultSavePath.Replace("<pageNumberWithZero>", "<pageNumber>"); @@ -200,6 +200,7 @@ private static async Task DoWorkAsync(MyOption myOption) string savePathFormat = myOption.FilePattern; string lang = myOption.Language; string selectPage = myOption.SelectPage.ToUpper(); + string uposHost = myOption.UposHost; string aidOri = ""; //原始aid int delay = Convert.ToInt32(myOption.DelayPerPage); Config.HOST = myOption.Host; @@ -325,7 +326,7 @@ private static async Task DoWorkAsync(MyOption myOption) Log("获取aid..."); aidOri = await GetAvIdAsync(input); Log("获取aid结束: " + aidOri); - //-p的优先级大于URL中的自带p参数,所以先清空selectedPages + //-p的优先级大于URL中的自带p参数, 所以先清空selectedPages if (!string.IsNullOrEmpty(selectPage) && selectPage != "ALL") { selectedPages = new List<string>(); @@ -420,11 +421,11 @@ private static async Task DoWorkAsync(MyOption myOption) catch { LogError("解析分P参数时失败了~"); selectedPages = null; }; } - //如果用户没有选择分P,根据epid来确定某一集 + //如果用户没有选择分P, 根据epid来确定某一集 if (selectedPages == null && selectPage != "ALL" && !string.IsNullOrEmpty(vInfo.Index)) { selectedPages = new List<string> { vInfo.Index }; - Log("程序已自动选择你输入的集数,如果要下载其他集数请自行指定分P(如可使用-p ALL代表全部)"); + Log("程序已自动选择你输入的集数, 如果要下载其他集数请自行指定分P(如可使用-p ALL代表全部)"); } Log($"共计 {pagesInfo.Count} 个分P, 已选择:" + (selectedPages == null ? "ALL" : string.Join(",", selectedPages))); @@ -436,7 +437,7 @@ private static async Task DoWorkAsync(MyOption myOption) // 根据p数选择存储路径 savePathFormat = string.IsNullOrEmpty(myOption.FilePattern) ? SinglePageDefaultSavePath : myOption.FilePattern; - // 1. 多P; 2. 只有1P,但是是番剧,尚未完结时 按照多P处理 + // 1. 多P; 2. 只有1P, 但是是番剧, 尚未完结时 按照多P处理 if (pagesCount > 1 || (bangumi && !vInfo.IsBangumiEnd)) { savePathFormat = string.IsNullOrEmpty(myOption.MultiFilePattern) ? MultiPageDefaultSavePath : myOption.MultiFilePattern; @@ -538,7 +539,7 @@ private static async Task DoWorkAsync(MyOption myOption) var savePath = ""; - //此处代码简直灾难,后续优化吧 + //此处代码简直灾难, 后续优化吧 if ((videoTracks.Count != 0 || audioTracks.Count != 0) && clips.Count == 0) //dash { if (webJsonStr.Contains("\"video\":[") && videoTracks.Count == 0) @@ -613,31 +614,46 @@ private static async Task DoWorkAsync(MyOption myOption) if (audioTracks.Count > 0) LogColor($"[音频] [{audioTracks[aIndex].codecs}] [{audioTracks[aIndex].bandwith} kbps] [~{FormatFileSize(audioTracks[aIndex].dur * audioTracks[aIndex].bandwith * 1024 / 8)}]", false); - //处理PCDN - var pcdnReg = PcdnRegex(); - if (videoTracks.Count > 0 && pcdnReg.IsMatch(videoTracks[vIndex].baseUrl)) + if (uposHost == "") { - LogWarn($"检测到视频流为PCDN,尝试强制替换为{BACKUP_HOST}……"); - videoTracks[vIndex].baseUrl = pcdnReg.Replace(videoTracks[vIndex].baseUrl, $"://{BACKUP_HOST}/"); - } - - if (audioTracks.Count > 0 && pcdnReg.IsMatch(audioTracks[aIndex].baseUrl)) - { - LogWarn($"检测到音频流为PCDN,尝试强制替换为{BACKUP_HOST}……"); - audioTracks[aIndex].baseUrl = pcdnReg.Replace(audioTracks[aIndex].baseUrl, $"://{BACKUP_HOST}/"); - } + //处理PCDN + var pcdnReg = PcdnRegex(); + if (videoTracks.Count > 0 && pcdnReg.IsMatch(videoTracks[vIndex].baseUrl)) + { + LogWarn($"检测到视频流为PCDN, 尝试强制替换为{BACKUP_HOST}……"); + videoTracks[vIndex].baseUrl = pcdnReg.Replace(videoTracks[vIndex].baseUrl, $"://{BACKUP_HOST}/"); + } + if (audioTracks.Count > 0 && pcdnReg.IsMatch(audioTracks[aIndex].baseUrl)) + { + LogWarn($"检测到音频流为PCDN, 尝试强制替换为{BACKUP_HOST}……"); + audioTracks[aIndex].baseUrl = pcdnReg.Replace(audioTracks[aIndex].baseUrl, $"://{BACKUP_HOST}/"); + } - var akamReg = AkamRegex(); - if (videoTracks.Count > 0 && Config.AREA != "" && videoTracks[vIndex].baseUrl.Contains("akamaized.net")) - { - LogWarn($"检测到视频流为外国源,尝试强制替换为{BACKUP_HOST}……"); - videoTracks[vIndex].baseUrl = akamReg.Replace(videoTracks[vIndex].baseUrl, $"://{BACKUP_HOST}/"); + var akamReg = AkamRegex(); + if (videoTracks.Count > 0 && Config.AREA != "" && videoTracks[vIndex].baseUrl.Contains("akamaized.net")) + { + LogWarn($"检测到视频流为外国源, 尝试强制替换为{BACKUP_HOST}……"); + videoTracks[vIndex].baseUrl = akamReg.Replace(videoTracks[vIndex].baseUrl, $"://{BACKUP_HOST}/"); + } + if (audioTracks.Count > 0 && Config.AREA != "" && audioTracks[aIndex].baseUrl.Contains("akamaized.net")) + { + LogWarn($"检测到音频流为外国源, 尝试强制替换为{BACKUP_HOST}……"); + audioTracks[aIndex].baseUrl = akamReg.Replace(audioTracks[aIndex].baseUrl, $"://{BACKUP_HOST}/"); + } } - - if (audioTracks.Count > 0 && Config.AREA != "" && audioTracks[aIndex].baseUrl.Contains("akamaized.net")) + else { - LogWarn($"检测到音频流为外国源,尝试强制替换为{BACKUP_HOST}……"); - audioTracks[aIndex].baseUrl = akamReg.Replace(audioTracks[aIndex].baseUrl, $"://{BACKUP_HOST}/"); + var uposReg = UposRegex(); + if (videoTracks.Count > 0) + { + Log($"尝试将视频流强制替换为{uposHost}……"); + videoTracks[vIndex].baseUrl = uposReg.Replace(videoTracks[vIndex].baseUrl, $"://{uposHost}/"); + } + if (audioTracks.Count > 0) + { + Log($"尝试将音频流强制替换为{uposHost}……"); + audioTracks[aIndex].baseUrl = uposReg.Replace(audioTracks[aIndex].baseUrl, $"://{uposHost}/"); + } } LogDebug("Format Before: " + savePathFormat); @@ -678,7 +694,7 @@ private static async Task DoWorkAsync(MyOption myOption) continue; } - //杜比视界,若ffmpeg版本小于5.0,使用mp4box封装 + //杜比视界, 若ffmpeg版本小于5.0, 使用mp4box封装 if (videoTracks[vIndex].dfn == Config.qualitys["126"] && !useMp4box && !CheckFFmpegDOVI()) { LogWarn($"检测到杜比视界清晰度且您的ffmpeg版本小于5.0,将使用mp4box混流..."); @@ -873,11 +889,11 @@ private static async Task DoWorkAsync(MyOption myOption) { if (webJsonStr.Contains("平台不可观看")) { - throw new Exception("当前(WEB)平台不可观看,请尝试使用TV API解析。"); + throw new Exception("当前(WEB)平台不可观看, 请尝试使用TV API解析。"); } else if (webJsonStr.Contains("地区不可观看") || webJsonStr.Contains("地区不支持")) { - throw new Exception("当前地区不可观看,尝试设置系统代理后解析。"); + throw new Exception("当前地区不可观看, 尝试设置系统代理后解析。"); } else if (webJsonStr.Contains("购买后才能观看")) { @@ -916,7 +932,7 @@ private static async Task DoWorkAsync(MyOption myOption) private static List<Video> SortTracks(List<Video> videoTracks, Dictionary<string, int> dfnPriority, Dictionary<string, byte> encodingPriority, bool bandwithAscending) { - //用户同时输入了自定义分辨率优先级和自定义编码优先级,则根据输入顺序依次进行排序 + //用户同时输入了自定义分辨率优先级和自定义编码优先级, 则根据输入顺序依次进行排序 return dfnPriority.Count > 0 && encodingPriority.Count > 0 && Environment.CommandLine.IndexOf("--encoding-priority") < Environment.CommandLine.IndexOf("--dfn-priority") ? videoTracks .OrderBy(v => encodingPriority.TryGetValue(v.codecs, out byte i) ? i : 100) @@ -1077,6 +1093,8 @@ private static async Task LoginTV() private static partial Regex PcdnRegex(); [GeneratedRegex("://.*akamaized\\.net/")] private static partial Regex AkamRegex(); + [GeneratedRegex("://[^/]+/")] + private static partial Regex UposRegex(); [GeneratedRegex("<(\\w+?)>")] private static partial Regex InfoRegex(); } From 3cb326ec1ca7b35337847ca52c5f97dbb65e4af6 Mon Sep 17 00:00:00 2001 From: My-Responsitories <email.youxiang.alpha@gmail.com> Date: Fri, 16 Dec 2022 13:32:11 +0800 Subject: [PATCH 2/2] edit '-intl' help information --- BBDown/CommandLineInvoker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BBDown/CommandLineInvoker.cs b/BBDown/CommandLineInvoker.cs index 47f625104..1e0df8d7e 100644 --- a/BBDown/CommandLineInvoker.cs +++ b/BBDown/CommandLineInvoker.cs @@ -14,7 +14,7 @@ internal class CommandLineInvoker private readonly static Argument<string> Url = new("url", description: "视频地址 或 av|bv|BV|ep|ss"); private readonly static Option<bool> UseTvApi = new(new string[] { "--use-tv-api", "-tv" }, "使用TV端解析模式"); private readonly static Option<bool> UseAppApi = new(new string[] { "--use-app-api", "-app" }, "使用APP端解析模式"); - private readonly static Option<bool> UseIntlApi = new(new string[] { "--use-intl-api", "-intl" }, "使用国际版解析模式"); + private readonly static Option<bool> UseIntlApi = new(new string[] { "--use-intl-api", "-intl" }, "使用国际版(东南亚视频)解析模式"); private readonly static Option<bool> UseMP4box = new(new string[] { "--use-mp4box" }, "使用MP4Box来混流"); private readonly static Option<string> EncodingPriority = new(new string[] { "--encoding-priority" }, "视频编码的选择优先级, 用逗号分割 例: \"hevc,av1,avc\""); private readonly static Option<string> DfnPriority = new(new string[] { "--dfn-priority" }, "画质优先级,用逗号分隔 例: \"8K 超高清, 1080P 高码率, HDR 真彩, 杜比视界\"");