From f01c44a4739f54a10adf2f951ee5ab75a020531d Mon Sep 17 00:00:00 2001
From: leiurayer <1432593898@qq.com>
Date: Fri, 28 Jul 2023 00:15:04 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A6=96=E9=A1=B5=E6=90=9C?=
=?UTF-8?q?=E7=B4=A2=E6=A1=86=E6=9C=8D=E5=8A=A1=E3=80=81=E5=89=AA=E8=B4=B4?=
=?UTF-8?q?=E6=9D=BF=E6=9C=8D=E5=8A=A1=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=B8=80?=
=?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Downkyi.Core/Settings/SettingsManager.cs | 13 +-
src/Downkyi.UI/Mvvm/BaseServices.cs | 8 +
.../Mvvm/Navigation/INavigationAware.cs | 2 +-
src/Downkyi.UI/Mvvm/ViewModelBase.cs | 2 +
src/Downkyi.UI/Services/IClipboardService.cs | 6 +
src/Downkyi.UI/Services/IMainSearchService.cs | 28 ++++
src/Downkyi.UI/Services/MainSearchService.cs | 140 ++++++++++++++++++
src/Downkyi.UI/ViewModels/IndexViewModel.cs | 25 +++-
.../ViewModels/Settings/NetworkViewModel.cs | 47 ++----
.../Video/PublicFavoritesViewModel.cs | 29 ++++
.../ViewModels/Video/VideoDetailViewModel.cs | 29 ++++
src/Downkyi/ServiceLocator.cs | 21 ++-
src/Downkyi/Services/ClipboardService.cs | 19 +++
src/Downkyi/ViewModels/MainWindowViewModel.cs | 64 +++++++-
src/Downkyi/Views/MainWindow.axaml | 7 +
src/Downkyi/Views/Settings/NetworkView.axaml | 28 ++--
16 files changed, 407 insertions(+), 61 deletions(-)
create mode 100644 src/Downkyi.UI/Services/IClipboardService.cs
create mode 100644 src/Downkyi.UI/Services/IMainSearchService.cs
create mode 100644 src/Downkyi.UI/Services/MainSearchService.cs
create mode 100644 src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs
create mode 100644 src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs
create mode 100644 src/Downkyi/Services/ClipboardService.cs
diff --git a/src/Downkyi.Core/Settings/SettingsManager.cs b/src/Downkyi.Core/Settings/SettingsManager.cs
index 6716091..510c88f 100644
--- a/src/Downkyi.Core/Settings/SettingsManager.cs
+++ b/src/Downkyi.Core/Settings/SettingsManager.cs
@@ -50,13 +50,16 @@ public partial class SettingsManager
///
private AppSettings GetSettings()
{
+ if (appSettings != null) { return appSettings; }
+
try
{
- var fileStream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- var streamReader = new StreamReader(fileStream, System.Text.Encoding.UTF8);
- string jsonWordTemplate = streamReader.ReadToEnd();
- streamReader.Close();
- fileStream.Close();
+ string jsonWordTemplate = string.Empty;
+ using (var stream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
+ {
+ using var reader = new StreamReader(stream, System.Text.Encoding.UTF8);
+ jsonWordTemplate = reader.ReadToEnd();
+ }
#if DEBUG
#else
diff --git a/src/Downkyi.UI/Mvvm/BaseServices.cs b/src/Downkyi.UI/Mvvm/BaseServices.cs
index 58035e3..ad88aa8 100644
--- a/src/Downkyi.UI/Mvvm/BaseServices.cs
+++ b/src/Downkyi.UI/Mvvm/BaseServices.cs
@@ -9,8 +9,12 @@ public class BaseServices
public INotificationEvent NotificationEvent { get; }
+ public IClipboardService ClipboardService { get; }
+
public IDictionaryResource DictionaryResource { get; }
+ public IMainSearchService MainSearchService { get; }
+
public INavigationService NavigationService { get; }
public IStoragePicker StoragePicker { get; }
@@ -19,14 +23,18 @@ public class BaseServices
public BaseServices(IBroadcastEvent broadcastEvent,
INotificationEvent notificationEvent,
+ IClipboardService clipboardService,
IDictionaryResource dictionaryResource,
+ IMainSearchService mainSearchService,
INavigationService navigationService,
IStoragePicker storagePicker,
IStorageService storageService)
{
BroadcastEvent = broadcastEvent;
NotificationEvent = notificationEvent;
+ ClipboardService = clipboardService;
DictionaryResource = dictionaryResource;
+ MainSearchService = mainSearchService;
NavigationService = navigationService;
StoragePicker = storagePicker;
StorageService = storageService;
diff --git a/src/Downkyi.UI/Mvvm/Navigation/INavigationAware.cs b/src/Downkyi.UI/Mvvm/Navigation/INavigationAware.cs
index 35e50b6..d8df6c2 100644
--- a/src/Downkyi.UI/Mvvm/Navigation/INavigationAware.cs
+++ b/src/Downkyi.UI/Mvvm/Navigation/INavigationAware.cs
@@ -5,4 +5,4 @@ public interface INavigationAware
void OnNavigatedTo(Dictionary? parameter);
void OnNavigatedFrom(Dictionary? parameter);
-}
+}
\ No newline at end of file
diff --git a/src/Downkyi.UI/Mvvm/ViewModelBase.cs b/src/Downkyi.UI/Mvvm/ViewModelBase.cs
index 7b76597..9242a08 100644
--- a/src/Downkyi.UI/Mvvm/ViewModelBase.cs
+++ b/src/Downkyi.UI/Mvvm/ViewModelBase.cs
@@ -11,7 +11,9 @@ public abstract class ViewModelBase : ObservableObject, INavigationAware
protected IBroadcastEvent BroadcastEvent => _baseServices.BroadcastEvent;
protected INotificationEvent NotificationEvent => _baseServices.NotificationEvent;
+ protected IClipboardService ClipboardService => _baseServices.ClipboardService;
protected IDictionaryResource DictionaryResource => _baseServices.DictionaryResource;
+ protected IMainSearchService MainSearchService => _baseServices.MainSearchService;
protected INavigationService NavigationService => _baseServices.NavigationService;
protected IStoragePicker StoragePicker => _baseServices.StoragePicker;
protected IStorageService StorageService => _baseServices.StorageService;
diff --git a/src/Downkyi.UI/Services/IClipboardService.cs b/src/Downkyi.UI/Services/IClipboardService.cs
new file mode 100644
index 0000000..32c7e64
--- /dev/null
+++ b/src/Downkyi.UI/Services/IClipboardService.cs
@@ -0,0 +1,6 @@
+namespace Downkyi.UI.Services;
+
+public interface IClipboardService
+{
+ Task GetTextAsync();
+}
\ No newline at end of file
diff --git a/src/Downkyi.UI/Services/IMainSearchService.cs b/src/Downkyi.UI/Services/IMainSearchService.cs
new file mode 100644
index 0000000..8064a9a
--- /dev/null
+++ b/src/Downkyi.UI/Services/IMainSearchService.cs
@@ -0,0 +1,28 @@
+namespace Downkyi.UI.Services;
+
+public interface IMainSearchService
+{
+ ///
+ /// 解析支持的输入,
+ /// 支持的格式有:
+ /// av号:av170001, AV170001, https://www.bilibili.com/video/av170001
+ /// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC
+ /// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982
+ /// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925
+ /// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367
+ /// 课程ss号:https://www.bilibili.com/cheese/play/ss205
+ /// 课程ep号:https://www.bilibili.com/cheese/play/ep3489
+ /// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/
+ /// 用户空间:uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123
+ ///
+ ///
+ ///
+ bool BiliInput(string input);
+
+ ///
+ /// 搜索关键词
+ ///
+ ///
+ ///
+ bool SearchKey(string input);
+}
\ No newline at end of file
diff --git a/src/Downkyi.UI/Services/MainSearchService.cs b/src/Downkyi.UI/Services/MainSearchService.cs
new file mode 100644
index 0000000..35f4fa4
--- /dev/null
+++ b/src/Downkyi.UI/Services/MainSearchService.cs
@@ -0,0 +1,140 @@
+using Downkyi.Core.Bili.Utils;
+using Downkyi.Core.Settings;
+using Downkyi.Core.Settings.Models;
+using Downkyi.UI.ViewModels.User;
+using Downkyi.UI.ViewModels.Video;
+
+namespace Downkyi.UI.Services;
+
+public class MainSearchService : IMainSearchService
+{
+ private readonly INavigationService NavigationService;
+
+ public MainSearchService(INavigationService navigationService)
+ {
+ NavigationService = navigationService;
+ }
+
+ public bool BiliInput(string input)
+ {
+ // 移除剪贴板id
+ //string validId = input.Replace(AppConstant.ClipboardId, "");
+
+ string validId = input;
+
+ // 参数
+ Dictionary parameter = new()
+ {
+ { "key", "MainSearchService" },
+ { "value", new object() },
+ };
+
+ // 视频
+ if (ParseEntrance.IsAvId(validId))
+ {
+ parameter["value"] = $"{ParseEntrance.VideoUrl}{validId.ToLower()}";
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsAvUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBvId(validId))
+ {
+ parameter["value"] = $"{ParseEntrance.VideoUrl}{input}";
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBvUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ // 番剧(电影、电视剧)
+ else if (ParseEntrance.IsBangumiSeasonId(validId))
+ {
+ parameter["value"] = $"{ParseEntrance.BangumiUrl}{input.ToLower()}";
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBangumiSeasonUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBangumiEpisodeId(validId))
+ {
+ parameter["value"] = $"{ParseEntrance.BangumiUrl}{input.ToLower()}";
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBangumiEpisodeUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBangumiMediaId(validId))
+ {
+ parameter["value"] = $"{ParseEntrance.BangumiMediaUrl}{input.ToLower()}";
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ else if (ParseEntrance.IsBangumiMediaUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ // 课程
+ else if (ParseEntrance.IsCheeseSeasonUrl(validId)
+ || ParseEntrance.IsCheeseEpisodeUrl(validId))
+ {
+ parameter["value"] = validId;
+ NavigationService.ForwardAsync(VideoDetailViewModel.Key, parameter);
+ }
+ // 用户(参数传入mid)
+ else if (ParseEntrance.IsUserId(validId) || ParseEntrance.IsUserUrl(validId))
+ {
+ NavigateToViewUserSpace(ParseEntrance.GetUserId(input));
+ }
+ // 收藏夹
+ else if (ParseEntrance.IsFavoritesId(validId) || ParseEntrance.IsFavoritesUrl(validId))
+ {
+ parameter["value"] = ParseEntrance.GetFavoritesId(input);
+ NavigationService.ForwardAsync(PublicFavoritesViewModel.Key, parameter);
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public bool SearchKey(string input)
+ {
+ // TODO
+ return false;
+ }
+
+ ///
+ /// 导航到用户空间,
+ /// 如果传入的mid与本地登录的mid一致,
+ /// 则进入我的用户空间。
+ ///
+ ///
+ private void NavigateToViewUserSpace(long mid)
+ {
+ Dictionary parameter = new()
+ {
+ { "key", "MainSearchService" },
+ { "value", mid },
+ };
+
+ UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo();
+ if (userInfo != null && userInfo.Mid == mid)
+ {
+ NavigationService.ForwardAsync(MySpaceViewModel.Key, parameter);
+ }
+ else
+ {
+ NavigationService.ForwardAsync(UserSpaceViewModel.Key, parameter);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Downkyi.UI/ViewModels/IndexViewModel.cs b/src/Downkyi.UI/ViewModels/IndexViewModel.cs
index c18747d..854b3c3 100644
--- a/src/Downkyi.UI/ViewModels/IndexViewModel.cs
+++ b/src/Downkyi.UI/ViewModels/IndexViewModel.cs
@@ -1,15 +1,18 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Downkyi.Core.Bili;
+using Downkyi.Core.Log;
using Downkyi.Core.Settings;
using Downkyi.Core.Settings.Models;
using Downkyi.Core.Storage;
using Downkyi.UI.Mvvm;
+using Downkyi.UI.Services;
using Downkyi.UI.ViewModels.DownloadManager;
using Downkyi.UI.ViewModels.Login;
using Downkyi.UI.ViewModels.Settings;
using Downkyi.UI.ViewModels.Toolbox;
using Downkyi.UI.ViewModels.User;
+using System.Text.RegularExpressions;
namespace Downkyi.UI.ViewModels;
@@ -115,9 +118,29 @@ public partial class IndexViewModel : ViewModelBase
#region 业务逻辑
+ ///
+ /// 进入B站链接的处理逻辑,
+ /// 只负责处理输入,并跳转到视频详情页。
+ /// 不是支持的格式,则进入搜索页面。
+ ///
private void EnterBili()
{
- NotificationEvent.Publish("Enter Bili!");
+ if (InputText == string.Empty)
+ {
+ return;
+ }
+ Log.Logger.Debug(InputText);
+
+ InputText = Regex.Replace(InputText, @"[【]*[^【]*[^】]*[】 ]", "");
+
+ bool isSupport = MainSearchService.BiliInput(InputText);
+ if (!isSupport)
+ {
+ // 关键词搜索
+ MainSearchService.SearchKey(InputText);
+ }
+
+ InputText = string.Empty;
}
private async Task UpdateUserInfo()
diff --git a/src/Downkyi.UI/ViewModels/Settings/NetworkViewModel.cs b/src/Downkyi.UI/ViewModels/Settings/NetworkViewModel.cs
index acd18b1..a85f179 100644
--- a/src/Downkyi.UI/ViewModels/Settings/NetworkViewModel.cs
+++ b/src/Downkyi.UI/ViewModels/Settings/NetworkViewModel.cs
@@ -114,14 +114,11 @@ public partial class NetworkViewModel : BaseSettingsViewModel
for (int i = 1; i <= 10; i++) { Splits.Add(i); }
// Aria的日志等级
- AriaLogLevels = new List
- {
- "DEBUG",
- "INFO",
- "NOTICE",
- "WARN",
- "ERROR"
- };
+ AriaLogLevels.Add("DEBUG");
+ AriaLogLevels.Add("INFO");
+ AriaLogLevels.Add("NOTICE");
+ AriaLogLevels.Add("WARN");
+ AriaLogLevels.Add("ERROR");
// Aria同时下载数
for (int i = 1; i <= 10; i++) { AriaMaxConcurrentDownloads.Add(i); }
@@ -130,12 +127,9 @@ public partial class NetworkViewModel : BaseSettingsViewModel
for (int i = 1; i <= 10; i++) { AriaSplits.Add(i); }
// Aria文件预分配
- AriaFileAllocations = new List
- {
- "NONE",
- "PREALLOC",
- "FALLOC"
- };
+ AriaFileAllocations.Add("NONE");
+ AriaFileAllocations.Add("PREALLOC");
+ AriaFileAllocations.Add("FALLOC");
#endregion
}
@@ -288,10 +282,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
///
[RelayCommand]
- private void SetMaxCurrentDownloads(object parameter)
+ private void SetMaxCurrentDownloads()
{
- SelectedMaxCurrentDownload = (int)parameter;
-
bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedMaxCurrentDownload);
PublishTip(Key, isSucceed);
}
@@ -301,10 +293,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
///
[RelayCommand]
- private void SetSplits(object parameter)
+ private void SetSplits()
{
- SelectedSplit = (int)parameter;
-
bool isSucceed = SettingsManager.GetInstance().SetSplit(SelectedSplit);
PublishTip(Key, isSucceed);
}
@@ -389,9 +379,9 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
///
[RelayCommand]
- private void SetAriaLogLevels(string parameter)
+ private void SetAriaLogLevels()
{
- var ariaLogLevel = parameter switch
+ var ariaLogLevel = SelectedAriaLogLevel switch
{
"DEBUG" => AriaConfigLogLevel.DEBUG,
"INFO" => AriaConfigLogLevel.INFO,
@@ -409,10 +399,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
///
[RelayCommand]
- private void SetAriaMaxConcurrentDownloads(object parameter)
+ private void SetAriaMaxConcurrentDownloads()
{
- SelectedAriaMaxConcurrentDownload = (int)parameter;
-
bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedAriaMaxConcurrentDownload);
PublishTip(Key, isSucceed);
}
@@ -422,10 +410,8 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
///
[RelayCommand]
- private void SetAriaSplits(object parameter)
+ private void SetAriaSplits()
{
- SelectedAriaSplit = (int)parameter;
-
bool isSucceed = SettingsManager.GetInstance().SetAriaSplit(SelectedAriaSplit);
PublishTip(Key, isSucceed);
}
@@ -498,11 +484,10 @@ public partial class NetworkViewModel : BaseSettingsViewModel
///
/// Aria文件预分配事件
///
- ///
[RelayCommand]
- private void SetAriaFileAllocations(string parameter)
+ private void SetAriaFileAllocations()
{
- var ariaFileAllocation = parameter switch
+ var ariaFileAllocation = SelectedAriaFileAllocation switch
{
"NONE" => AriaConfigFileAllocation.NONE,
"PREALLOC" => AriaConfigFileAllocation.PREALLOC,
diff --git a/src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs b/src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs
new file mode 100644
index 0000000..4d9aacd
--- /dev/null
+++ b/src/Downkyi.UI/ViewModels/Video/PublicFavoritesViewModel.cs
@@ -0,0 +1,29 @@
+using CommunityToolkit.Mvvm.Input;
+using Downkyi.UI.Mvvm;
+
+namespace Downkyi.UI.ViewModels.Video;
+
+public partial class PublicFavoritesViewModel : ViewModelBase
+{
+ public const string Key = "PublicFavorites";
+
+ public PublicFavoritesViewModel(BaseServices baseServices) : base(baseServices)
+ {
+ }
+
+ #region 命令申明
+
+ [RelayCommand(FlowExceptionsToTaskScheduler = true)]
+ private async Task BackwardAsync()
+ {
+ Dictionary parameter = new()
+ {
+ { "key", Key },
+ };
+
+ await NavigationService.BackwardAsync(parameter);
+ }
+
+ #endregion
+
+}
\ No newline at end of file
diff --git a/src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs b/src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs
new file mode 100644
index 0000000..f664035
--- /dev/null
+++ b/src/Downkyi.UI/ViewModels/Video/VideoDetailViewModel.cs
@@ -0,0 +1,29 @@
+using CommunityToolkit.Mvvm.Input;
+using Downkyi.UI.Mvvm;
+
+namespace Downkyi.UI.ViewModels.Video;
+
+public partial class VideoDetailViewModel : ViewModelBase
+{
+ public const string Key = "VideoDetail";
+
+ public VideoDetailViewModel(BaseServices baseServices) : base(baseServices)
+ {
+ }
+
+ #region 命令申明
+
+ [RelayCommand(FlowExceptionsToTaskScheduler = true)]
+ private async Task BackwardAsync()
+ {
+ Dictionary parameter = new()
+ {
+ { "key", Key },
+ };
+
+ await NavigationService.BackwardAsync(parameter);
+ }
+
+ #endregion
+
+}
\ No newline at end of file
diff --git a/src/Downkyi/ServiceLocator.cs b/src/Downkyi/ServiceLocator.cs
index 7f0d059..2e798b4 100644
--- a/src/Downkyi/ServiceLocator.cs
+++ b/src/Downkyi/ServiceLocator.cs
@@ -9,6 +9,7 @@ using Downkyi.UI.ViewModels.Login;
using Downkyi.UI.ViewModels.Settings;
using Downkyi.UI.ViewModels.Toolbox;
using Downkyi.UI.ViewModels.User;
+using Downkyi.UI.ViewModels.Video;
using Downkyi.ViewModels;
using Downkyi.ViewModels.Login;
using Downkyi.ViewModels.Settings;
@@ -92,31 +93,41 @@ public static class ServiceLocator
.AddScoped()
.AddSingleton()
.AddSingleton()
+ .AddSingleton()
.AddSingleton()
+ .AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
//ViewModels
.AddSingleton()
.AddSingleton()
+ //
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ //
.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton()
- .AddSingleton()
+ //
.AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton()
- .AddSingleton()
- .AddSingleton()
+ //
.AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
+ //
+ .AddSingleton()
+ .AddSingleton()
+ //
+ .AddSingleton()
+ .AddSingleton()
.BuildServiceProvider());
}
}
diff --git a/src/Downkyi/Services/ClipboardService.cs b/src/Downkyi/Services/ClipboardService.cs
new file mode 100644
index 0000000..600b3d7
--- /dev/null
+++ b/src/Downkyi/Services/ClipboardService.cs
@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Downkyi.UI.Services;
+using System;
+using System.Threading.Tasks;
+
+namespace Downkyi.Services;
+
+public class ClipboardService : IClipboardService
+{
+ public async Task GetTextAsync()
+ {
+ if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
+ desktop.MainWindow?.Clipboard is not { } provider)
+ throw new NullReferenceException("Missing Clipboard instance.");
+
+ return await provider.GetTextAsync() ?? string.Empty;
+ }
+}
\ No newline at end of file
diff --git a/src/Downkyi/ViewModels/MainWindowViewModel.cs b/src/Downkyi/ViewModels/MainWindowViewModel.cs
index ed48015..29d1d68 100644
--- a/src/Downkyi/ViewModels/MainWindowViewModel.cs
+++ b/src/Downkyi/ViewModels/MainWindowViewModel.cs
@@ -1,5 +1,10 @@
-using CommunityToolkit.Mvvm.ComponentModel;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
+using CommunityToolkit.Mvvm.Input;
+using Downkyi.Core.Settings;
+using Downkyi.Core.Settings.Enum;
using Downkyi.Core.Utils;
using Downkyi.UI.Mvvm;
using Downkyi.UI.ViewModels;
@@ -8,8 +13,10 @@ using Downkyi.UI.ViewModels.Login;
using Downkyi.UI.ViewModels.Settings;
using Downkyi.UI.ViewModels.Toolbox;
using Downkyi.UI.ViewModels.User;
+using System;
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
namespace Downkyi.ViewModels;
@@ -19,6 +26,8 @@ public partial class MainWindowViewModel : ViewModelBase
private readonly LinkStack _pages = new();
+ private readonly CancellationTokenSource? tokenSource;
+
#region 页面属性申明
[ObservableProperty]
@@ -55,8 +64,61 @@ public partial class MainWindowViewModel : ViewModelBase
MessageVisibility = false;
});
+ // 监听剪贴板线程
+ string oldClip = string.Empty;
+ Task.Run(async () =>
+ {
+ CancellationToken cancellationToken = tokenSource!.Token;
+
+ if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
+ desktop.MainWindow?.Clipboard is not { } provider)
+ throw new NullReferenceException("Missing Clipboard instance.");
+ await provider.SetTextAsync(oldClip);
+
+ while (true)
+ {
+ AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard();
+ if (isListenClipboard != AllowStatus.YES)
+ {
+ continue;
+ }
+
+ // 判断是否该结束线程,若为true,跳出while循环
+ if (cancellationToken.IsCancellationRequested)
+ {
+ break;
+ }
+ else
+ {
+ string clip = await ClipboardService.GetTextAsync();
+ if (clip.Equals(oldClip))
+ {
+ await Task.Delay(100);
+ continue;
+ }
+
+ oldClip = clip;
+ MainSearchService.BiliInput(clip);
+ }
+ }
+ }, (tokenSource = new CancellationTokenSource()).Token);
+
}
+ #region 命令申明
+
+ ///
+ /// 退出窗口时执行
+ ///
+ [RelayCommand]
+ private void OnClosing()
+ {
+ // 取消任务
+ tokenSource?.Cancel();
+ }
+
+ #endregion
+
public void Forward(string viewKey, Dictionary? parameter = null)
{
var viewModel = SetContent(viewKey);
diff --git a/src/Downkyi/Views/MainWindow.axaml b/src/Downkyi/Views/MainWindow.axaml
index e7f0b1a..786e333 100644
--- a/src/Downkyi/Views/MainWindow.axaml
+++ b/src/Downkyi/Views/MainWindow.axaml
@@ -2,6 +2,8 @@
x:Class="Downkyi.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
+ xmlns:ia="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"
xmlns:local="using:Downkyi"
xmlns:vm="using:Downkyi.ViewModels"
Title="{DynamicResource AppName}"
@@ -14,6 +16,11 @@
Design.DataContext="{x:Static local:ServiceLocator.MainWindowViewModel}"
Icon="/Assets/logo.ico"
WindowStartupLocation="CenterScreen">
+
+
+
+
+
diff --git a/src/Downkyi/Views/Settings/NetworkView.axaml b/src/Downkyi/Views/Settings/NetworkView.axaml
index 8be9eb9..c6c8501 100644
--- a/src/Downkyi/Views/Settings/NetworkView.axaml
+++ b/src/Downkyi/Views/Settings/NetworkView.axaml
@@ -87,15 +87,14 @@
VerticalAlignment="Center"
Text="{DynamicResource MaxCurrentDownloads}" />
+ SelectedItem="{Binding SelectedMaxCurrentDownload}">
-
+
@@ -107,15 +106,14 @@
VerticalAlignment="Center"
Text="{DynamicResource Split}" />
+ SelectedItem="{Binding SelectedSplit}">
-
+
@@ -203,15 +201,14 @@
VerticalAlignment="Center"
Text="{DynamicResource AriaLogLevel}" />
+ SelectedItem="{Binding SelectedAriaLogLevel}">
-
+
@@ -223,15 +220,14 @@
VerticalAlignment="Center"
Text="{DynamicResource AriaMaxConcurrentDownloads}" />
+ SelectedItem="{Binding SelectedAriaMaxConcurrentDownload}">
-
+
@@ -243,15 +239,14 @@
VerticalAlignment="Center"
Text="{DynamicResource AriaSplit}" />
+ SelectedItem="{Binding SelectedAriaSplit}">
-
+
@@ -376,7 +371,6 @@
VerticalAlignment="Center"
Text="{DynamicResource AriaFileAllocation}" />
-
+