diff --git a/src/DownKyi.Core/BiliApi/Sign/WbiSign.cs b/src/DownKyi.Core/BiliApi/Sign/WbiSign.cs new file mode 100644 index 0000000..4d584dc --- /dev/null +++ b/src/DownKyi.Core/BiliApi/Sign/WbiSign.cs @@ -0,0 +1,120 @@ +using DownKyi.Core.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace DownKyi.Core.BiliApi.Sign +{ + public static class WbiSign + { + + /// + /// 打乱重排实时口令 + /// + /// + /// + private static string GetMixinKey(string origin) + { + int[] mixinKeyEncTab = new int[] + { + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39,12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 + }; + + var temp = new StringBuilder(); + foreach (var i in mixinKeyEncTab) + { + temp.Append(origin[i]); + } + return temp.ToString().Substring(0, 32); + } + + /// + /// 将字典参数转为字符串 + /// + /// + /// + public static string ParametersToQuery(Dictionary parameters) + { + var keys = parameters.Keys.ToList(); + var queryList = new List(); + foreach (var item in keys) + { + var value = parameters[item]; + queryList.Add($"{item}={value}"); + } + return string.Join("&", queryList); + } + + /// + /// Wbi签名,返回所有参数字典 + /// + /// + /// + public static Dictionary EncodeWbi(Dictionary parameters) + { + return EncodeWbi(parameters, GetKey().Item1, GetKey().Item2); + } + + /// + /// Wbi签名,返回所有参数字典 + /// + /// + /// + /// + /// + public static Dictionary EncodeWbi(Dictionary parameters, string imgKey, string subKey) + { + var mixinKey = GetMixinKey(imgKey + subKey); + + var chrFilter = new Regex("[!'()*]"); + + var newParameters = new Dictionary + { + { "wts", (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds } + }; + + foreach (var para in parameters) + { + var key = para.Key; + var value = para.Value.ToString(); + + var encodedValue = chrFilter.Replace(value, ""); + + newParameters.Add(Uri.EscapeDataString(key), Uri.EscapeDataString(encodedValue)); + } + + var keys = newParameters.Keys.ToList(); + keys.Sort(); + + var queryList = new List(); + foreach (var item in keys) + { + var value = newParameters[item]; + queryList.Add($"{item}={value}"); + } + + var queryString = string.Join("&", queryList); + var md5Hasher = MD5.Create(); + var hashStr = queryString + mixinKey; + var hashedQueryString = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(hashStr)); + var wbiSign = BitConverter.ToString(hashedQueryString).Replace("-", "").ToLower(); + + newParameters.Add("w_rid", wbiSign); + return newParameters; + } + + public static Tuple GetKey() + { + var user = SettingsManager.GetInstance().GetUserInfo(); + + return new Tuple(user.ImgKey, user.SubKey); + } + + } +} \ No newline at end of file diff --git a/src/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs b/src/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs index 0801dd3..d1256dc 100644 --- a/src/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs +++ b/src/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs @@ -53,6 +53,9 @@ namespace DownKyi.Core.BiliApi.Users.Models //public int vip_theme_type { get; set; } [JsonProperty("wallet")] public UserInfoWallet Wallet { get; set; } + + [JsonProperty("wbi_img")] + public Wbi Wbi { get; set; } } //public class NavDataLevelInfo @@ -105,4 +108,14 @@ namespace DownKyi.Core.BiliApi.Users.Models [JsonProperty("mid")] public long Mid { get; set; } } + + [JsonObject] + public class Wbi + { + [JsonProperty("img_url")] + public string ImgUrl { get; set; } + [JsonProperty("sub_url")] + public string SubUrl { get; set; } + } + } diff --git a/src/DownKyi.Core/BiliApi/Users/UserInfo.cs b/src/DownKyi.Core/BiliApi/Users/UserInfo.cs index 175f1e3..d6d1a21 100644 --- a/src/DownKyi.Core/BiliApi/Users/UserInfo.cs +++ b/src/DownKyi.Core/BiliApi/Users/UserInfo.cs @@ -1,7 +1,9 @@ -using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.Users.Models; using DownKyi.Core.Logging; using Newtonsoft.Json; using System; +using System.Collections.Generic; namespace DownKyi.Core.BiliApi.Users { @@ -43,7 +45,12 @@ namespace DownKyi.Core.BiliApi.Users /// public static UserInfoForSpace GetUserInfoForSpace(long mid) { - string url = $"https://api.bilibili.com/x/space/wbi/acc/info?mid={mid}"; + var parameters = new Dictionary + { + { "mid", mid } + }; + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/space/wbi/acc/info?{query}"; string referer = "https://www.bilibili.com"; string response = WebClient.RequestWeb(url, referer); diff --git a/src/DownKyi.Core/BiliApi/Users/UserSpace.cs b/src/DownKyi.Core/BiliApi/Users/UserSpace.cs index c76af60..4072cf1 100644 --- a/src/DownKyi.Core/BiliApi/Users/UserSpace.cs +++ b/src/DownKyi.Core/BiliApi/Users/UserSpace.cs @@ -1,4 +1,5 @@ -using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.Users.Models; using DownKyi.Core.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -114,7 +115,17 @@ namespace DownKyi.Core.BiliApi.Users /// public static SpacePublicationList GetPublication(long mid, int pn, int ps, long tid = 0, PublicationOrder order = PublicationOrder.PUBDATE, string keyword = "") { - string url = $"https://api.bilibili.com/x/space/wbi/arc/search?mid={mid}&pn={pn}&ps={ps}&order={order.ToString("G").ToLower()}&tid={tid}&keyword={keyword}"; + var parameters = new Dictionary + { + { "mid", mid }, + { "pn", pn }, + { "ps", ps }, + { "order", order.ToString("G").ToLower() }, + { "tid", tid }, + { "keyword", keyword }, + }; + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/space/wbi/arc/search?{query}"; string referer = "https://www.bilibili.com"; string response = WebClient.RequestWeb(url, referer); diff --git a/src/DownKyi.Core/DownKyi.Core.csproj b/src/DownKyi.Core/DownKyi.Core.csproj index c919ea6..2a9a3fb 100644 --- a/src/DownKyi.Core/DownKyi.Core.csproj +++ b/src/DownKyi.Core/DownKyi.Core.csproj @@ -186,6 +186,7 @@ + diff --git a/src/DownKyi.Core/Settings/Models/UserInfoSettings.cs b/src/DownKyi.Core/Settings/Models/UserInfoSettings.cs index 774b7ec..63debc7 100644 --- a/src/DownKyi.Core/Settings/Models/UserInfoSettings.cs +++ b/src/DownKyi.Core/Settings/Models/UserInfoSettings.cs @@ -6,5 +6,8 @@ public string Name { get; set; } public bool IsLogin { get; set; } // 是否登录 public bool IsVip { get; set; } // 是否为大会员,未登录时为false + + public string ImgKey { get; set; } + public string SubKey { get; set; } } } diff --git a/src/DownKyi/Languages/Default.xaml b/src/DownKyi/Languages/Default.xaml index b6ca780..19cebae 100644 --- a/src/DownKyi/Languages/Default.xaml +++ b/src/DownKyi/Languages/Default.xaml @@ -200,7 +200,7 @@ 启用https(若下载器提示SSL错误,则关闭此项) UserAgent: 选择下载器(重启生效): - 内建下载器(测试) + 内建下载器 Aria2下载器 自定义Aria2下载器 Aria服务器地址: diff --git a/src/DownKyi/Services/Download/DownloadService.cs b/src/DownKyi/Services/Download/DownloadService.cs index acea7a1..c6297bc 100644 --- a/src/DownKyi/Services/Download/DownloadService.cs +++ b/src/DownKyi/Services/Download/DownloadService.cs @@ -20,14 +20,13 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using System.Windows; namespace DownKyi.Services.Download { public abstract class DownloadService { protected string Tag = "DownloadService"; - protected TaskbarIcon _notifyIcon; + protected TaskbarIcon _notifyIcon; protected IDialogService dialogService; protected ObservableCollection downloadingList; protected ObservableCollection downloadedList; diff --git a/src/DownKyi/ViewModels/ViewIndexViewModel.cs b/src/DownKyi/ViewModels/ViewIndexViewModel.cs index 9eaeb10..37aff24 100644 --- a/src/DownKyi/ViewModels/ViewIndexViewModel.cs +++ b/src/DownKyi/ViewModels/ViewIndexViewModel.cs @@ -1,4 +1,5 @@ using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; using DownKyi.Core.Logging; using DownKyi.Core.Settings; using DownKyi.Core.Settings.Models; @@ -12,6 +13,7 @@ using Prism.Regions; using Prism.Services.Dialogs; using System; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; @@ -227,6 +229,36 @@ namespace DownKyi.ViewModels InputText = string.Empty; } + private UserInfoForNavigation GetUserInfo() + { + // 获取用户信息 + var userInfo = UserInfo.GetUserInfoForNavigation(); + if (userInfo != null) + { + SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings + { + Mid = userInfo.Mid, + Name = userInfo.Name, + IsLogin = userInfo.IsLogin, + IsVip = userInfo.VipStatus == 1, + ImgKey = userInfo.Wbi.ImgUrl.Split('/').ToList().Last().Split('.')[0], + SubKey = userInfo.Wbi.SubUrl.Split('/').ToList().Last().Split('.')[0], + }); + } + else + { + SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings + { + Mid = -1, + Name = "", + IsLogin = false, + IsVip = false, + }); + } + + return userInfo; + } + /// /// 更新用户登录信息 /// @@ -248,27 +280,7 @@ namespace DownKyi.ViewModels await Task.Run(new Action(() => { // 获取用户信息 - var userInfo = UserInfo.GetUserInfoForNavigation(); - if (userInfo != null) - { - SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings - { - Mid = userInfo.Mid, - Name = userInfo.Name, - IsLogin = userInfo.IsLogin, - IsVip = userInfo.VipStatus == 1 - }); - } - else - { - SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings - { - Mid = -1, - Name = "", - IsLogin = false, - IsVip = false - }); - } + var userInfo = GetUserInfo(); PropertyChangeAsync(new Action(() => { @@ -318,21 +330,27 @@ namespace DownKyi.ViewModels { return; } + // 启动 if (parameter == "start") { UpdateUserInfo(); } // 从登录页面返回 - if (parameter == "login") + else if (parameter == "login") { UpdateUserInfo(); } // 注销 - if (parameter == "logout") + else if (parameter == "logout") { UpdateUserInfo(); } + // 其他情况只更新设置的用户信息,不更新UI + else + { + GetUserInfo(); + } }