diff --git a/BBDown.Core/Config.cs b/BBDown.Core/Config.cs index 7fadd6f04..b75e11626 100644 --- a/BBDown.Core/Config.cs +++ b/BBDown.Core/Config.cs @@ -15,6 +15,8 @@ public class Config //BiliPlus Area public static string AREA { get; set; } = ""; + public static string WBI { get; set; } = ""; + public static readonly Dictionary qualitys = new() { {"127","8K 超高清" }, {"126","杜比视界" }, {"125","HDR 真彩" }, {"120","4K 超清" }, {"116","1080P 高帧率" }, {"112","1080P 高码率" }, {"80","1080P 高清" }, {"74","720P 高帧率" }, diff --git a/BBDown.Core/Fetcher/SpaceVideoFetcher.cs b/BBDown.Core/Fetcher/SpaceVideoFetcher.cs index 5a60e9a1e..5c4bb8c79 100644 --- a/BBDown.Core/Fetcher/SpaceVideoFetcher.cs +++ b/BBDown.Core/Fetcher/SpaceVideoFetcher.cs @@ -1,6 +1,5 @@ using BBDown.Core.Entity; using System; -using System.Security.Cryptography; using System.Text; using System.Text.Json; using static BBDown.Core.Util.HTTPUtil; @@ -10,24 +9,16 @@ namespace BBDown.Core.Fetcher { public class SpaceVideoFetcher : IFetcher { - public static string WbiSign(string api, string wbi) - { - return $"{api}&w_rid=" + string.Concat(MD5.HashData(Encoding.UTF8.GetBytes(api + wbi)).Select(i => i.ToString("x2")).ToArray()); - } - public async Task FetchAsync(string id) { id = id[4..]; - string[] tmp = id.Split("|"); - id = tmp[0]; - var wbi = tmp[1]; // using the live API can bypass w_rid string userInfoApi = $"https://api.live.bilibili.com/live_user/v1/Master/info?uid={id}"; string userName = GetValidFileName(JsonDocument.Parse(await GetWebSourceAsync(userInfoApi)).RootElement.GetProperty("data").GetProperty("info").GetProperty("uname").ToString(), ".", true); List urls = new(); int pageSize = 50; int pageNumber = 1; - var api = WbiSign($"mid={id}&order=pubdate&pn={pageNumber}&ps={pageSize}&tid=0&wts={DateTimeOffset.Now.ToUnixTimeSeconds().ToString()}", wbi); + var api = Parser.WbiSign($"mid={id}&order=pubdate&pn={pageNumber}&ps={pageSize}&tid=0&wts={DateTimeOffset.Now.ToUnixTimeSeconds().ToString()}"); api = $"https://api.bilibili.com/x/space/wbi/arc/search?{api}"; string json = await GetWebSourceAsync(api); var infoJson = JsonDocument.Parse(json); @@ -41,7 +32,7 @@ public async Task FetchAsync(string id) while (pageNumber < totalPage) { pageNumber++; - urls.AddRange(await GetVideosByPageAsync(pageNumber, pageSize, id, wbi)); + urls.AddRange(await GetVideosByPageAsync(pageNumber, pageSize, id)); } File.WriteAllText($"{userName}的投稿视频.txt", string.Join('\n', urls)); Log("目前下载器不支持下载用户的全部投稿视频,不过程序已经获取到了该用户的全部投稿视频地址,你可以自行使用批处理脚本等手段调用本程序进行批量下载。如在Windows系统你可以使用如下代码:"); @@ -53,10 +44,10 @@ public async Task FetchAsync(string id) throw new Exception("暂不支持该功能"); } - static async Task> GetVideosByPageAsync(int pageNumber, int pageSize, string mid, string wbi) + static async Task> GetVideosByPageAsync(int pageNumber, int pageSize, string mid) { List urls = new(); - var api = WbiSign($"mid={mid}&order=pubdate&pn={pageNumber}&ps={pageSize}&tid=0&wts={DateTimeOffset.Now.ToUnixTimeSeconds().ToString()}", wbi); + var api = Parser.WbiSign($"mid={mid}&order=pubdate&pn={pageNumber}&ps={pageSize}&tid=0&wts={DateTimeOffset.Now.ToUnixTimeSeconds().ToString()}"); api = $"https://api.bilibili.com/x/space/wbi/arc/search?{api}"; string json = await GetWebSourceAsync(api); var infoJson = JsonDocument.Parse(json); diff --git a/BBDown.Core/Parser.cs b/BBDown.Core/Parser.cs index 97276e30e..90caacab3 100644 --- a/BBDown.Core/Parser.cs +++ b/BBDown.Core/Parser.cs @@ -10,6 +10,11 @@ namespace BBDown.Core { public partial class Parser { + public static string WbiSign(string api) + { + return $"{api}&w_rid=" + string.Concat(MD5.HashData(Encoding.UTF8.GetBytes(api + Config.WBI)).Select(i => i.ToString("x2")).ToArray()); + } + private static async Task GetPlayJsonAsync(bool onlyAvc, string aidOri, string aid, string cid, string epId, bool tvApi, bool intl, bool appApi, string qn = "0") { LogDebug("aid={0},cid={1},epId={2},tvApi={3},IntlApi={4},appApi={5},qn={6}", aid, cid, epId, tvApi, intl, appApi, qn); @@ -24,13 +29,14 @@ private static async Task GetPlayJsonAsync(bool onlyAvc, string aidOri, if (appApi) return await AppHelper.DoReqAsync(aid, cid, epId, qn, bangumi, onlyAvc, Config.TOKEN); string prefix = tvApi ? bangumi ? "api.snm0516.aisee.tv/pgc/player/api/playurltv" : "api.snm0516.aisee.tv/x/tv/ugc/playurl" - : bangumi ? $"{Config.HOST}/pgc/player/web/playurl" : $"{Config.HOST}/x/player/playurl"; - string api = $"https://{prefix}?avid={aid}&cid={cid}&qn={qn}&type=&otype=json" + (tvApi ? "" : "&fourk=1") + - $"&fnver=0&fnval=4048" + (Config.AREA != "" ? Config.TOKEN != "" ? $"&access_key={Config.TOKEN}&area={Config.AREA}" : $"&area={Config.AREA}" : "") + - (tvApi ? "&device=android&platform=android" + - "&mobi_app=android_tv_yst&npcybs=0&force_host=2&build=102801" + - (Config.TOKEN != "" ? $"&access_key={Config.TOKEN}" : "") : "") + - (bangumi ? $"&module=bangumi&ep_id={epId}&fourk=1" + "&session=" : ""); + : bangumi ? $"{Config.HOST}/pgc/player/web/playurl" : "api.bilibili.com/x/player/wbi/playurl"; + + string api = $"avid={aid}&cid={cid}&fnval=4048&fnver=0" + + (tvApi ? "" : "&fourk=1") + (Config.AREA != "" ? Config.TOKEN != "" ? $"&access_key={Config.TOKEN}&area={Config.AREA}" : $"&area={Config.AREA}" : "") + + (tvApi ? "&device=android&platform=android&mobi_app=android_tv_yst&npcybs=0&force_host=2&build=102801" + + (Config.TOKEN != "" ? $"&access_key={Config.TOKEN}" : "") : "") + $"&otype=json&qn={qn}" + + (bangumi ? $"&module=bangumi&ep_id={epId}&fourk=1&session=" : $"&try_look=1&wts={GetTimeStamp(true)}"); + api = $"https://{prefix}?{(bangumi ? api : WbiSign(api))}"; if (tvApi && bangumi) { api = (Config.TOKEN != "" ? $"access_key={Config.TOKEN}&" : "") + @@ -79,6 +85,12 @@ private static async Task GetPlayJsonAsync(string aid, string cid, strin return webJson; } + public static string SkiPcdn(List urlList, string baseUrl) + { + urlList.Add(baseUrl); + return urlList.FirstOrDefault(i => !PcdnRegex().IsMatch(i), urlList.First()); + } + public static async Task<(string, List