From 395f8df0ec63d22f6b59062dadf55124a1a9a765 Mon Sep 17 00:00:00 2001 From: leiurayer <1432593898@qq.com> Date: Tue, 19 Jul 2022 13:04:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89ar?= =?UTF-8?q?ia=E6=9C=8D=E5=8A=A1=E5=99=A8=EF=BC=8C=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aria2cNet/Client/AriaClient.cs | 91 ++-- src/DownKyi.Core/Settings/Downloader.cs | 1 + .../Settings/Models/NetworkSettings.cs | 2 + .../Settings/SettingsManager.Network.cs | 60 +++ src/DownKyi/App.xaml.cs | 3 + src/DownKyi/DownKyi.csproj | 1 + src/DownKyi/Languages/Default.xaml | 3 + .../Services/Download/AriaDownloadService.cs | 5 + .../Download/CustomAriaDownloadService.cs | 440 ++++++++++++++++++ .../Settings/ViewNetworkViewModel.cs | 63 +++ src/DownKyi/Views/Settings/ViewNetwork.xaml | 126 +++++ 11 files changed, 760 insertions(+), 35 deletions(-) create mode 100644 src/DownKyi/Services/Download/CustomAriaDownloadService.cs diff --git a/src/DownKyi.Core/Aria2cNet/Client/AriaClient.cs b/src/DownKyi.Core/Aria2cNet/Client/AriaClient.cs index 77083a4..dd1b5fa 100644 --- a/src/DownKyi.Core/Aria2cNet/Client/AriaClient.cs +++ b/src/DownKyi.Core/Aria2cNet/Client/AriaClient.cs @@ -16,7 +16,10 @@ namespace DownKyi.Core.Aria2cNet.Client public static class AriaClient { private static readonly string JSONRPC = "2.0"; - private static readonly string TOKEN = "downkyi"; + private const string LOCAL_HOST = "http://localhost"; + private const string TOKEN = "downkyi"; + private static string host = LOCAL_HOST; + private static string token = TOKEN; /// /// This method adds a new download. @@ -41,7 +44,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, uris, option }; @@ -91,7 +94,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, torrent, uris, option @@ -136,7 +139,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, metalink, uris, option @@ -168,7 +171,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -193,7 +196,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -220,7 +223,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -242,7 +245,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -266,7 +269,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -288,7 +291,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -311,7 +314,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -333,7 +336,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -360,7 +363,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -384,7 +387,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -408,7 +411,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -433,7 +436,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -457,7 +460,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -480,7 +483,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -520,7 +523,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, offset, num }; @@ -552,7 +555,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, offset, num }; @@ -591,7 +594,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid, pos, how.ToString("G") @@ -635,7 +638,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid, fileIndex, delUris, @@ -669,7 +672,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; @@ -705,7 +708,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid, option }; @@ -735,7 +738,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData @@ -770,7 +773,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, option }; @@ -793,7 +796,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -814,7 +817,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -836,7 +839,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN, + "token:" + token, gid }; AriaSendData ariaSend = new AriaSendData @@ -858,7 +861,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -881,7 +884,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -902,7 +905,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -926,7 +929,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -947,7 +950,7 @@ namespace DownKyi.Core.Aria2cNet.Client { List ariaParams = new List { - "token:" + TOKEN + "token:" + token, }; AriaSendData ariaSend = new AriaSendData { @@ -1018,13 +1021,31 @@ namespace DownKyi.Core.Aria2cNet.Client return await GetRpcResponseAsync(ariaSend); } + /// + /// 设置aria token + /// + /// + public static void SetToken(string token = TOKEN) + { + AriaClient.token = token; + } + + /// + /// 设置aria host + /// + /// + public static void SetHost(string host = LOCAL_HOST) + { + AriaClient.host = host; + } + /// /// 获取jsonrpc的地址 /// /// private static string GetRpcUri(int listenPort = 6800) { - return $"http://localhost:{listenPort}/jsonrpc"; + return $"{host}:{listenPort}/jsonrpc"; } /// diff --git a/src/DownKyi.Core/Settings/Downloader.cs b/src/DownKyi.Core/Settings/Downloader.cs index ff5cb8c..0008bbe 100644 --- a/src/DownKyi.Core/Settings/Downloader.cs +++ b/src/DownKyi.Core/Settings/Downloader.cs @@ -5,5 +5,6 @@ NOT_SET = 0, BUILT_IN, ARIA, + CUSTOM_ARIA, } } diff --git a/src/DownKyi.Core/Settings/Models/NetworkSettings.cs b/src/DownKyi.Core/Settings/Models/NetworkSettings.cs index bf26ede..d745442 100644 --- a/src/DownKyi.Core/Settings/Models/NetworkSettings.cs +++ b/src/DownKyi.Core/Settings/Models/NetworkSettings.cs @@ -22,6 +22,8 @@ namespace DownKyi.Core.Settings.Models #endregion #region Aria + public string AriaToken { get; set; } = null; + public string AriaHost { get; set; } = null; public int AriaListenPort { get; set; } = -1; public AriaConfigLogLevel AriaLogLevel { get; set; } = AriaConfigLogLevel.NOT_SET; public int AriaSplit { get; set; } = -1; diff --git a/src/DownKyi.Core/Settings/SettingsManager.Network.cs b/src/DownKyi.Core/Settings/SettingsManager.Network.cs index 8ffb9e7..2e2a468 100644 --- a/src/DownKyi.Core/Settings/SettingsManager.Network.cs +++ b/src/DownKyi.Core/Settings/SettingsManager.Network.cs @@ -24,6 +24,12 @@ namespace DownKyi.Core.Settings private readonly string httpProxy = ""; private readonly int httpProxyListenPort = 0; + // Aria服务器token + private readonly string ariaToken = "downkyi"; + + // Aria服务器host + private readonly string ariaHost = "http://localhost"; + // Aria服务器端口号 private readonly int ariaListenPort = 6800; @@ -263,6 +269,60 @@ namespace DownKyi.Core.Settings return SetSettings(); } + /// + /// 获取Aria服务器的token + /// + /// + public string GetAriaToken() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaToken == null) + { + // 第一次获取,先设置默认值 + SetHttpProxy(ariaToken); + return ariaToken; + } + return appSettings.Network.AriaToken; + } + + /// + /// 设置Aria服务器的token + /// + /// + /// + public bool SetAriaToken(string token) + { + appSettings.Network.AriaToken = token; + return SetSettings(); + } + + /// + /// 获取Aria服务器的host + /// + /// + public string GetAriaHost() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaHost == null) + { + // 第一次获取,先设置默认值 + SetHttpProxy(ariaHost); + return ariaHost; + } + return appSettings.Network.AriaHost; + } + + /// + /// 设置Aria服务器的host + /// + /// + /// + public bool SetAriaHost(string host) + { + appSettings.Network.AriaHost = host; + return SetSettings(); + } + /// /// 获取Aria服务器的端口号 /// diff --git a/src/DownKyi/App.xaml.cs b/src/DownKyi/App.xaml.cs index e09d666..732836d 100644 --- a/src/DownKyi/App.xaml.cs +++ b/src/DownKyi/App.xaml.cs @@ -132,6 +132,9 @@ namespace DownKyi case Downloader.ARIA: downloadService = new AriaDownloadService(DownloadingList, DownloadedList); break; + case Downloader.CUSTOM_ARIA: + downloadService = new CustomAriaDownloadService(DownloadingList, DownloadedList); + break; } if (downloadService != null) { diff --git a/src/DownKyi/DownKyi.csproj b/src/DownKyi/DownKyi.csproj index aac8fe5..ebc1fa4 100644 --- a/src/DownKyi/DownKyi.csproj +++ b/src/DownKyi/DownKyi.csproj @@ -117,6 +117,7 @@ + diff --git a/src/DownKyi/Languages/Default.xaml b/src/DownKyi/Languages/Default.xaml index ce65c29..e0ced81 100644 --- a/src/DownKyi/Languages/Default.xaml +++ b/src/DownKyi/Languages/Default.xaml @@ -188,7 +188,10 @@ 选择下载器(重启生效): 内建下载器(测试) Aria2下载器 + 自定义Aria2下载器 + Aria服务器地址: Aria服务器端口: + Aria服务器Token: Aria日志等级: Aria同时下载数: Aria最大线程数: diff --git a/src/DownKyi/Services/Download/AriaDownloadService.cs b/src/DownKyi/Services/Download/AriaDownloadService.cs index 34ef063..57ede1b 100644 --- a/src/DownKyi/Services/Download/AriaDownloadService.cs +++ b/src/DownKyi/Services/Download/AriaDownloadService.cs @@ -232,6 +232,11 @@ namespace DownKyi.Services.Download /// public void Start() { + // 设置aria token + AriaClient.SetToken(); + // 设置aria host + AriaClient.SetHost(); + // 启动Aria服务器 StartAriaServer(); diff --git a/src/DownKyi/Services/Download/CustomAriaDownloadService.cs b/src/DownKyi/Services/Download/CustomAriaDownloadService.cs new file mode 100644 index 0000000..d30e429 --- /dev/null +++ b/src/DownKyi/Services/Download/CustomAriaDownloadService.cs @@ -0,0 +1,440 @@ +using DownKyi.Core.Aria2cNet; +using DownKyi.Core.Aria2cNet.Client; +using DownKyi.Core.Aria2cNet.Client.Entity; +using DownKyi.Core.Aria2cNet.Server; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Utils; +using DownKyi.Models; +using DownKyi.Utils; +using DownKyi.ViewModels.DownloadManager; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace DownKyi.Services.Download +{ + /// + /// 音视频采用Aria下载,其余采用WebClient下载 + /// + public class CustomAriaDownloadService : DownloadService, IDownloadService + { + public CustomAriaDownloadService(ObservableCollection downloadingList, ObservableCollection downloadedList) : base(downloadingList, downloadedList) + { + Tag = "AriaDownloadService"; + } + + #region 音视频 + + /// + /// 下载音频,返回下载文件路径 + /// + /// + /// + public override string DownloadAudio(DownloadingItem downloading) + { + PlayUrlDashVideo downloadAudio = BaseDownloadAudio(downloading); + + return DownloadVideo(downloading, downloadAudio); + } + + /// + /// 下载视频,返回下载文件路径 + /// + /// + /// + public override string DownloadVideo(DownloadingItem downloading) + { + PlayUrlDashVideo downloadVideo = BaseDownloadVideo(downloading); + + return DownloadVideo(downloading, downloadVideo); + } + + /// + /// 将下载音频和视频的函数中相同代码抽象出来 + /// + /// + /// + /// + private string DownloadVideo(DownloadingItem downloading, PlayUrlDashVideo downloadVideo) + { + // 如果为空,说明没有匹配到可下载的音频视频 + if (downloadVideo == null) { return null; } + + // 下载链接 + List urls = new List(); + if (downloadVideo.BaseUrl != null) { urls.Add(downloadVideo.BaseUrl); } + if (downloadVideo.BackupUrl != null) { urls.AddRange(downloadVideo.BackupUrl); } + + // 路径 + downloading.DownloadBase.FilePath = downloading.DownloadBase.FilePath.Replace("\\", "/"); + string[] temp = downloading.DownloadBase.FilePath.Split('/'); + //string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], ""); + string path = downloading.DownloadBase.FilePath.TrimEnd(temp[temp.Length - 1].ToCharArray()); + + // 下载文件名 + string fileName = Guid.NewGuid().ToString("N"); + string key = $"{downloadVideo.Id}_{downloadVideo.Codecs}"; + + // 老版本数据库没有这一项,会变成null + if (downloading.Downloading.DownloadedFiles == null) + { + downloading.Downloading.DownloadedFiles = new List(); + } + + if (downloading.Downloading.DownloadFiles.ContainsKey(key)) + { + // 如果存在,表示下载过, + // 则继续使用上次下载的文件名 + fileName = downloading.Downloading.DownloadFiles[key]; + + // 还要检查一下文件有没有被人删掉,删掉的话重新下载 + // 如果下载视频之后音频文件被人删了。此时gid还是视频的,会下错文件 + if (downloading.Downloading.DownloadedFiles.Contains(key) && File.Exists(Path.Combine(path, fileName))) + { + return Path.Combine(path, fileName); + } + } + else + { + // 记录本次下载的文件 + try + { + downloading.Downloading.DownloadFiles.Add(key, fileName); + } + catch (ArgumentException) { } + // Gid最好能是每个文件单独存储,现在复用有可能会混 + // 不过好消息是下载是按固定顺序的,而且下载了两个音频会混流不过 + downloading.Downloading.Gid = null; + } + + // 启用https + AllowStatus useSSL = SettingsManager.GetInstance().UseSSL(); + if (useSSL == AllowStatus.YES) + { + for (int i = 0; i < urls.Count; i++) + { + string url = urls[i]; + if (url.StartsWith("http://")) + { + urls[i] = url.Replace("http://", "https://"); + } + } + } + else + { + for (int i = 0; i < urls.Count; i++) + { + string url = urls[i]; + if (url.StartsWith("https://")) + { + urls[i] = url.Replace("https://", "http://"); + } + } + } + + // 开始下载 + DownloadResult downloadStatus = DownloadByAria(downloading, urls, path, fileName); + switch (downloadStatus) + { + case DownloadResult.SUCCESS: + downloading.Downloading.DownloadedFiles.Add(key); + downloading.Downloading.Gid = null; + return Path.Combine(path, fileName); + case DownloadResult.FAILED: + case DownloadResult.ABORT: + default: + return nullMark; + } + } + + #endregion + + /// + /// 下载封面 + /// + /// + public override string DownloadCover(DownloadingItem downloading, string coverUrl, string fileName) + { + return BaseDownloadCover(downloading, coverUrl, fileName); + } + + /// + /// 下载弹幕 + /// + /// + public override string DownloadDanmaku(DownloadingItem downloading) + { + return BaseDownloadDanmaku(downloading); + } + + /// + /// 下载字幕 + /// + /// + public override List DownloadSubtitle(DownloadingItem downloading) + { + return BaseDownloadSubtitle(downloading); + } + + /// + /// 混流音频和视频 + /// + /// + /// + /// + /// + public override string MixedFlow(DownloadingItem downloading, string audioUid, string videoUid) + { + if (videoUid == nullMark) + { + return null; + } + return BaseMixedFlow(downloading, audioUid, videoUid); + } + + /// + /// 解析视频流的下载链接 + /// + /// + public override void Parse(DownloadingItem downloading) + { + BaseParse(downloading); + } + + /// + /// 停止下载服务(转换await和Task.Wait两种调用形式) + /// + private async Task EndTask() + { + // 停止基本任务 + await BaseEndTask(); + + // 关闭Aria服务器 + await CloseAriaServer(); + } + + /// + /// 停止下载服务 + /// + public void End() + { + Task.Run(EndTask).Wait(); + } + + /// + /// 启动下载服务 + /// + public void Start() + { + // 设置aria token + AriaClient.SetToken(SettingsManager.GetInstance().GetAriaToken()); + // 设置aria host + AriaClient.SetHost(SettingsManager.GetInstance().GetAriaHost()); + + // 启动基本服务 + BaseStart(); + } + + /// + /// 强制暂停 + /// + /// + /// + protected override void Pause(DownloadingItem downloading) + { + cancellationToken.ThrowIfCancellationRequested(); + + downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + if (downloading.Downloading.DownloadStatus == DownloadStatus.PAUSE) + { + throw new OperationCanceledException("Stop thread by pause"); + } + // 是否存在 + var isExist = IsExist(downloading); + if (!isExist.Result) + { + throw new OperationCanceledException("Task is deleted"); + } + } + + /// + /// 是否存在于下载列表中 + /// + /// + /// + private async Task IsExist(DownloadingItem downloading) + { + bool isExist = downloadingList.Contains(downloading); + if (isExist) + { + return true; + } + else + { + // 先恢复为waiting状态,暂停状态下Remove会导致文件重新下载,原因暂不清楚 + await AriaClient.UnpauseAsync(downloading.Downloading.Gid); + // 移除下载项 + var ariaRemove = await AriaClient.RemoveAsync(downloading.Downloading.Gid); + if (ariaRemove == null || ariaRemove.Result == downloading.Downloading.Gid) + { + // 从内存中删除下载项 + await AriaClient.RemoveDownloadResultAsync(downloading.Downloading.Gid); + } + + return false; + } + } + + /// + /// 关闭Aria服务器 + /// + private async Task CloseAriaServer() + { + // 暂停所有下载 + var ariaPause = await AriaClient.PauseAllAsync(); +#if DEBUG + Core.Utils.Debugging.Console.PrintLine(ariaPause.ToString()); +#endif + + // 关闭服务器 + bool close = AriaServer.CloseServer(); +#if DEBUG + Core.Utils.Debugging.Console.PrintLine(close); +#endif + } + + /// + /// 采用Aria下载文件 + /// + /// + /// + private DownloadResult DownloadByAria(DownloadingItem downloading, List urls, string path, string localFileName) + { + // path已斜杠结尾,去掉斜杠 + path = path.TrimEnd('/').TrimEnd('\\'); + + //检查gid对应任务,如果已创建那么直接使用 + //但是代理设置会出现不能随时更新的问题 + + if (downloading.Downloading.Gid != null) + { + Task status = AriaClient.TellStatus(downloading.Downloading.Gid); + if (status == null || status.Result == null) + downloading.Downloading.Gid = null; + else if (status.Result.Result == null && status.Result.Error != null) + { + if (status.Result.Error.Message.Contains("is not found")) + { + downloading.Downloading.Gid = null; + } + } + + } + + if (downloading.Downloading.Gid == null) + { + AriaSendOption option = new AriaSendOption + { + //HttpProxy = $"http://{Settings.GetAriaHttpProxy()}:{Settings.GetAriaHttpProxyListenPort()}", + Dir = path, + Out = localFileName, + //Header = $"cookie: {LoginHelper.GetLoginInfoCookiesString()}\nreferer: https://www.bilibili.com", + //UseHead = "true", + UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36", + }; + + //// 如果设置了代理,则增加HttpProxy + //if (SettingsManager.GetInstance().IsAriaHttpProxy() == AllowStatus.YES) + //{ + // option.HttpProxy = $"http://{SettingsManager.GetInstance().GetAriaHttpProxy()}:{SettingsManager.GetInstance().GetAriaHttpProxyListenPort()}"; + //} + + // 添加一个下载 + Task ariaAddUri = AriaClient.AddUriAsync(urls, option); + if (ariaAddUri == null || ariaAddUri.Result == null || ariaAddUri.Result.Result == null) + { + return DownloadResult.FAILED; + } + + // 保存gid + string gid = ariaAddUri.Result.Result; + downloading.Downloading.Gid = gid; + } + else + { + Task ariaUnpause = AriaClient.UnpauseAsync(downloading.Downloading.Gid); + } + + // 管理下载 + AriaManager ariaManager = new AriaManager(); + ariaManager.TellStatus += AriaTellStatus; + ariaManager.DownloadFinish += AriaDownloadFinish; + return ariaManager.GetDownloadStatus(downloading.Downloading.Gid, new Action(() => + { + cancellationToken.ThrowIfCancellationRequested(); + switch (downloading.Downloading.DownloadStatus) + { + case DownloadStatus.PAUSE: + Task ariaPause = AriaClient.PauseAsync(downloading.Downloading.Gid); + // 通知UI,并阻塞当前线程 + Pause(downloading); + break; + case DownloadStatus.DOWNLOADING: + break; + } + })); + } + + private void AriaTellStatus(long totalLength, long completedLength, long speed, string gid) + { + // 当前的下载视频 + DownloadingItem video = null; + try + { + video = downloadingList.FirstOrDefault(it => it.Downloading.Gid == gid); + } + catch (InvalidOperationException e) + { + Core.Utils.Debugging.Console.PrintLine("AriaTellStatus()发生异常: {0}", e); + LogManager.Error("AriaTellStatus()", e); + } + + if (video == null) { return; } + + // 下载进度百分比 + float percent = 0; + if (totalLength != 0) + { + percent = (float)completedLength / totalLength * 100; + } + + // 根据进度判断本次是否需要更新UI + if (Math.Abs(percent - video.Progress) < 0.01) { return; } + + // 下载进度 + video.Progress = percent; + + // 下载大小 + video.DownloadingFileSize = Format.FormatFileSize(completedLength) + "/" + Format.FormatFileSize(totalLength); + + // 下载速度 + video.SpeedDisplay = Format.FormatSpeed(speed); + + // 最大下载速度 + if (video.Downloading.MaxSpeed < speed) + { + video.Downloading.MaxSpeed = speed; + } + } + + private void AriaDownloadFinish(bool isSuccess, string downloadPath, string gid, string msg) + { + //throw new NotImplementedException(); + } + } +} diff --git a/src/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs b/src/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs index a46ce58..98c40c3 100644 --- a/src/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs +++ b/src/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs @@ -41,6 +41,13 @@ namespace DownKyi.ViewModels.Settings set => SetProperty(ref aria2c, value); } + private bool customAria2c; + public bool CustomAria2c + { + get => customAria2c; + set => SetProperty(ref customAria2c, value); + } + private List maxCurrentDownloads; public List MaxCurrentDownloads { @@ -90,6 +97,13 @@ namespace DownKyi.ViewModels.Settings set => SetProperty(ref httpProxyPort, value); } + private string ariaHost; + public string AriaHost + { + get => ariaHost; + set => SetProperty(ref ariaHost, value); + } + private int ariaListenPort; public int AriaListenPort { @@ -97,6 +111,13 @@ namespace DownKyi.ViewModels.Settings set => SetProperty(ref ariaListenPort, value); } + private string ariaToken; + public string AriaToken + { + get => ariaToken; + set => SetProperty(ref ariaToken, value); + } + private List ariaLogLevels; public List AriaLogLevels { @@ -259,6 +280,9 @@ namespace DownKyi.ViewModels.Settings case Downloader.ARIA: Aria2c = true; break; + case Downloader.CUSTOM_ARIA: + CustomAria2c = true; + break; } // builtin同时下载数 @@ -277,9 +301,15 @@ namespace DownKyi.ViewModels.Settings // builtin的http代理的端口 HttpProxyPort = SettingsManager.GetInstance().GetHttpProxyListenPort(); + // Aria服务器host + AriaHost = SettingsManager.GetInstance().GetAriaHost(); + // Aria服务器端口 AriaListenPort = SettingsManager.GetInstance().GetAriaListenPort(); + // Aria服务器Token + AriaToken = SettingsManager.GetInstance().GetAriaToken(); + // Aria的日志等级 AriaConfigLogLevel ariaLogLevel = SettingsManager.GetInstance().GetAriaLogLevel(); SelectedAriaLogLevel = ariaLogLevel.ToString("G"); @@ -349,6 +379,9 @@ namespace DownKyi.ViewModels.Settings case "Aria2c": downloader = Downloader.ARIA; break; + case "CustomAria2c": + downloader = Downloader.CUSTOM_ARIA; + break; default: downloader = SettingsManager.GetInstance().GetDownloader(); break; @@ -444,6 +477,21 @@ namespace DownKyi.ViewModels.Settings PublishTip(isSucceed); } + // Aria服务器host事件 + private DelegateCommand ariaHostCommand; + public DelegateCommand AriaHostCommand => ariaHostCommand ?? (ariaHostCommand = new DelegateCommand(ExecuteAriaHostCommand)); + + /// + /// Aria服务器host事件 + /// + /// + private void ExecuteAriaHostCommand(string parameter) + { + AriaHost = parameter; + bool isSucceed = SettingsManager.GetInstance().SetAriaHost(AriaHost); + PublishTip(isSucceed); + } + // Aria服务器端口事件 private DelegateCommand ariaListenPortCommand; public DelegateCommand AriaListenPortCommand => ariaListenPortCommand ?? (ariaListenPortCommand = new DelegateCommand(ExecuteAriaListenPortCommand)); @@ -461,6 +509,21 @@ namespace DownKyi.ViewModels.Settings PublishTip(isSucceed); } + // Aria服务器token事件 + private DelegateCommand ariaTokenCommand; + public DelegateCommand AriaTokenCommand => ariaTokenCommand ?? (ariaTokenCommand = new DelegateCommand(ExecuteAriaTokenCommand)); + + /// + /// Aria服务器token事件 + /// + /// + private void ExecuteAriaTokenCommand(string parameter) + { + AriaToken = parameter; + bool isSucceed = SettingsManager.GetInstance().SetAriaToken(AriaToken); + PublishTip(isSucceed); + } + // Aria的日志等级事件 private DelegateCommand ariaLogLevelsCommand; public DelegateCommand AriaLogLevelsCommand => ariaLogLevelsCommand ?? (ariaLogLevelsCommand = new DelegateCommand(ExecuteAriaLogLevelsCommand)); diff --git a/src/DownKyi/Views/Settings/ViewNetwork.xaml b/src/DownKyi/Views/Settings/ViewNetwork.xaml index 23a3e49..884df8e 100644 --- a/src/DownKyi/Views/Settings/ViewNetwork.xaml +++ b/src/DownKyi/Views/Settings/ViewNetwork.xaml @@ -56,6 +56,15 @@ Foreground="{DynamicResource BrushTextDark}" IsChecked="{Binding Aria2c}" Style="{StaticResource RadioStyle}" /> + @@ -208,6 +217,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +