diff --git a/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml b/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml
new file mode 100644
index 000000000..e40048d1c
--- /dev/null
+++ b/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml
@@ -0,0 +1,421 @@
+
+
+
+
+ 极验
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj
index 766c06eba..cd3bc778b 100644
--- a/src/BiliLite.UWP/BiliLite.UWP.csproj
+++ b/src/BiliLite.UWP/BiliLite.UWP.csproj
@@ -136,6 +136,12 @@
PackageReference
+
+ AttentionButton.xaml
+
+
+ UserFollowingTagsFlyout.xaml
+
@@ -187,6 +193,9 @@
+
+
+
@@ -196,6 +205,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -628,7 +647,7 @@
-
+
@@ -876,6 +895,7 @@
+
Designer
@@ -895,6 +915,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -903,6 +927,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/src/BiliLite.UWP/Controls/AttentionButton.xaml b/src/BiliLite.UWP/Controls/AttentionButton.xaml
new file mode 100644
index 000000000..371a056b2
--- /dev/null
+++ b/src/BiliLite.UWP/Controls/AttentionButton.xaml
@@ -0,0 +1,35 @@
+
+
+
+ 设置分组
+ 取消关注
+
+
+
+
+
+
+
+
diff --git a/src/BiliLite.UWP/Controls/AttentionButton.xaml.cs b/src/BiliLite.UWP/Controls/AttentionButton.xaml.cs
new file mode 100644
index 000000000..df1f09e0a
--- /dev/null
+++ b/src/BiliLite.UWP/Controls/AttentionButton.xaml.cs
@@ -0,0 +1,61 @@
+using System.Threading.Tasks;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using BiliLite.ViewModels.User;
+using Microsoft.Extensions.DependencyInjection;
+
+//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板
+
+namespace BiliLite.Controls
+{
+ public sealed partial class AttentionButton : UserControl
+ {
+ private readonly UserAttentionButtonViewModel m_viewModel;
+
+ public AttentionButton()
+ {
+ m_viewModel = App.ServiceProvider.GetRequiredService();
+ this.InitializeComponent();
+ }
+
+ public static readonly DependencyProperty AttentionProperty =
+ DependencyProperty.Register(nameof(Attention), typeof(int), typeof(AttentionButton), new PropertyMetadata(0));
+
+ public int Attention
+ {
+ get => m_viewModel.Attention;
+ set => m_viewModel.Attention = value;
+ }
+
+ public static readonly DependencyProperty UserIdProperty =
+ DependencyProperty.Register(nameof(Attention), typeof(string), typeof(AttentionButton), new PropertyMetadata(default(string)));
+
+ public string UserId
+ {
+ get => m_viewModel.UserId;
+ set => m_viewModel.UserId = value;
+ }
+
+ public async Task AttentionUp()
+ {
+ await m_viewModel.AttentionUP(m_viewModel.UserId, 1);
+ }
+
+ private void AttendedBtn_OnClick(object sender, RoutedEventArgs e)
+ {
+ var flyoutShowOptions = new FlyoutShowOptions()
+ {
+ Placement = FlyoutPlacementMode.Bottom
+ };
+ AttentionFlyout.ShowAt(sender as DependencyObject, flyoutShowOptions);
+ }
+
+ private async void SetFollowingTag_OnClick(object sender, RoutedEventArgs e)
+ {
+ if(!UserFollowingTagsFlyout.HasInit)
+ await UserFollowingTagsFlyout.Init(m_viewModel.UserId);
+ UserFollowingTagsFlyout.ShowAt(AttendedBtn);
+ }
+ }
+}
diff --git a/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml b/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml
new file mode 100644
index 000000000..ef4cfc932
--- /dev/null
+++ b/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml.cs b/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml.cs
new file mode 100644
index 000000000..bb8d29fab
--- /dev/null
+++ b/src/BiliLite.UWP/Controls/UserFollowingTagsFlyout.xaml.cs
@@ -0,0 +1,49 @@
+using System.Threading.Tasks;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using BiliLite.ViewModels.User;
+using Microsoft.Extensions.DependencyInjection;
+
+//https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板
+
+namespace BiliLite.Controls
+{
+ public sealed partial class UserFollowingTagsFlyout : UserControl
+ {
+ private readonly UserFollowingTagsFlyoutViewModel m_viewModel;
+
+ public UserFollowingTagsFlyout()
+ {
+ m_viewModel = App.ServiceProvider.GetRequiredService();
+ this.InitializeComponent();
+ }
+
+ public bool HasInit { get; set; }
+
+ private void FollowingTagFlyout_OnClosed(object sender, object e)
+ {
+ m_viewModel.CancelSaveFollowingTagUser();
+ }
+
+ private async void SaveFollowingTagUser_OnClick(object sender, RoutedEventArgs e)
+ {
+ await m_viewModel.SaveFollowingTagUser();
+ FollowingTagFlyout.Hide();
+ }
+
+ public async Task Init(string userId)
+ {
+ await m_viewModel.Init(userId);
+ HasInit = true;
+ }
+
+ public void ShowAt(DependencyObject target)
+ {
+ ContextFlyout.ShowAt(target, new FlyoutShowOptions()
+ {
+ Placement = FlyoutPlacementMode.Bottom
+ });
+ }
+ }
+}
diff --git a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml
index 704b7fd99..3ec5d79fe 100644
--- a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml
+++ b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml
@@ -10,6 +10,7 @@
PrimaryButtonText="登录"
SecondaryButtonText="取消"
xmlns:user="using:BiliLite.Modules.User"
+ xmlns:controls="using:Microsoft.UI.Xaml.Controls"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
IsPrimaryButtonEnabled="{x:Bind Path=loginVM.PrimaryButtonEnable,Mode=OneWay}"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
@@ -142,7 +143,7 @@
-
+
diff --git a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs
index db76c2887..be3192d60 100644
--- a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs
+++ b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs
@@ -5,8 +5,12 @@
using Newtonsoft.Json.Linq;
using System;
using System.Text.RegularExpressions;
+using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.Web.WebView2.Core;
+using Windows.Storage;
// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板
@@ -50,9 +54,17 @@ private void _biliapp_ValidateLoginEvent(object sender, string e)
loginVM.ValidateLogin(JObject.Parse(e));
}
- private void LoginVM_OpenWebView(object sender, Uri e)
+
+ private async void LoginVM_OpenWebView(object sender, Uri e)
{
- webView.Source = e;
+ await InitWebView2();
+ var templateText = await FileIO.ReadTextAsync(
+ await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/GeeTest/bili_gt.cshtml")));
+
+ var result = templateText.Replace("@Model.Url", e.AbsoluteUri);
+
+ //webView.Source = e;
+ webView.NavigateToString(result);
}
private void SMSLoginDialog_Loaded(object sender, RoutedEventArgs e)
@@ -77,6 +89,11 @@ private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDia
}
+ private async Task InitWebView2()
+ {
+ await webView.EnsureCoreWebView2Async();
+ }
+
private void txt_Password_GotFocus(object sender, RoutedEventArgs e)
{
@@ -88,20 +105,20 @@ private void txt_Password_LostFocus(object sender, RoutedEventArgs e)
hide.Visibility = Visibility.Collapsed;
}
- private async void webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
+ private async void WebView_OnNavigationStarting(WebView2 sender, CoreWebView2NavigationStartingEventArgs args)
{
- if (args.Uri.AbsoluteUri.Contains("access_key="))
+ if (args.Uri.Contains("access_key="))
{
- var access = Regex.Match(args.Uri.AbsoluteUri, "access_key=(.*?)&").Groups[1].Value;
- var mid = Regex.Match(args.Uri.AbsoluteUri, "mid=(.*?)&").Groups[1].Value;
+ var access = Regex.Match(args.Uri, "access_key=(.*?)&").Groups[1].Value;
+ var mid = Regex.Match(args.Uri, "mid=(.*?)&").Groups[1].Value;
var appKey = SettingConstants.Account.DefaultLoginAppKeySecret;
await loginVM.account.SaveLogin(access, "", 0, long.Parse(mid), null, null, appKey);
this.Hide();
return;
}
- if (args.Uri.AbsoluteUri.Contains("geetest.result"))
+ if (args.Uri.Contains("geetest.result"))
{
- var success = (Regex.Match(args.Uri.AbsoluteUri, @"success=(\d)&").Groups[1].Value).ToInt32();
+ var success = (Regex.Match(args.Uri, @"success=(\d)&").Groups[1].Value).ToInt32();
if (success == 0)
{
//验证失败
@@ -112,10 +129,10 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS
{
webView.Visibility = Visibility.Collapsed;
//验证成功
- var challenge = Regex.Match(args.Uri.AbsoluteUri, "geetest_challenge=(.*?)&").Groups[1].Value;
- var validate = Regex.Match(args.Uri.AbsoluteUri, "geetest_validate=(.*?)&").Groups[1].Value;
- var seccode = Regex.Match(args.Uri.AbsoluteUri, "geetest_seccode=(.*?)&").Groups[1].Value;
- var recaptcha_token = Regex.Match(args.Uri.AbsoluteUri, "recaptcha_token=(.*?)&").Groups[1].Value;
+ var challenge = Regex.Match(args.Uri, "geetest_challenge=(.*?)&").Groups[1].Value;
+ var validate = Regex.Match(args.Uri, "geetest_validate=(.*?)&").Groups[1].Value;
+ var seccode = Regex.Match(args.Uri, "geetest_seccode=(.*?)&").Groups[1].Value;
+ var recaptcha_token = Regex.Match(args.Uri, "recaptcha_token=(.*?)&").Groups[1].Value;
loginVM.HandleGeetestSuccess(seccode, validate, challenge, recaptcha_token);
}
else if (success == 2)
@@ -129,8 +146,8 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS
}
try
{
- this.webView.AddWebAllowedObject("biliapp", _biliapp);
- this.webView.AddWebAllowedObject("secure", _secure);
+ //this.webView.AddWebAllowedObject("biliapp", _biliapp);
+ //this.webView.AddWebAllowedObject("secure", _secure);
}
catch (Exception ex)
{
@@ -138,15 +155,15 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS
}
}
- private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
+ private async void WebView_OnNavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
{
- if (args.Uri.AbsoluteUri == "https://passport.bilibili.com/ajax/miniLogin/redirect" || args.Uri.AbsoluteUri == "https://www.bilibili.com/")
+ if (sender.Source.AbsoluteUri == "https://passport.bilibili.com/ajax/miniLogin/redirect" || sender.Source.AbsoluteUri == "https://www.bilibili.com/")
{
var results = await $"https://passport.bilibili.com/login/app/third?appkey=&api=http%3A%2F%2Flink.acg.tv%2Fforum.php&sign=67ec798004373253d60114caaad89a8c".GetString();
var obj = JObject.Parse(results);
if (obj["code"].ToInt32() == 0)
{
- webView.Navigate(new Uri(obj["data"]["confirm_uri"].ToString()));
+ webView.Source = new Uri(obj["data"]["confirm_uri"].ToString());
}
else
{
diff --git a/src/BiliLite.UWP/Extensions/MapperExtensions.cs b/src/BiliLite.UWP/Extensions/MapperExtensions.cs
index f447c710e..117495c1f 100644
--- a/src/BiliLite.UWP/Extensions/MapperExtensions.cs
+++ b/src/BiliLite.UWP/Extensions/MapperExtensions.cs
@@ -8,19 +8,23 @@
using BiliLite.Models.Common;
using BiliLite.Models.Common.Anime;
using BiliLite.Models.Common.Comment;
+using BiliLite.Models.Common.Download;
using BiliLite.Models.Common.Dynamic;
using BiliLite.Models.Common.Home;
using BiliLite.Models.Common.Season;
using BiliLite.Models.Common.User;
+using BiliLite.Models.Common.User.UserDetails;
using BiliLite.Models.Common.UserDynamic;
using BiliLite.Models.Common.Video.Detail;
using BiliLite.Models.Download;
using BiliLite.Models.Dynamic;
+using BiliLite.Modules.User.UserDetail;
using BiliLite.Services;
using BiliLite.ViewModels.Comment;
using BiliLite.ViewModels.Download;
using BiliLite.ViewModels.Home;
using BiliLite.ViewModels.Season;
+using BiliLite.ViewModels.User;
using BiliLite.ViewModels.UserDynamic;
using BiliLite.ViewModels.Video;
using Microsoft.Extensions.DependencyInjection;
@@ -48,6 +52,13 @@ public static IServiceCollection AddMapper(this IServiceCollection services)
expression.CreateMap();
expression.CreateMap();
expression.CreateMap();
+ expression.CreateMap();
+ expression.CreateMap();
+
+ expression.CreateMap()
+ .ForMember(dest => dest.Paths, opt => opt.MapFrom(src => new List()))
+ .ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.EpisodeTitle))
+ .ForMember(dest => dest.SubtitlePath, opt => opt.MapFrom(src => new List()));
expression.CreateMap()
.ForMember(dest => dest.Play, opt => opt.MapFrom(src => src.Archive.Stat.View))
@@ -141,6 +152,14 @@ public static List MapToDynamicItemModels(this IEnumerable x.ModuleType == DynModuleType.ModuleAuthor);
var moduleDynamic = src.Modules.FirstOrDefault(x => x.ModuleType == DynModuleType.ModuleDynamic);
+
+ // 处理特殊情况:类型为番剧但是数据为普通视频
+ if (moduleDynamic != null && type == 512 && moduleDynamic.ModuleDynamic.DynArchive != null &&
+ moduleDynamic.ModuleDynamic.DynPgc == null)
+ {
+ type = 8;
+ }
+
var dynDesc = new DynamicDescModel()
{
Type = type,
@@ -151,6 +170,7 @@ public static List MapToDynamicItemModels(this IEnumerable(this T obj)
return default;
}
}
+
+ public static T ObjectCloneWithoutSerializable(this T obj)
+ {
+ try
+ {
+ var serializedObj = JsonConvert.SerializeObject(obj);
+ return JsonConvert.DeserializeObject(serializedObj);
+ }
+ catch (Exception e)
+ {
+ return default;
+ }
+ }
}
}
diff --git a/src/BiliLite.UWP/Extensions/StringExtensions.cs b/src/BiliLite.UWP/Extensions/StringExtensions.cs
index 67c4db81b..5bff2a1ab 100644
--- a/src/BiliLite.UWP/Extensions/StringExtensions.cs
+++ b/src/BiliLite.UWP/Extensions/StringExtensions.cs
@@ -225,7 +225,7 @@ public static string ParseArea(this string title, long mid)
public static string ParseArea(this string title, string mid)
{
- return title.ParseArea(mid.ToInt32());
+ return title.ParseArea(mid.ToInt64());
}
///
diff --git a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs
index df3ecb03a..a188a8a16 100644
--- a/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs
+++ b/src/BiliLite.UWP/Extensions/ViewModelExtensions.cs
@@ -22,6 +22,9 @@ public static IServiceCollection AddViewModels(this IServiceCollection services)
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
return services;
}
}
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoLiveRoomModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoLiveRoomModel.cs
new file mode 100644
index 000000000..d860fd365
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoLiveRoomModel.cs
@@ -0,0 +1,27 @@
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoLiveRoomModel
+ {
+ public int RoomStatus { get; set; }
+
+ public int LiveStatus { get; set; }
+
+ public string Url { get; set; }
+
+ public string Title { get; set; }
+
+ public string Cover { get; set; }
+
+ public int Online { get; set; }
+
+ [JsonProperty("roomid")]
+ public int RoomId { get; set; }
+
+ public int RoundStatus { get; set; }
+
+ [JsonProperty("broadcast_type")]
+ public int BroadcastType { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoModel.cs
new file mode 100644
index 000000000..31970658a
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoModel.cs
@@ -0,0 +1,63 @@
+using System;
+using BiliLite.Modules.User;
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoModel
+ {
+ public long Mid { get; set; }
+
+ public string Name { get; set; }
+
+ public string Sex { get; set; }
+
+ public string Face { get; set; }
+
+ public string Sign { get; set; }
+
+ public int Rank { get; set; }
+
+ public int Level { get; set; }
+
+ [JsonProperty("jointime")]
+ public int JoinTime { get; set; }
+
+ public int Moral { get; set; }
+
+ public int Silence { get; set; }
+
+ public string Birthday { get; set; }
+
+ public double Coins { get; set; }
+
+ [JsonProperty("fans_badge")]
+ public bool FansBadge { get; set; }
+
+ public UserCenterInfoOfficialModel Official { get; set; }
+
+ public UserCenterInfoVipModel Vip { get; set; }
+
+ public UserCenterInfoPendantModel Pendant { get; set; }
+
+ [JsonProperty("nameplate")]
+ public UserCenterInfoNameplateModel NamePlate { get; set; }
+
+ [JsonProperty("is_followed")]
+ public bool IsFollowed { get; set; }
+
+ [JsonProperty("top_photo")]
+ public string TopPhoto { get; set; }
+
+ [JsonProperty("live_room")]
+ public UserCenterInfoLiveRoomModel LiveRoom { get; set; }
+
+ public UserCenterSpaceStatModel Stat { get; set; }
+
+ [Obsolete]
+ public string PendantStr => "";
+
+ [Obsolete]
+ public string Verify => "";
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoNameplateModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoNameplateModel.cs
new file mode 100644
index 000000000..78bd38ea4
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoNameplateModel.cs
@@ -0,0 +1,20 @@
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoNameplateModel
+ {
+ public int Nid { get; set; }
+
+ public string Name { get; set; }
+
+ public string Image { get; set; }
+
+ [JsonProperty("image_small")]
+ public string ImageSmall { get; set; }
+
+ public string Level { get; set; }
+
+ public string Condition { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoOfficialModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoOfficialModel.cs
new file mode 100644
index 000000000..d592cb7df
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoOfficialModel.cs
@@ -0,0 +1,15 @@
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoOfficialModel
+ {
+ public int Role { get; set; }
+
+ public string Title { get; set; }
+
+ public string Desc { get; set; }
+
+ public int Type { get; set; }
+
+ public bool ShowOfficial => Type != -1;
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoPendantModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoPendantModel.cs
new file mode 100644
index 000000000..911afcbd0
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoPendantModel.cs
@@ -0,0 +1,18 @@
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoPendantModel
+ {
+ public int Pid { get; set; }
+
+ public string Name { get; set; }
+
+ public string Image { get; set; }
+
+ public int Expire { get; set; }
+
+ [JsonProperty("image_enhance")]
+ public string ImageEnhance { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoStatModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoStatModel.cs
new file mode 100644
index 000000000..243fe29b0
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoStatModel.cs
@@ -0,0 +1,15 @@
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoStatModel
+ {
+ public long Mid { get; set; }
+
+ public int Following { get; set; }
+
+ public int Whisper { get; set; }
+
+ public int Black { get; set; }
+
+ public int Follower { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipLabelModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipLabelModel.cs
new file mode 100644
index 000000000..601ebd9db
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipLabelModel.cs
@@ -0,0 +1,14 @@
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoVipLabelModel
+ {
+ public string Path { get; set; }
+
+ public string Text { get; set; }
+
+ [JsonProperty("label_theme")]
+ public string LabelTheme { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipModel.cs
new file mode 100644
index 000000000..320a6dc57
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterInfoVipModel.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterInfoVipModel
+ {
+ public int Type { get; set; }
+
+ public int Status { get; set; }
+
+ [JsonProperty("theme_type")]
+ public int ThemeType { get; set; }
+
+ public UserCenterInfoVipLabelModel Label { get; set; }
+
+ [JsonProperty("avatar_subscript")]
+ public int AvatarSubscript { get; set; }
+
+ [JsonProperty("nickname_color")]
+ public string NicknameColor { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterSpaceStatModel.cs b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterSpaceStatModel.cs
new file mode 100644
index 000000000..55eb7a5d1
--- /dev/null
+++ b/src/BiliLite.UWP/Models/Common/User/UserDetails/UserCenterSpaceStatModel.cs
@@ -0,0 +1,31 @@
+using BiliLite.Extensions;
+
+namespace BiliLite.Models.Common.User.UserDetails
+{
+ public class UserCenterSpaceStatModel
+ {
+ public int Following { get; set; }
+
+ public string Attention => Following > 0 ? " " + Following.ToCountString() : "";
+
+ public int Follower { get; set; }
+
+ public string Fans => Follower > 0 ? " " + Follower.ToCountString() : "";
+
+ public int VideoCount { get; set; }
+
+ public string Video => VideoCount > 0 ? " " + VideoCount.ToCountString() : "";
+
+ public int ArticleCount { get; set; }
+
+ public string Article => ArticleCount > 0 ? " " + ArticleCount.ToCountString() : "";
+
+ public int FavouriteCount { get; set; }
+
+ public string Favourite => FavouriteCount > 0 ? " " + FavouriteCount.ToCountString() : "";
+
+ public int CollectionCount { get; set; }
+
+ public string Collection => CollectionCount > 0 ? " " + CollectionCount.ToCountString() : "";
+ }
+}
\ No newline at end of file
diff --git a/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs b/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs
index 0ebdc7b36..63963b223 100644
--- a/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs
+++ b/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs
@@ -94,6 +94,10 @@ public ApiModel SendSMS(string cid, string phone, string sessionId, ApiKeyInfo a
public ApiModel SendSMSWithCaptcha(string cid, string phone, string session_id, string seccode = "", string validate = "", string challenge = "", string recaptchaToken = "", ApiKeyInfo appKey = null)
{
+ if (seccode.Contains("|"))
+ {
+ seccode = seccode.UrlEncode();
+ }
var buvid = ApiHelper.GetBuvid();
var api = new ApiModel()
{
diff --git a/src/BiliLite.UWP/Models/Requests/Api/User/DynamicAPI.cs b/src/BiliLite.UWP/Models/Requests/Api/User/DynamicAPI.cs
index c23f84b98..7890502be 100644
--- a/src/BiliLite.UWP/Models/Requests/Api/User/DynamicAPI.cs
+++ b/src/BiliLite.UWP/Models/Requests/Api/User/DynamicAPI.cs
@@ -154,8 +154,6 @@ public ApiModel RecommendTopic()
///
/// 发表图片动态
///
- /// 用户ID
- /// 1为关注,2为取消关注
///
public ApiModel CreateDynamicPhoto(string imgs, string content, string at_uids, string at_control)
{
@@ -173,8 +171,6 @@ public ApiModel CreateDynamicPhoto(string imgs, string content, string at_uids,
///
/// 发表文本动态
///
- /// 用户ID
- /// 1为关注,2为取消关注
///
public ApiModel CreateDynamicText(string content, string at_uids, string at_control)
{
@@ -192,8 +188,6 @@ public ApiModel CreateDynamicText(string content, string at_uids, string at_cont
///
/// 转发动态
///
- /// 用户ID
- /// 1为关注,2为取消关注
///
public ApiModel RepostDynamic(string dynamic_id, string content, string at_uids, string at_control)
{
diff --git a/src/BiliLite.UWP/Models/Requests/Api/User/FavoriteAPI.cs b/src/BiliLite.UWP/Models/Requests/Api/User/FavoriteAPI.cs
index 363047b46..354f01180 100644
--- a/src/BiliLite.UWP/Models/Requests/Api/User/FavoriteAPI.cs
+++ b/src/BiliLite.UWP/Models/Requests/Api/User/FavoriteAPI.cs
@@ -55,10 +55,10 @@ public ApiModel MyCreatedFavorite(string aid)
/// 添加到收藏夹
///
///
- public ApiModel AddFavorite(List fav_ids, string avid)
+ public ApiModel AddFavorite(List favIds, string avid)
{
var ids = "";
- foreach (var item in fav_ids)
+ foreach (var item in favIds)
{
ids += item + ",";
}
diff --git a/src/BiliLite.UWP/Models/Requests/Api/User/UserDetailAPI.cs b/src/BiliLite.UWP/Models/Requests/Api/User/UserDetailAPI.cs
index 80488fc0b..617888c8b 100644
--- a/src/BiliLite.UWP/Models/Requests/Api/User/UserDetailAPI.cs
+++ b/src/BiliLite.UWP/Models/Requests/Api/User/UserDetailAPI.cs
@@ -1,10 +1,20 @@
-using BiliLite.Services;
+using System.Collections.Generic;
+using System.Linq;
+using BiliLite.Services;
using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
namespace BiliLite.Models.Requests.Api.User
{
public class UserDetailAPI : BaseApi
{
+ private readonly CookieService m_cookieService;
+
+ public UserDetailAPI()
+ {
+ m_cookieService = App.ServiceProvider.GetRequiredService();
+ }
+
///
/// 用户信息
///
@@ -132,6 +142,66 @@ public ApiModel FollowingsTag()
api.parameter += ApiHelper.GetSign(api.parameter, AppKey);
return api;
}
+
+ ///
+ /// 查询目标用户所在的分组
+ ///
+ ///
+ public ApiModel FollowingTagUser(long targetUserId)
+ {
+ var api = new ApiModel()
+ {
+ method = RestSharp.Method.Get,
+ baseUrl = $"{ApiHelper.API_BASE_URL}/x/relation/tag/user",
+ parameter = $"fid={targetUserId}&" + ApiHelper.MustParameter(AppKey, true)
+ };
+ api.parameter += ApiHelper.GetSign(api.parameter, AppKey);
+ return api;
+ }
+
+ ///
+ /// 创建分组
+ ///
+ ///
+ public ApiModel CreateFollowingTag(long tag)
+ {
+ var api = new ApiModel()
+ {
+ method = RestSharp.Method.Post,
+ baseUrl = $"{ApiHelper.API_BASE_URL}/x/relation/tag/create",
+ body = $"tag={tag}&" + ApiHelper.MustParameter(AppKey, true)
+ };
+ api.body += ApiHelper.GetSign(api.parameter, AppKey);
+ return api;
+ }
+
+ ///
+ /// 修改分组成员
+ ///
+ ///
+ public ApiModel AddFollowingTagUsers(List targetUserIdList,List tagIdList)
+ {
+ var csrf = m_cookieService.GetCSRFToken();
+ var fids = targetUserIdList.Aggregate("", (current, id) => current + $"{id},");
+ fids = fids.TrimEnd(',');
+ var tagids = "0";
+ if (tagIdList.Any())
+ {
+ tagids = tagIdList.Aggregate("", (current, id) => current + $"{id},");
+ tagids = tagids.TrimEnd(',');
+ }
+
+ var api = new ApiModel()
+ {
+ method = RestSharp.Method.Post,
+ baseUrl = $"{ApiHelper.API_BASE_URL}/x/relation/tags/addUsers",
+ body = $"fids={fids}&tagids={tagids}&csrf={csrf}",// + ApiHelper.MustParameter(AppKey, true)
+ need_cookie = true,
+ };
+ //api.body += ApiHelper.GetSign(api.body, AppKey);
+ return api;
+ }
+
///
/// 关注的人
///
diff --git a/src/BiliLite.UWP/Modules/Live/LiveMessage.cs b/src/BiliLite.UWP/Modules/Live/LiveMessage.cs
index 96c501637..0e7f62638 100644
--- a/src/BiliLite.UWP/Modules/Live/LiveMessage.cs
+++ b/src/BiliLite.UWP/Modules/Live/LiveMessage.cs
@@ -37,7 +37,7 @@ public LiveMessage()
ws = new ClientWebSocket();
}
private static System.Timers.Timer heartBeatTimer;
- public async Task Connect(int roomID, int uid, string token, string buvid, string host, CancellationToken cancellationToken)
+ public async Task Connect(int roomID, long uid, string token, string buvid, string host, CancellationToken cancellationToken)
{
ws.Options.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69");
//连接
@@ -89,7 +89,7 @@ private async void HeartBeatTimer_Elapsed(object sender, System.Timers.ElapsedEv
///
///
///
- private async Task JoinRoomAsync(int roomId, string buvid, string token, int uid = 0)
+ private async Task JoinRoomAsync(int roomId, string buvid, string token, long uid = 0)
{
if (ws.State == WebSocketState.Open)
{
diff --git a/src/BiliLite.UWP/Modules/Player/Playurl/BiliPlayUrlRequest.cs b/src/BiliLite.UWP/Modules/Player/Playurl/BiliPlayUrlRequest.cs
index eb7e646c1..76fd09304 100644
--- a/src/BiliLite.UWP/Modules/Player/Playurl/BiliPlayUrlRequest.cs
+++ b/src/BiliLite.UWP/Modules/Player/Playurl/BiliPlayUrlRequest.cs
@@ -15,6 +15,7 @@
using BiliLite.Models.Common.Video;
using BiliLite.Models.Common.Video.PlayUrlInfos;
using PlayURL = BiliLite.gRPC.Api.PlayURL;
+using BiliLite.gRPC.Api;
namespace BiliLite.Modules.Player.Playurl
{
@@ -686,7 +687,11 @@ private async Task GetPlayUrlUseGrpc(PlayInfo playInfo,
{
Bilibili.App.Playurl.V1.CodeType codec = CodecMode == PlayUrlCodecMode.DASH_H265 ? Bilibili.App.Playurl.V1.CodeType.Code265 : Bilibili.App.Playurl.V1.CodeType.Code264;
- var playViewReply = await playUrlApi.VideoPlayView(Convert.ToInt64(playInfo.avid), Convert.ToInt64(playInfo.cid), qualityID, 16, codec, SettingService.Account.AccessKey);
+ var requestUserInfo = new GrpcBiliUserInfo(
+ SettingService.Account.AccessKey,
+ SettingService.Account.UserID,
+ SettingService.Account.GetLoginAppKeySecret().Appkey);
+ var playViewReply = await playUrlApi.VideoPlayView(Convert.ToInt64(playInfo.avid), Convert.ToInt64(playInfo.cid), qualityID, 16, codec, requestUserInfo);
var grpcResult = await ParseGrpc(qualityID, playViewReply, AndroidUserAgent, "");
return grpcResult;
@@ -784,7 +789,11 @@ private async Task GetPlayUrlUseGrpc(PlayInfo playInfo,
CodeType codec = CodecMode == PlayUrlCodecMode.DASH_H265 ? CodeType.Code265 : CodeType.Code264;
- var playViewReply = await playUrlApi.BangumiPlayView(Convert.ToInt64(playInfo.ep_id), Convert.ToInt64(playInfo.cid), qualityID, 0, codec, SettingService.Account.AccessKey);
+ var requestUserInfo = new GrpcBiliUserInfo(
+ SettingService.Account.AccessKey,
+ SettingService.Account.UserID,
+ SettingService.Account.GetLoginAppKeySecret().Appkey);
+ var playViewReply = await playUrlApi.BangumiPlayView(Convert.ToInt64(playInfo.ep_id), Convert.ToInt64(playInfo.cid), qualityID, 0, codec, requestUserInfo);
var grpcResult = await ParseGrpc(qualityID, playViewReply, AndroidUserAgent, "");
return grpcResult;
diff --git a/src/BiliLite.UWP/Modules/User/LoginVM.cs b/src/BiliLite.UWP/Modules/User/LoginVM.cs
index ef7352e5c..64112b0f7 100644
--- a/src/BiliLite.UWP/Modules/User/LoginVM.cs
+++ b/src/BiliLite.UWP/Modules/User/LoginVM.cs
@@ -340,8 +340,9 @@ public async void SendSMSCodeWithCaptcha(string seccode = "", string validate =
try
{
var appKey = SettingConstants.Account.DefaultLoginAppKeySecret;
- var results = await accountApi.SendSMSWithCaptcha(CurrentCountry.country_code, Phone, sessionId,
- seccode, validate, challenge, recaptcha_token, appKey).Request();
+ var request = accountApi.SendSMSWithCaptcha(CurrentCountry.country_code, Phone, sessionId,
+ seccode, validate, challenge, recaptcha_token, appKey);
+ var results = await request.Request();
if (!results.status)
{
throw new CustomizedErrorWithDataException(results.message, results);
@@ -409,7 +410,7 @@ private async void DoSMSLogin()
SettingService.SetValue(SettingConstants.Account.IS_WEB_LOGIN, false);
var data = await results.GetData();
var result = await HandelLoginResult(data.code, data.message, data.data, appKey);
- HnadelResult(result);
+ HandleResult(result);
}
else
{
@@ -476,7 +477,7 @@ private async void DoPasswordLogin()
var data = await results.GetData();
var result = await HandelLoginResult(data.code, data.message, data.data, appKey);
- HnadelResult(result);
+ HandleResult(result);
}
else
{
@@ -523,7 +524,7 @@ private async void CompletePasswordLoginCheck()
var code = obj["data"]["code"].ToString();
var result = await PasswordLoginFetchCookie(code);
- HnadelResult(result);
+ HandleResult(result);
}
catch (CustomizedErrorWithDataException ex)
{
@@ -694,11 +695,12 @@ public void HandleGeetestSuccess(string seccode, string validate, string challen
{
if (gee_req != null)
{
+ // 验证完成后的 gee_challenge 值可能与之前获取的不同,此处只做提示
if (gee_req.gee_challenge != challenge)
{
Notify.ShowMessageToast("验证码失效");
- return;
}
+ gee_req.gee_challenge = challenge;
gee_req.gee_validate = validate;
gee_req.gee_seccode = seccode;
}
@@ -832,7 +834,7 @@ private async Task HandelLoginResult(int code, string messag
}
}
- private void HnadelResult(LoginCallbackModel result)
+ private void HandleResult(LoginCallbackModel result)
{
switch (result.status)
{
@@ -847,6 +849,15 @@ private void HnadelResult(LoginCallbackModel result)
case LoginStatus.NeedCaptcha:
var uri = new Uri(result.url);
SetWebViewVisibility?.Invoke(this, true);
+ var query = HttpUtility.ParseQueryString(uri.Query);
+ gee_req = new GeetestRequestModel()
+ {
+ gee_challenge = query.Get("gee_challenge"),
+ gee_gt = query.Get("gee_gt"),
+ recaptcha_token = query.Get("recaptcha_token"),
+ };
+ // TODO: 密码登录验证需要获取tmp_code
+ gee_tmp_token = "";
//验证码重定向
//源码:https://github.com/xiaoyaocz/some_web
OpenWebView?.Invoke(this, new Uri("ms-appx-web:///Assets/GeeTest/bili_gt.html" + uri.Query + "&app=uwp"));
diff --git a/src/BiliLite.UWP/Modules/User/SendDynamic/AtVM.cs b/src/BiliLite.UWP/Modules/User/SendDynamic/AtVM.cs
index fe0764f05..5ed9ac291 100644
--- a/src/BiliLite.UWP/Modules/User/SendDynamic/AtVM.cs
+++ b/src/BiliLite.UWP/Modules/User/SendDynamic/AtVM.cs
@@ -69,7 +69,7 @@ public async Task GetUser()
{
Face = item["face"].ToString(),
UserName = item["name"].ToString(),
- ID = item["mid"].ToInt32(),
+ ID = item["mid"].ToInt64(),
});
}
}
@@ -83,7 +83,7 @@ public async Task GetUser()
{
Face = item["face"].ToString(),
UserName = item["uname"].ToString(),
- ID = item["uid"].ToInt32(),
+ ID = item["uid"].ToInt64(),
});
}
}
@@ -135,7 +135,7 @@ public async void Search(string keyword)
}
public class AtUserModel
{
- public int ID { get; set; }
+ public long ID { get; set; }
public string UserName { get; set; }
public string Face { get; set; }
public string Display { get { return "@" + UserName; } }
diff --git a/src/BiliLite.UWP/Modules/User/UserDetail/UserDetailVM.cs b/src/BiliLite.UWP/Modules/User/UserDetail/UserDetailVM.cs
deleted file mode 100644
index 231af0e76..000000000
--- a/src/BiliLite.UWP/Modules/User/UserDetail/UserDetailVM.cs
+++ /dev/null
@@ -1,406 +0,0 @@
-using BiliLite.Models;
-using BiliLite.Models.Requests.Api.User;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Input;
-using Windows.Storage.Streams;
-using Windows.UI;
-using Windows.UI.Xaml.Media;
-using BiliLite.Extensions;
-using BiliLite.Models.Common;
-using BiliLite.Services;
-
-namespace BiliLite.Modules.User
-{
- public class UserDetailVM : IModules
- {
- private static readonly ILogger logger = GlobalLogger.FromCurrentType();
-
- public string mid { get; set; }
- private readonly UserDetailAPI userDetailAPI;
- private readonly FollowAPI followAPI;
- public UserDetailVM()
- {
- userDetailAPI = new UserDetailAPI();
- followAPI = new FollowAPI();
- AttentionCommand = new RelayCommand(DoAttentionUP);
- }
- private UserCenterInfoModel _userInfo;
- public UserCenterInfoModel UserInfo
- {
- get { return _userInfo; }
- set { _userInfo = value; DoPropertyChanged("UserInfo"); }
- }
-
- public ICommand AttentionCommand { get; private set; }
-
- public async void GetUserInfo()
- {
- try
- {
- var api = await userDetailAPI.UserInfo(mid);
- var result = await api.Request();
-
- if (result.status)
- {
- var data = await result.GetData();
- if (data.success)
- {
- data.data.stat = await GetSpeceStat();
- UserInfo = data.data;
- }
- else
- {
- Notify.ShowMessageToast(data.message);
- }
-
- }
- else
- {
- Notify.ShowMessageToast(result.message);
- }
- }
- catch (Exception ex)
- {
- logger.Log("读取个人资料失败", LogType.Error, ex);
- Notify.ShowMessageToast("读取个人资料失败");
- }
- }
- public async Task GetStat()
- {
- try
- {
- var result = await userDetailAPI.UserStat(mid).Request();
-
- if (result.status)
- {
- var data = await result.GetData();
- if (data.success)
- {
- return data.data;
- }
- else
- {
- return null;
- }
-
- }
- else
- {
- return null;
- }
- }
- catch (Exception ex)
- {
- logger.Log("读取个人资料失败", LogType.Error, ex);
- return null;
- }
- }
-
- public async Task GetSpeceStat()
- {
- try
- {
- var result = await userDetailAPI.Space(mid).Request();
-
- if (result.status)
- {
- var data = await result.GetData();
- if (data.success)
- {
- UserCenterSpaceStatModel stat = new UserCenterSpaceStatModel();
- stat.article_count = (data.data["article"]?["count"] ?? 0).ToInt32();
- stat.video_count = (data.data["archive"]?["count"] ?? 0).ToInt32();
- stat.favourite_count = (data.data["favourite2"]?["count"] ?? 0).ToInt32();
- stat.follower = data.data["card"]["fans"].ToInt32();
- stat.following = data.data["card"]["attention"].ToInt32();
- stat.CollectionCount = (data.data?["ugc_season"]?["count"] ?? 0).ToInt32() + (data.data?["series"]?["item"].ToArray().Length ?? 0);
- return stat;
- }
- else
- {
- return null;
- }
-
- }
- else
- {
- return null;
- }
- }
- catch (Exception ex)
- {
- logger.Log("读取个人资料失败", LogType.Error, ex);
- return null;
- }
- }
- public async void DoAttentionUP()
- {
- var result = await AttentionUP(UserInfo.mid.ToString(), UserInfo.is_followed ? 2 : 1);
- if (result)
- {
- UserInfo.is_followed = !UserInfo.is_followed;
- }
- }
- public async Task AttentionUP(string mid, int mode)
- {
- if (!SettingService.Account.Logined && !await Notify.ShowLoginDialog())
- {
- Notify.ShowMessageToast("请先登录后再操作");
- return false;
- }
-
- try
- {
- var results = await followAPI.Attention(mid, mode.ToString()).Request();
- if (results.status)
- {
- var data = await results.GetJson>();
- if (data.success)
- {
- Notify.ShowMessageToast("操作成功");
- return true;
- }
- else
- {
- Notify.ShowMessageToast(data.message);
- return false;
- }
- }
- else
- {
- Notify.ShowMessageToast(results.message);
- return false;
- }
- }
- catch (Exception ex)
- {
- var handel = HandelError