From 31dfd6ffafc56dc54aeaa786853db37e94f53f9e Mon Sep 17 00:00:00 2001
From: yaobiao131 <28655758+yaobiao131@users.noreply.github.com>
Date: Mon, 16 Jun 2025 21:02:26 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=B9=B6=E4=BC=98=E5=8C=96=E4=B8=8B=E8=BD=BD?=
=?UTF-8?q?=E5=88=97=E8=A1=A8=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Directory.Packages.props | 5 +-
DownKyi.Core/DownKyi.Core.csproj | 1 -
DownKyi/App.axaml.cs | 155 +++++----
DownKyi/DownKyi.csproj | 10 +-
DownKyi/Models/DownloadBase.cs | 53 +--
DownKyi/Models/Downloaded.cs | 21 +-
DownKyi/Models/Downloading.cs | 35 +-
.../Services/Download/AddToDownloadService.cs | 43 ++-
.../Services/Download/AriaDownloadService.cs | 12 +-
.../Download/BuiltinDownloadService.cs | 10 +-
.../Download/CustomAriaDownloadService.cs | 12 +-
DownKyi/Services/Download/DownloadService.cs | 144 ++++----
.../Download/DownloadStorageService.cs | 39 ++-
.../Utils/DataAnnotations/JsonMapAttribute.cs | 10 +
DownKyi/Utils/JsonMapCore.cs | 274 +++++++++++++++
.../NewVersionAvailableDialogViewModel.cs | 1 -
.../Dialogs/ViewUpgradingDialogViewModel.cs | 129 +++----
.../DownloadManager/DownloadBaseItem.cs | 17 +-
.../DownloadManager/DownloadedItem.cs | 241 ++++---------
.../DownloadManager/DownloadingItem.cs | 27 +-
.../ViewDownloadFinishedViewModel.cs | 328 +++++++++++-------
.../ViewDownloadingViewModel.cs | 62 ++--
.../ViewDownloadFinished.axaml | 10 +-
.../DownloadManager/ViewDownloading.axaml | 4 +-
24 files changed, 912 insertions(+), 731 deletions(-)
create mode 100644 DownKyi/Utils/DataAnnotations/JsonMapAttribute.cs
create mode 100644 DownKyi/Utils/JsonMapCore.cs
diff --git a/Directory.Packages.props b/Directory.Packages.props
index dcad14f..268acbf 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,8 +5,9 @@
-
-
+
+
+
diff --git a/DownKyi.Core/DownKyi.Core.csproj b/DownKyi.Core/DownKyi.Core.csproj
index 6da4cdd..c2bec4f 100644
--- a/DownKyi.Core/DownKyi.Core.csproj
+++ b/DownKyi.Core/DownKyi.Core.csproj
@@ -15,7 +15,6 @@
-
diff --git a/DownKyi/App.axaml.cs b/DownKyi/App.axaml.cs
index db92d17..e0a541f 100644
--- a/DownKyi/App.axaml.cs
+++ b/DownKyi/App.axaml.cs
@@ -29,9 +29,9 @@ using DownKyi.Views.Friends;
using DownKyi.Views.Settings;
using DownKyi.Views.Toolbox;
using DownKyi.Views.UserSpace;
+using FreeSql;
using Prism.DryIoc;
using Prism.Ioc;
-using SqlSugar;
using ViewSeasonsSeries = DownKyi.Views.ViewSeasonsSeries;
using ViewSeasonsSeriesViewModel = DownKyi.ViewModels.ViewSeasonsSeriesViewModel;
@@ -41,7 +41,7 @@ public partial class App : PrismApplication
{
public const string RepoOwner = "yaobiao131";
public const string RepoName = "downkyicore";
-
+
public static ObservableCollection DownloadingList { get; set; } = new();
public static ObservableCollection DownloadedList { get; set; } = new();
public new static App Current => (App)Application.Current!;
@@ -49,18 +49,19 @@ public partial class App : PrismApplication
public IClassicDesktopStyleApplicationLifetime? AppLife;
private static Mutex _mutex;
+
// 下载服务
private IDownloadService? _downloadService;
public override void Initialize()
{
- #if !DEBUG
+#if !DEBUG
_mutex = new Mutex(true, "Global\\DownKyi", out var createdNew);
if (!createdNew)
{
Environment.Exit(0);
}
- #endif
+#endif
AvaloniaXamlLoader.Load(this);
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
@@ -74,37 +75,33 @@ public partial class App : PrismApplication
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
- containerRegistry.RegisterSingleton(() => new SqlSugarScope(new ConnectionConfig
- {
- DbType = DbType.Sqlite,
- ConnectionString = $"datasource={StorageManager.GetDbPath()}",
- IsAutoCloseConnection = true,
- },
- db =>
- {
- db.Aop.OnLogExecuting = (sql, pars) =>
- {
- if (pars != null && pars.Length > 0)
- {
- string fullSql = sql;
- foreach (var param in pars)
- {
- // 处理参数值的格式
- var value = param.Value is string || param.Value is DateTime
- ? $"'{param.Value}'"
- : param.Value?.ToString() ?? "NULL";
- fullSql = fullSql.Replace(param.ParameterName, value);
- }
-
- Console.WriteLine($"完整SQL: {fullSql}");
- }
- else
- {
- Console.WriteLine($"SQL: {sql}");
- }
- };
- })
- );
+ containerRegistry.RegisterSingleton(() =>
+ {
+ var freeSql = new FreeSqlBuilder()
+ .UseConnectionString(DataType.Sqlite, $"Data Source={StorageManager.GetDbPath()}")
+ .UseAdoConnectionPool(true)
+#if DEBUG
+ .UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}"))
+#endif
+ .Build();
+ freeSql.UseJsonMap();
+ return freeSql;
+ });
+ containerRegistry.RegisterSingleton();
+ containerRegistry.RegisterScoped>(cp =>
+ {
+ var freeSql = (IFreeSql)cp.Resolve(typeof(IFreeSql));
+ var downloadingRepository = freeSql.GetRepository();
+ downloadingRepository.DbContextOptions.EnableCascadeSave = true;
+ return downloadingRepository;
+ });
+ containerRegistry.RegisterScoped>(cp =>
+ {
+ var freeSql = (IFreeSql)cp.Resolve(typeof(IFreeSql));
+ var downloadRepository = freeSql.GetRepository();
+ downloadRepository.DbContextOptions.EnableCascadeSave = true;
+ return downloadRepository;
+ });
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
@@ -169,11 +166,11 @@ public partial class App : PrismApplication
{
if (!Design.IsDesignMode)
{
- Container.Resolve().CodeFirst.InitTables(typeof(DownloadBase), typeof(Downloaded), typeof(Downloading));
+ Container.Resolve().CodeFirst.SyncStructure(typeof(DownloadBase), typeof(Downloaded), typeof(Downloading));
}
// 下载数据存储服务
- var downloadStorageService = new DownloadStorageService();
+ var downloadStorageService = Container.Resolve();
// 从数据库读取
var downloadingItems = downloadStorageService.GetDownloading();
@@ -217,37 +214,37 @@ public partial class App : PrismApplication
};
// 下载完成列表发生变化时执行的任务
- DownloadedList.CollectionChanged += async (sender, e) =>
- {
- await Task.Run(() =>
- {
- if (e.Action == NotifyCollectionChangedAction.Add)
- {
- if (e.NewItems == null) return;
- foreach (var item in e.NewItems)
- {
- if (item is DownloadedItem downloaded)
- {
- //Console.WriteLine("DownloadedList添加");
- downloadStorageService.AddDownloaded(downloaded);
- }
- }
- }
-
- if (e.Action == NotifyCollectionChangedAction.Remove)
- {
- if (e.OldItems == null) return;
- foreach (var item in e.OldItems)
- {
- if (item is DownloadedItem downloaded)
- {
- //Console.WriteLine("DownloadedList移除");
- downloadStorageService.RemoveDownloaded(downloaded);
- }
- }
- }
- });
- };
+ // DownloadedList.CollectionChanged += async (sender, e) =>
+ // {
+ // await Task.Run(() =>
+ // {
+ // if (e.Action == NotifyCollectionChangedAction.Add)
+ // {
+ // if (e.NewItems == null) return;
+ // foreach (var item in e.NewItems)
+ // {
+ // if (item is DownloadedItem downloaded)
+ // {
+ // //Console.WriteLine("DownloadedList添加");
+ // downloadStorageService.AddDownloaded(downloaded);
+ // }
+ // }
+ // }
+ //
+ // if (e.Action == NotifyCollectionChangedAction.Remove)
+ // {
+ // if (e.OldItems == null) return;
+ // foreach (var item in e.OldItems)
+ // {
+ // if (item is DownloadedItem downloaded)
+ // {
+ // //Console.WriteLine("DownloadedList移除");
+ // downloadStorageService.RemoveDownloaded(downloaded);
+ // }
+ // }
+ // }
+ // });
+ // };
// 启动下载服务
var download = SettingsManager.GetInstance().GetDownloader();
@@ -295,33 +292,43 @@ public partial class App : PrismApplication
///
public static void SortDownloadedList(DownloadFinishedSort finishedSort)
{
- var list = DownloadedList?.ToList();
+ var list = DownloadedList.ToList();
switch (finishedSort)
{
case DownloadFinishedSort.DownloadAsc:
// 按下载先后排序
- list?.Sort((x, y) => x.Downloaded.FinishedTimestamp.CompareTo(y.Downloaded.FinishedTimestamp));
+ list.Sort((x, y) => x.Downloaded.FinishedTimestamp.CompareTo(y.Downloaded.FinishedTimestamp));
break;
case DownloadFinishedSort.DownloadDesc:
// 按下载先后排序
- list?.Sort((x, y) => y.Downloaded.FinishedTimestamp.CompareTo(x.Downloaded.FinishedTimestamp));
+ list.Sort((x, y) => y.Downloaded.FinishedTimestamp.CompareTo(x.Downloaded.FinishedTimestamp));
break;
case DownloadFinishedSort.Number:
// 按序号排序
- list?.Sort((x, y) =>
+ list.Sort((x, y) =>
{
var compare = string.Compare(x.MainTitle, y.MainTitle, StringComparison.Ordinal);
return compare == 0 ? x.Order.CompareTo(y.Order) : compare;
});
break;
+ case DownloadFinishedSort.NotSet:
default:
break;
}
// 更新下载完成列表
// 如果有更好的方法再重写
- DownloadedList?.Clear();
- list?.ForEach(item => DownloadedList?.Add(item));
+ DownloadedList.Clear();
+ list.ForEach(item => DownloadedList.Add(item));
+ }
+
+ public void RefreshDownloadedList()
+ {
+ // 重新获取下载完成列表
+ var downloadStorageService = Container.Resolve();
+ var downloadedItems = downloadStorageService.GetDownloaded();
+ DownloadedList.Clear();
+ DownloadedList.AddRange(downloadedItems);
}
private void OnExit(object sender, ControlledApplicationLifetimeExitEventArgs e)
diff --git a/DownKyi/DownKyi.csproj b/DownKyi/DownKyi.csproj
index 4266b92..c484b06 100644
--- a/DownKyi/DownKyi.csproj
+++ b/DownKyi/DownKyi.csproj
@@ -31,9 +31,11 @@
+
+
+
-
@@ -42,10 +44,4 @@
-
-
-
- Always
-
-
diff --git a/DownKyi/Models/DownloadBase.cs b/DownKyi/Models/DownloadBase.cs
index 8924684..155454c 100644
--- a/DownKyi/Models/DownloadBase.cs
+++ b/DownKyi/Models/DownloadBase.cs
@@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using DownKyi.Core.BiliApi.BiliUtils;
+using DownKyi.Utils.DataAnnotations;
+using FreeSql.DataAnnotations;
namespace DownKyi.Models;
-[Serializable]
-[SqlSugar.SugarTable("download_base", TableDescription = "下载项的基础信息")]
+[Table(Name = "download_base")]
+[Description("下载项的基础信息")]
public class DownloadBase
{
public DownloadBase()
@@ -25,75 +28,75 @@ public class DownloadBase
}
// 此条下载项的id
- [SqlSugar.SugarColumn(IsPrimaryKey = true, ColumnName = "id")]
+ [Column(IsPrimary = true, Name = "id")]
public string Id { get; set; }
// 需要下载的内容
- [SqlSugar.SugarColumn(IsJson = true, ColumnName = "need_download_content")]
+ [Column(Name = "need_download_content"),]
public Dictionary NeedDownloadContent { get; set; }
// 视频的id
- [SqlSugar.SugarColumn(ColumnName = "bvid")]
- public string Bvid { get; set; }
+ [Column(Name = "bvid")] public string Bvid { get; set; }
- [SqlSugar.SugarColumn(ColumnName = "avid")]
- public long Avid { get; set; }
+ [Column(Name = "avid")] public long Avid { get; set; }
- [SqlSugar.SugarColumn(ColumnName = "cid")]
- public long Cid { get; set; }
+ [Column(Name = "cid")] public long Cid { get; set; }
- [SqlSugar.SugarColumn(ColumnName = "episode_id")]
- public long EpisodeId { get; set; }
+ [Column(Name = "episode_id")] public long EpisodeId { get; set; }
// 视频封面的url
- [SqlSugar.SugarColumn(ColumnName = "cover_url", ColumnDescription = "视频封面的url")]
+ [Column(Name = "cover_url"), Description("视频封面的url")]
public string CoverUrl { get; set; }
// 视频page的封面的url
- [SqlSugar.SugarColumn(ColumnName = "page_cover_url", ColumnDescription = "视频page的封面的url")]
+ [Column(Name = "page_cover_url"), Description("视频page的封面的url")]
public string PageCoverUrl { get; set; }
// 分区id
- [SqlSugar.SugarColumn(ColumnName = "zone_id", ColumnDescription = "分区id")]
+ [Column(Name = "zone_id"), Description("分区id")]
public int ZoneId { get; set; }
// 视频序号
- [SqlSugar.SugarColumn(ColumnName = "order", ColumnDescription = "视频序号")]
+ [Column(Name = "order"), Description("视频序号")]
public int Order { get; set; }
// 视频主标题
- [SqlSugar.SugarColumn(ColumnName = "main_title", ColumnDescription = "视频主标题")]
+ [Column(Name = "main_title"), Description("视频主标题")]
public string MainTitle { get; set; }
// 视频标题
- [SqlSugar.SugarColumn(ColumnName = "name", ColumnDescription = "视频标题")]
+ [Column(Name = "name"), Description("视频标题")]
public string Name { get; set; }
// 时长
- [SqlSugar.SugarColumn(ColumnName = "duration", ColumnDescription = "时长")]
+ [Column(Name = "duration"), Description("时长")]
public string Duration { get; set; }
// 视频编码名称,AVC、HEVC
- [SqlSugar.SugarColumn(ColumnName = "video_codec_name", ColumnDescription = "视频编码名称,AVC、HEVC")]
+ [Column(Name = "video_codec_name")]
+ [Description("视频编码名称,AVC、HEVC")]
public string VideoCodecName { get; set; }
// 视频画质
- [SqlSugar.SugarColumn(ColumnName = "resolution", ColumnDescription = "视频画质", IsJson = true)]
+ [Column(Name = "resolution"), Description("视频画质"), JsonMap]
public Quality Resolution { get; set; }
// 音频编码
- [SqlSugar.SugarColumn(ColumnName = "audio_codec", ColumnDescription = "音频编码", IsJson = true,IsNullable = true)]
+ [Column(Name = "audio_codec", IsNullable = true), Description("音频编码"), JsonMap]
public Quality AudioCodec { get; set; }
// 文件路径,不包含扩展名,所有内容均以此路径下载
- [SqlSugar.SugarColumn(ColumnName = "file_path", ColumnDescription = "文件路径,不包含扩展名,所有内容均以此路径下载")]
+ [Column(Name = "file_path"), Description("文件路径,不包含扩展名,所有内容均以此路径下载")]
public string FilePath { get; set; }
// 文件大小
- [SqlSugar.SugarColumn(ColumnName = "file_size", ColumnDescription = "文件大小", IsNullable = true)]
+ [Column(Name = "file_size", IsNullable = true), Description("文件大小")]
public string? FileSize { get; set; }
// 视频分p(默认为1)
- [SqlSugar.SugarColumn(ColumnName = "page", ColumnDescription = "视频分p(默认为1)")]
+ [Column(Name = "page"), Description("视频分p(默认为1)")]
public int Page { get; set; } = 1;
+
+ [Navigate(nameof(Id))] public Downloaded? Downloaded { get; set; }
+ [Navigate(nameof(Id))] public Downloading? Downloading { get; set; }
}
\ No newline at end of file
diff --git a/DownKyi/Models/Downloaded.cs b/DownKyi/Models/Downloaded.cs
index 9a479c6..822f404 100644
--- a/DownKyi/Models/Downloaded.cs
+++ b/DownKyi/Models/Downloaded.cs
@@ -1,21 +1,19 @@
using System;
-using SqlSugar;
+using FreeSql.DataAnnotations;
namespace DownKyi.Models;
-[Serializable]
-[SugarTable(TableName = "downloaded")]
+[Table(Name = "downloaded")]
public class Downloaded
{
- [SugarColumn(IsPrimaryKey = true, ColumnName = "id")]
+ [Column(IsPrimary = true, Name = "id")]
public string Id { get; set; } = null!;
+
// 下载速度
- [SugarColumn(ColumnName = "max_speed_display")]
- public string? MaxSpeedDisplay { get; set; }
+ [Column(Name = "max_speed_display")] public string? MaxSpeedDisplay { get; set; }
// 完成时间戳
- [SugarColumn(ColumnName = "finished_timestamp")]
- public long FinishedTimestamp { get; set; }
+ [Column(Name = "finished_timestamp")] public long FinishedTimestamp { get; set; }
public void SetFinishedTimestamp(long finishedTimestamp)
{
@@ -27,10 +25,7 @@ public class Downloaded
}
// 完成时间
- [SugarColumn(ColumnName = "finished_time")]
- public string FinishedTime { get; set; }
+ [Column(Name = "finished_time")] public string FinishedTime { get; set; }
- [Navigate(NavigateType.OneToOne, nameof(Id))]
- [SugarColumn(IsIgnore = true)]
- public DownloadBase DownloadBase { get; set; }
+ [Navigate(nameof(Id))] public DownloadBase? DownloadBase { get; set; }
}
\ No newline at end of file
diff --git a/DownKyi/Models/Downloading.cs b/DownKyi/Models/Downloading.cs
index 7d577e6..810e62a 100644
--- a/DownKyi/Models/Downloading.cs
+++ b/DownKyi/Models/Downloading.cs
@@ -1,61 +1,56 @@
using System;
using System.Collections.Generic;
using DownKyi.Core.BiliApi.VideoStream;
-using Downloader;
-using SqlSugar;
+using DownKyi.Utils.DataAnnotations;
+using FreeSql.DataAnnotations;
namespace DownKyi.Models;
[Serializable]
public class Downloading
{
- [SugarColumn(IsPrimaryKey = true, ColumnName = "id")]
+ [Column(IsPrimary = true, Name = "id")]
public string Id { get; set; } = null!;
// Aria相关
- [SugarColumn(ColumnName = "gid", IsNullable = true)]
+ [Column(Name = "gid", IsNullable = true)]
public string? Gid { get; set; }
// 下载的文件
- [SugarColumn(ColumnName = "download_files", IsJson = true)]
+ [Column(Name = "download_files"), JsonMap]
public Dictionary DownloadFiles { get; set; } = new();
// 已下载的文件
- [SugarColumn(ColumnName = "downloaded_files", IsJson = true)]
+ [Column(Name = "downloaded_files"), JsonMap]
public List DownloadedFiles { get; set; } = new();
// 视频类别
- [SugarColumn(ColumnName = "play_stream_type")]
- public PlayStreamType PlayStreamType { get; set; }
+ [Column(Name = "play_stream_type")] public PlayStreamType PlayStreamType { get; set; }
// 下载状态
- [SugarColumn(ColumnName = "download_status")]
- public DownloadStatus DownloadStatus { get; set; }
+ [Column(Name = "download_status")] public DownloadStatus DownloadStatus { get; set; }
// 正在下载内容(音频、视频、弹幕、字幕、封面)
- [SugarColumn(ColumnName = "download_content", IsNullable = true)]
+ [Column(Name = "download_content", IsNullable = true)]
public string? DownloadContent { get; set; }
// 下载状态显示
- [SugarColumn(ColumnName = "download_status_title", IsNullable = true)]
+ [Column(Name = "download_status_title", IsNullable = true)]
public string? DownloadStatusTitle { get; set; }
// 下载进度
- [SugarColumn(ColumnName = "progress")] public float Progress { get; set; }
+ [Column(Name = "progress")] public float Progress { get; set; }
// 已下载大小/文件大小
- [SugarColumn(ColumnName = "downloading_file_size", IsNullable = true)]
+ [Column(Name = "downloading_file_size", IsNullable = true)]
public string? DownloadingFileSize { get; set; }
// 下载的最高速度
- [SugarColumn(ColumnName = "max_speed")]
- public long MaxSpeed { get; set; }
+ [Column(Name = "max_speed")] public long MaxSpeed { get; set; }
// 下载速度
- [SugarColumn(ColumnName = "speed_display", IsNullable = true)]
+ [Column(Name = "speed_display", IsNullable = true)]
public string? SpeedDisplay { get; set; }
- [Navigate(NavigateType.OneToOne, nameof(Id))]
- [SugarColumn(IsIgnore = true)]
- public DownloadBase DownloadBase { get; set; }
+ [Navigate(nameof(Id))] public DownloadBase? DownloadBase { get; set; }
}
\ No newline at end of file
diff --git a/DownKyi/Services/Download/AddToDownloadService.cs b/DownKyi/Services/Download/AddToDownloadService.cs
index 9da6cac..d1494e7 100644
--- a/DownKyi/Services/Download/AddToDownloadService.cs
+++ b/DownKyi/Services/Download/AddToDownloadService.cs
@@ -33,6 +33,7 @@ public class AddToDownloadService
private IInfoService _videoInfoService;
private VideoInfoView? _videoInfoView;
private List? _videoSections;
+ private DownloadStorageService _downloadStorageService = (DownloadStorageService)App.Current.Container.Resolve(typeof(DownloadStorageService));
// 下载内容
private bool _downloadAudio = true;
@@ -297,7 +298,7 @@ public class AddToDownloadService
continue;
}
- bool f = item.DownloadBase.Cid == page.Cid &&
+ bool f = item.DownloadBase.Cid == page.Cid &&
item.Resolution.Id == page.VideoQuality.Quality &&
item.VideoCodecName == page.VideoQuality.SelectedVideoCodec &&
(
@@ -328,7 +329,7 @@ public class AddToDownloadService
continue;
}
- bool f = item.DownloadBase.Cid == page.Cid &&
+ bool f = item.DownloadBase.Cid == page.Cid &&
item.Resolution.Id == page.VideoQuality.Quality &&
item.VideoCodecName == page.VideoQuality.SelectedVideoCodec &&
(
@@ -344,30 +345,34 @@ public class AddToDownloadService
switch (repeatDownloadStrategy)
{
case RepeatDownloadStrategy.Ask:
+ {
+ var result = ButtonResult.Cancel;
+ await Dispatcher.UIThread.Invoke(async () =>
{
- var result = ButtonResult.Cancel;
- await Dispatcher.UIThread.Invoke(async () =>
- {
- var param = new DialogParameters
+ var param = new DialogParameters
{
{ "message", $"{item.Name}已下载,是否重新下载" },
};
- await dialogService.ShowDialogAsync(ViewAlreadyDownloadedDialogViewModel.Tag, param, buttonResult => { result = buttonResult.Result; });
+ await dialogService.ShowDialogAsync(ViewAlreadyDownloadedDialogViewModel.Tag, param, buttonResult => { result = buttonResult.Result; });
+ });
+
+ if (result == ButtonResult.OK)
+ {
+ App.PropertyChangeAsync(() =>
+ {
+ App.DownloadedList.Remove(item);
+ _downloadStorageService.RemoveDownloaded(item);
});
-
- if (result == ButtonResult.OK)
- {
- App.PropertyChangeAsync(() => { App.DownloadedList.Remove(item); });
- isDownloaded = false;
- }
- else
- {
- isDownloaded = true;
- }
-
- break;
+ isDownloaded = false;
}
+ else
+ {
+ isDownloaded = true;
+ }
+
+ break;
+ }
case RepeatDownloadStrategy.ReDownload:
isDownloaded = false;
break;
diff --git a/DownKyi/Services/Download/AriaDownloadService.cs b/DownKyi/Services/Download/AriaDownloadService.cs
index 85f70fe..efc1bbb 100644
--- a/DownKyi/Services/Download/AriaDownloadService.cs
+++ b/DownKyi/Services/Download/AriaDownloadService.cs
@@ -176,7 +176,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
case DownloadResult.FAILED:
case DownloadResult.ABORT:
default:
- return nullMark;
+ return NullMark;
}
}
@@ -221,7 +221,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
///
public override string MixedFlow(DownloadingItem downloading, string? audioUid, string? videoUid)
{
- if (videoUid == nullMark)
+ if (videoUid == NullMark)
{
return null;
}
@@ -284,7 +284,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
///
protected override void Pause(DownloadingItem downloading)
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing");
if (downloading.Downloading.DownloadStatus == DownloadStatus.Pause)
@@ -307,7 +307,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
///
private async Task IsExist(DownloadingItem downloading)
{
- var isExist = downloadingList.Contains(downloading);
+ var isExist = DownloadingList.Contains(downloading);
if (isExist)
{
return true;
@@ -479,7 +479,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
ariaManager.DownloadFinish += AriaDownloadFinish;
return ariaManager.GetDownloadStatus(downloading.Downloading.Gid, new Action(() =>
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
switch (downloading.Downloading.DownloadStatus)
{
case DownloadStatus.Pause:
@@ -499,7 +499,7 @@ public class AriaDownloadService : DownloadService, IDownloadService
DownloadingItem? video = null;
try
{
- video = downloadingList.FirstOrDefault(it => it.Downloading.Gid == gid);
+ video = DownloadingList.FirstOrDefault(it => it.Downloading.Gid == gid);
}
catch (InvalidOperationException e)
{
diff --git a/DownKyi/Services/Download/BuiltinDownloadService.cs b/DownKyi/Services/Download/BuiltinDownloadService.cs
index 0421619..1fb92a0 100644
--- a/DownKyi/Services/Download/BuiltinDownloadService.cs
+++ b/DownKyi/Services/Download/BuiltinDownloadService.cs
@@ -177,7 +177,7 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
}
else
{
- return nullMark;
+ return NullMark;
}
}
catch (FileNotFoundException e)
@@ -185,7 +185,7 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
Console.PrintLine("BuiltinDownloadService.DownloadVideo()发生异常: {0}", e);
LogManager.Error("BuiltinDownloadService.DownloadVideo()", e);
- return nullMark;
+ return NullMark;
}
}
@@ -274,7 +274,7 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
///
protected override void Pause(DownloadingItem downloading)
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing");
if (downloading.Downloading.DownloadStatus == DownloadStatus.Pause)
@@ -297,7 +297,7 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
///
private bool IsExist(DownloadingItem downloading)
{
- return downloadingList.Contains(downloading);
+ return DownloadingList.Contains(downloading);
}
#region 内建下载器
@@ -379,7 +379,7 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
// 阻塞当前任务,监听暂停事件
while (!isComplete)
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
switch (downloading.Downloading.DownloadStatus)
{
case DownloadStatus.Pause:
diff --git a/DownKyi/Services/Download/CustomAriaDownloadService.cs b/DownKyi/Services/Download/CustomAriaDownloadService.cs
index a77a172..fe6120d 100644
--- a/DownKyi/Services/Download/CustomAriaDownloadService.cs
+++ b/DownKyi/Services/Download/CustomAriaDownloadService.cs
@@ -176,7 +176,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
case DownloadResult.FAILED:
case DownloadResult.ABORT:
default:
- return nullMark;
+ return NullMark;
}
}
@@ -218,7 +218,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
///
public override string MixedFlow(DownloadingItem downloading, string? audioUid, string? videoUid)
{
- if (videoUid == nullMark)
+ if (videoUid == NullMark)
{
return null;
}
@@ -278,7 +278,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
///
protected override void Pause(DownloadingItem downloading)
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing");
if (downloading.Downloading.DownloadStatus == DownloadStatus.Pause)
@@ -301,7 +301,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
///
private async Task IsExist(DownloadingItem downloading)
{
- bool isExist = downloadingList.Contains(downloading);
+ bool isExist = DownloadingList.Contains(downloading);
if (isExist)
{
return true;
@@ -408,7 +408,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
ariaManager.DownloadFinish += AriaDownloadFinish;
return ariaManager.GetDownloadStatus(downloading.Downloading.Gid, new Action(() =>
{
- cancellationToken.ThrowIfCancellationRequested();
+ CancellationToken?.ThrowIfCancellationRequested();
switch (downloading.Downloading.DownloadStatus)
{
case DownloadStatus.Pause:
@@ -428,7 +428,7 @@ public class CustomAriaDownloadService : DownloadService, IDownloadService
DownloadingItem video = null;
try
{
- video = downloadingList.FirstOrDefault(it => it.Downloading.Gid == gid);
+ video = DownloadingList.FirstOrDefault(it => it.Downloading.Gid == gid);
}
catch (InvalidOperationException e)
{
diff --git a/DownKyi/Services/Download/DownloadService.cs b/DownKyi/Services/Download/DownloadService.cs
index a0ef47c..8f1e312 100644
--- a/DownKyi/Services/Download/DownloadService.cs
+++ b/DownKyi/Services/Download/DownloadService.cs
@@ -19,7 +19,6 @@ using DownKyi.Models;
using DownKyi.PrismExtension.Dialog;
using DownKyi.Utils;
using DownKyi.ViewModels.DownloadManager;
-using ImTools;
using Console = DownKyi.Core.Utils.Debugging.Console;
namespace DownKyi.Services.Download;
@@ -30,16 +29,18 @@ public abstract class DownloadService
// protected TaskbarIcon _notifyIcon;
protected readonly IDialogService? DialogService;
- protected ObservableCollection downloadingList;
- protected ObservableCollection downloadedList;
+ protected readonly ObservableCollection DownloadingList;
+ protected readonly ObservableCollection DownloadedList;
- protected Task workTask;
- protected CancellationTokenSource tokenSource;
- protected CancellationToken cancellationToken;
- protected List downloadingTasks = new();
+ protected Task? WorkTask;
+ protected CancellationTokenSource? TokenSource;
+ protected CancellationToken? CancellationToken;
+ protected readonly List DownloadingTasks = new();
- protected readonly int retry = 5;
- protected readonly string nullMark = "";
+ protected const int Retry = 5;
+ protected const string NullMark = "";
+
+ protected readonly DownloadStorageService DownloadStorageService = (DownloadStorageService)App.Current.Container.Resolve(typeof(DownloadStorageService));
///
/// 初始化
@@ -50,8 +51,8 @@ public abstract class DownloadService
///
public DownloadService(ObservableCollection downloadingList, ObservableCollection downloadedList, IDialogService? dialogService)
{
- this.downloadingList = downloadingList;
- this.downloadedList = downloadedList;
+ DownloadingList = downloadingList;
+ DownloadedList = downloadedList;
DialogService = dialogService;
}
@@ -133,7 +134,7 @@ public abstract class DownloadService
var codecs = Constant.GetCodecIds().FirstOrDefault(t => t.Id == video.CodecId);
if (video.Id == downloading.Resolution.Id && codecs?.Name == downloading.VideoCodecName)
{
- return new()
+ return new VideoPlayUrlBasic
{
BackupUrl = video.BackupUrl,
Codecs = video.Codecs,
@@ -147,7 +148,7 @@ public abstract class DownloadService
if (downloading?.PlayUrl?.Durl?.Count > 0)
{
var durl = downloading.PlayUrl.Durl.First();
- return new()
+ return new VideoPlayUrlBasic
{
BackupUrl = durl.BackupUrl,
BaseUrl = durl.Url,
@@ -199,7 +200,7 @@ public abstract class DownloadService
downloading.SpeedDisplay = string.Empty;
var title = $"{downloading.Name}";
- var assFile = $"{downloading.DownloadBase.FilePath}.ass";
+ var assFile = $"{downloading.DownloadBase?.FilePath}.ass";
// 记录本次下载的文件
if (!downloading.Downloading.DownloadFiles.ContainsKey("danmaku"))
@@ -243,8 +244,8 @@ public abstract class DownloadService
return assFile;
}
-
-
+
+
protected List BaseDownloadSubtitle(DownloadingItem downloading)
{
// 更新状态显示
@@ -286,7 +287,7 @@ public abstract class DownloadService
if (srtFiles.Count > 0)
{
var srtFile = $"{downloading.DownloadBase.FilePath}.srt";
- File.Copy(srtFiles[0], srtFile,true);
+ File.Copy(srtFiles[0], srtFile, true);
srtFiles.Add(srtFile);
}
@@ -334,17 +335,17 @@ public abstract class DownloadService
return finalFile;
}
-
-
- private string ConcatVideos(DownloadingItem downloading,List videoUids)
+
+
+ private string ConcatVideos(DownloadingItem downloading, List videoUids)
{
downloading.DownloadStatusTitle = DictionaryResource.GetString("ConcatVideos");
downloading.DownloadContent = DictionaryResource.GetString("DownloadingVideo");
downloading.DownloadingFileSize = string.Empty;
downloading.SpeedDisplay = string.Empty;
-
+
var finalFile = $"{downloading.DownloadBase.FilePath}.mp4";
- FFMpeg.Instance.ConcatVideos(videoUids,finalFile,(x)=>{});
+ FFMpeg.Instance.ConcatVideos(videoUids, finalFile, (x) => { });
if (File.Exists(finalFile))
{
var info = new FileInfo(finalFile);
@@ -354,6 +355,7 @@ public abstract class DownloadService
{
downloading.FileSize = Format.FormatFileSize(0);
}
+
return finalFile;
}
@@ -421,8 +423,8 @@ public abstract class DownloadService
try
{
- downloadingTasks.RemoveAll((m) => m.IsCompleted);
- foreach (var downloading in downloadingList)
+ DownloadingTasks.RemoveAll((m) => m.IsCompleted);
+ foreach (var downloading in DownloadingList)
{
if (downloading.Downloading.DownloadStatus == DownloadStatus.Downloading)
{
@@ -430,7 +432,7 @@ public abstract class DownloadService
}
}
- foreach (var downloading in downloadingList)
+ foreach (var downloading in DownloadingList)
{
if (downloadingCount >= maxDownloading)
{
@@ -441,7 +443,7 @@ public abstract class DownloadService
if (downloading.Downloading.DownloadStatus is not (DownloadStatus.NotStarted or DownloadStatus.WaitForDownload)) continue;
//这里需要立刻设置状态,否则如果SingleDownload没有及时执行,会重复创建任务
downloading.Downloading.DownloadStatus = DownloadStatus.Downloading;
- downloadingTasks.Add(SingleDownload(downloading));
+ DownloadingTasks.Add(SingleDownload(downloading));
downloadingCount++;
}
}
@@ -457,7 +459,7 @@ public abstract class DownloadService
}
// 判断是否该结束线程,若为true,跳出while循环
- if (cancellationToken.IsCancellationRequested)
+ if (CancellationToken?.IsCancellationRequested == true)
{
Console.PrintLine($"{Tag}.DoWork() 下载服务结束,跳出while循环");
LogManager.Debug($"{Tag}.DoWork()", "下载服务结束");
@@ -465,19 +467,19 @@ public abstract class DownloadService
}
// 判断下载列表中的视频是否全部下载完成
- if (lastDownloadingCount > 0 && downloadingList.Count == 0 && downloadedList.Count > 0)
+ if (lastDownloadingCount > 0 && DownloadingList.Count == 0 && DownloadedList.Count > 0)
{
AfterDownload();
}
- lastDownloadingCount = downloadingList.Count;
+ lastDownloadingCount = DownloadingList.Count;
// 降低CPU占用
await Task.Delay(500);
}
- await Task.WhenAny(Task.WhenAll(downloadingTasks), Task.Delay(30000));
- foreach (var tsk in downloadingTasks.FindAll((m) => !m.IsCompleted))
+ await Task.WhenAny(Task.WhenAll(DownloadingTasks), Task.Delay(30000));
+ foreach (var tsk in DownloadingTasks.FindAll((m) => !m.IsCompleted))
{
Console.PrintLine($"{Tag}.DoWork() 任务结束超时");
LogManager.Debug($"{Tag}.DoWork()", "任务结束超时");
@@ -510,7 +512,7 @@ public abstract class DownloadService
LogManager.Debug(Tag, e.Message);
var alertService = new AlertService(DialogService);
- var result = await alertService.ShowError($"{path}{DictionaryResource.GetString("DirectoryError")}");
+ await alertService.ShowError($"{path}{DictionaryResource.GetString("DirectoryError")}");
return;
}
@@ -541,17 +543,17 @@ public abstract class DownloadService
// 如果需要下载音频
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"])
{
- for (var i = 0; i < retry; i++)
+ for (var i = 0; i < Retry; i++)
{
audioUid = DownloadAudio(downloading);
- if (audioUid != null && audioUid != nullMark)
+ if (audioUid != null && audioUid != NullMark)
{
break;
}
}
}
- if (audioUid == nullMark)
+ if (audioUid == NullMark)
{
DownloadFailed(downloading);
return;
@@ -559,22 +561,22 @@ public abstract class DownloadService
Pause(downloading);
-
+
// 如果需要下载视频
if (downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
{
//videoUid = DownloadVideo(downloading);
- for (var i = 0; i < retry; i++)
+ for (var i = 0; i < Retry; i++)
{
videoUid = DownloadVideo(downloading);
- if (videoUid != null && videoUid != nullMark)
+ if (videoUid != null && videoUid != NullMark)
{
break;
}
}
}
- if (videoUid == nullMark)
+ if (videoUid == NullMark)
{
DownloadFailed(downloading);
return;
@@ -601,29 +603,29 @@ public abstract class DownloadService
isMediaSuccess = File.Exists(outputMedia);
}
}
- else if(downloading.PlayUrl.Durl != null)
+ else if (downloading.PlayUrl.Durl != null)
{
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] ||
- downloading.DownloadBase.NeedDownloadContent["downloadVideo"] )
+ downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
{
var durls = downloading.PlayUrl.Durl.ToList();
var downloadStatus = durls
- .Select((durl, index) => new { Durl = durl, Index = index })
- .ToDictionary(x => x.Index, x => new { Durl = x.Durl, Result = string.Empty });
+ .Select((durl, index) => new { Durl = durl, Index = index })
+ .ToDictionary(x => x.Index, x => new { Durl = x.Durl, Result = string.Empty });
for (int i = 0; i < durls.Count; i++)
{
downloading.PlayUrl.Durl = new List { durls[i] };
var result = DownloadVideo(downloading);
- downloadStatus[i] = new { Durl = durls[i], Result = result ?? nullMark };
+ downloadStatus[i] = new { Durl = durls[i], Result = result ?? NullMark };
}
-
+
int retryCount = 0;
- while (retryCount < retry && downloadStatus.Values
- .Any(x => x.Result == nullMark))
+ while (retryCount < Retry && downloadStatus.Values
+ .Any(x => x.Result == NullMark))
{
var toRetry = downloadStatus
- .Where(x => retryCount == 0 || x.Value.Result == nullMark)
+ .Where(x => retryCount == 0 || x.Value.Result == NullMark)
.ToList();
foreach (var item in toRetry)
@@ -632,11 +634,12 @@ public abstract class DownloadService
var result = DownloadVideo(downloading);
downloadStatus[item.Key] = new { item.Value.Durl, Result = result };
}
+
retryCount++;
await Task.Delay(1000);
}
-
- if(downloadStatus.Values.Any(x => x.Result == nullMark))
+
+ if (downloadStatus.Values.Any(x => x.Result == NullMark))
{
DownloadFailed(downloading);
return;
@@ -646,26 +649,27 @@ public abstract class DownloadService
if (durls.Count > 1)
{
- var output = ConcatVideos(downloading,downloadStatus.Values
+ var output = ConcatVideos(downloading, downloadStatus.Values
.Select(x => x.Result).ToList());
isMediaSuccess = File.Exists(output);
}
else
{
- var outputMedia = MixedFlow(downloading, null, downloadStatus.First().Value.Result);
- isMediaSuccess = File.Exists(outputMedia);
+ var outputMedia = MixedFlow(downloading, null, downloadStatus.First().Value.Result);
+ isMediaSuccess = File.Exists(outputMedia);
}
}
- if(downloading.DownloadBase.NeedDownloadContent["downloadAudio"] &&
- !downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
+ if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] &&
+ !downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
{
//音频分离?
}
Pause(downloading);
}
+
string? outputDanmaku = null;
// 如果需要下载弹幕
if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"])
@@ -777,11 +781,12 @@ public abstract class DownloadService
Downloaded = downloaded
};
+ DownloadStorageService.AddDownloaded(downloadedItem);
App.PropertyChangeAsync(() =>
{
// 加入到下载完成list中,并从下载中list去除
- downloadedList.Add(downloadedItem);
- downloadingList.Remove(downloading);
+ DownloadedList.Add(downloadedItem);
+ DownloadingList.Remove(downloading);
// 下载完成列表排序
var finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort();
@@ -868,25 +873,22 @@ public abstract class DownloadService
protected async Task BaseEndTask()
{
// 结束任务
- tokenSource.Cancel();
+ TokenSource?.Cancel();
- await workTask;
+ if (WorkTask != null) await WorkTask;
//先简单等待一下
// 下载数据存储服务
- var downloadStorageService = new DownloadStorageService();
+ var downloadStorageService = (DownloadStorageService)App.Current.Container.Resolve(typeof(DownloadStorageService));
// 保存数据
- foreach (var item in downloadingList)
+ foreach (var item in DownloadingList)
{
switch (item.Downloading.DownloadStatus)
{
case DownloadStatus.NotStarted:
- break;
case DownloadStatus.WaitForDownload:
- break;
case DownloadStatus.PauseStarted:
- break;
case DownloadStatus.Pause:
break;
case DownloadStatus.Downloading:
@@ -896,7 +898,6 @@ public abstract class DownloadService
break;
case DownloadStatus.DownloadSucceed:
case DownloadStatus.DownloadFailed:
- break;
default:
break;
}
@@ -905,11 +906,6 @@ public abstract class DownloadService
downloadStorageService.UpdateDownloading(item);
}
-
- foreach (var item in downloadedList)
- {
- downloadStorageService.UpdateDownloaded(item);
- }
}
///
@@ -917,14 +913,14 @@ public abstract class DownloadService
///
protected void BaseStart()
{
- tokenSource = new CancellationTokenSource();
- cancellationToken = tokenSource.Token;
+ TokenSource = new CancellationTokenSource();
+ CancellationToken = TokenSource.Token;
// _notifyIcon = new TaskbarIcon();
// _notifyIcon.IconSource = new BitmapImage(new Uri("pack://application:,,,/Resources/favicon.ico"));
- workTask = Task.Run(DoWork);
+ WorkTask = Task.Run(DoWork);
}
-
+
#region 抽象接口函数
public abstract void Parse(DownloadingItem downloading);
diff --git a/DownKyi/Services/Download/DownloadStorageService.cs b/DownKyi/Services/Download/DownloadStorageService.cs
index 9c8c5dd..130c0cd 100644
--- a/DownKyi/Services/Download/DownloadStorageService.cs
+++ b/DownKyi/Services/Download/DownloadStorageService.cs
@@ -2,13 +2,21 @@
using System.Linq;
using DownKyi.Models;
using DownKyi.ViewModels.DownloadManager;
-using SqlSugar;
+using FreeSql;
namespace DownKyi.Services.Download;
public class DownloadStorageService
{
- private readonly ISqlSugarClient _sqlSugarClient = (ISqlSugarClient)App.Current.Container.Resolve(typeof(ISqlSugarClient));
+ private readonly IBaseRepository _downloadingRepository;
+ private readonly IBaseRepository _downloadedRepository;
+
+
+ public DownloadStorageService(IBaseRepository downloadingRepository, IBaseRepository downloadedRepository)
+ {
+ _downloadingRepository = downloadingRepository;
+ _downloadedRepository = downloadedRepository;
+ }
#region 下载中数据
@@ -27,7 +35,7 @@ public class DownloadStorageService
downloading.Id = downloadingItem.DownloadBase.Id;
downloading.DownloadBase = downloadingItem.DownloadBase;
- _sqlSugarClient.UpdateNav(downloading, new UpdateNavRootOptions { IsInsertRoot = true }).IncludesAllFirstLayer().ExecuteCommand();
+ _downloadingRepository.InsertOrUpdate(downloading);
}
///
@@ -41,7 +49,7 @@ public class DownloadStorageService
return;
}
- _sqlSugarClient.Deleteable(it => it.Id == downloadingItem.Downloading.Id).ExecuteCommand();
+ _downloadingRepository.Delete(it => it.Id == downloadingItem.Downloading.Id);
}
///
@@ -50,7 +58,7 @@ public class DownloadStorageService
///
public List GetDownloading()
{
- var downloadingList = _sqlSugarClient.Queryable().IncludesAllFirstLayer().ToList();
+ var downloadingList = _downloadingRepository.Select.ToList();
return downloadingList.Select(downloading => new DownloadingItem { Downloading = downloading, DownloadBase = downloading.DownloadBase }).ToList();
}
@@ -69,7 +77,7 @@ public class DownloadStorageService
var downloading = downloadingItem.Downloading;
downloading.DownloadBase = downloadingItem.DownloadBase;
- _sqlSugarClient.UpdateNav(downloading).IncludesAllFirstLayer().ExecuteCommand();
+ _downloadingRepository.Update(downloading);
}
#endregion
@@ -89,9 +97,11 @@ public class DownloadStorageService
var downloaded = downloadedItem.Downloaded;
downloaded.Id = downloadedItem.DownloadBase.Id;
- _sqlSugarClient.AsTenant().BeginTran();
- _sqlSugarClient.Storageable(downloaded).TranLock().ExecuteCommand();
- _sqlSugarClient.AsTenant().CommitTran();
+ var exists = _downloadedRepository.Select.Any(download => download.Id == downloaded.Id);
+ if (!exists)
+ {
+ _downloadedRepository.Insert(downloaded);
+ }
}
///
@@ -105,7 +115,7 @@ public class DownloadStorageService
return;
}
- _sqlSugarClient.DeleteNav(it => it.Id == downloadedItem.Downloaded.Id).Include(o1 => o1.DownloadBase).ExecuteCommand();
+ _downloadedRepository.Delete(it => it.Id == downloadedItem.Downloaded.Id);
}
///
@@ -114,7 +124,7 @@ public class DownloadStorageService
///
public List GetDownloaded()
{
- var downloadedList = _sqlSugarClient.Queryable().IncludesAllFirstLayer().ToList();
+ var downloadedList = _downloadedRepository.Select.LeftJoin(downloaded => downloaded.DownloadBase.Id == downloaded.Id).ToList();
return downloadedList.Select(downloaded => new DownloadedItem { Downloaded = downloaded, DownloadBase = downloaded.DownloadBase }).ToList();
}
@@ -132,7 +142,12 @@ public class DownloadStorageService
var downloaded = downloadedItem.Downloaded;
downloaded.DownloadBase = downloadedItem.DownloadBase;
- _sqlSugarClient.UpdateNav(downloaded).IncludesAllFirstLayer().ExecuteCommand();
+ _downloadedRepository.Update(downloaded);
+ }
+
+ public void ClearDownloaded()
+ {
+ _downloadedRepository.DeleteCascadeByDatabase(item => true);
}
#endregion
diff --git a/DownKyi/Utils/DataAnnotations/JsonMapAttribute.cs b/DownKyi/Utils/DataAnnotations/JsonMapAttribute.cs
new file mode 100644
index 0000000..3c1c246
--- /dev/null
+++ b/DownKyi/Utils/DataAnnotations/JsonMapAttribute.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace DownKyi.Utils.DataAnnotations;
+
+///
+/// When the entity class property is , map storage in JSON format.
+/// 当实体类属性为【对象】时,以 JSON 形式映射存储
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class JsonMapAttribute : Attribute { }
\ No newline at end of file
diff --git a/DownKyi/Utils/JsonMapCore.cs b/DownKyi/Utils/JsonMapCore.cs
new file mode 100644
index 0000000..78ba665
--- /dev/null
+++ b/DownKyi/Utils/JsonMapCore.cs
@@ -0,0 +1,274 @@
+using System.Text.Json;
+using DownKyi.Utils.DataAnnotations;
+using FreeSql;
+using FreeSql.DataAnnotations;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Threading;
+
+namespace DownKyi.Utils;
+
+public static class SystemTextJsonHelper
+{
+ private static readonly MethodInfo _deserializeMethodInfo =
+ typeof(JsonSerializer).GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .First(m => m.Name == "Deserialize"
+ && m.IsGenericMethod
+ && m.GetParameters().Length == 2
+ && m.GetParameters()[0].ParameterType == typeof(string));
+
+ public static object? Deserialize(string json, Type type, JsonSerializerOptions options)
+ {
+ // 创建泛型方法
+ var genericMethod = _deserializeMethodInfo.MakeGenericMethod(type);
+ return genericMethod.Invoke(null, new object[] { json, options });
+ }
+
+ public static string Serialize(object value, JsonSerializerOptions options)
+ {
+ return JsonSerializer.Serialize(value, options);
+ }
+}
+
+public static class FreeSqlJsonMapCoreExtensions
+{
+ private static int _isAoped = 0;
+ private static readonly ConcurrentDictionary DicTypes = new();
+
+ private static readonly MethodInfo? MethodJsonConvertDeserializeObject =
+ typeof(SystemTextJsonHelper).GetMethod("Deserialize", new[] { typeof(string), typeof(Type), typeof(JsonSerializerOptions) });
+
+ private static readonly MethodInfo? MethodJsonConvertSerializeObject =
+ typeof(SystemTextJsonHelper).GetMethod("Serialize", new[] { typeof(object), typeof(JsonSerializerOptions) });
+
+ private static readonly ConcurrentDictionary> DicJsonMapFluentApi = new();
+
+ private static readonly object ConcurrentObj = new object();
+
+ public static ColumnFluent JsonMap(this ColumnFluent col)
+ {
+ DicJsonMapFluentApi.GetOrAdd(col._entityType, et => new ConcurrentDictionary())
+ .GetOrAdd(col._property.Name, pn => true);
+ return col;
+ }
+
+ ///
+ /// When the entity class property is and the attribute is marked as , map storage in JSON format.
+ /// 当实体类属性为【对象】时,并且标记特性 [JsonMap] 时,该属性将以JSON形式映射存储
+ ///
+ ///
+ public static void UseJsonMap(this IFreeSql fsql)
+ {
+ UseJsonMap(fsql, JsonSerializerOptions.Default);
+ }
+
+ public static void UseJsonMap(this IFreeSql fsql, JsonSerializerOptions options)
+ {
+ if (Interlocked.CompareExchange(ref _isAoped, 1, 0) == 0)
+ {
+ FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) =>
+ {
+ if (DicTypes.ContainsKey(type))
+ return Expression.IfThenElse(
+ Expression.TypeIs(valueExp, type),
+ Expression.Return(returnTarget, valueExp),
+ Expression.Return(returnTarget,
+ Expression.TypeAs(
+ Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(valueExp, typeof(string)), Expression.Constant(type),
+ Expression.Constant(options)), type))
+ );
+ return null;
+ });
+ }
+
+ fsql.Aop.ConfigEntityProperty += (s, e) =>
+ {
+ var isJsonMap = e.Property.GetCustomAttributes(typeof(JsonMapAttribute), false).Any() ||
+ DicJsonMapFluentApi.TryGetValue(e.EntityType, out var tryjmfu) && tryjmfu.ContainsKey(e.Property.Name);
+ if (isJsonMap)
+ {
+ if (DicTypes.ContainsKey(e.Property.PropertyType) == false &&
+ FreeSql.Internal.Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(e.Property.PropertyType))
+ return; //基础类型使用 JsonMap 无效
+
+ if (e.ModifyResult.MapType == null)
+ {
+ e.ModifyResult.MapType = typeof(string);
+ e.ModifyResult.StringLength = -2;
+ }
+
+ if (DicTypes.TryAdd(e.Property.PropertyType, true))
+ {
+ lock (ConcurrentObj)
+ {
+ FreeSql.Internal.Utils.dicExecuteArrayRowReadClassOrTuple[e.Property.PropertyType] = true;
+ FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionObjectToStringIfThenElse.Add((LabelTarget returnTarget, Expression valueExp, Expression elseExp,
+ Type type) =>
+ {
+ return Expression.IfThenElse(
+ Expression.TypeIs(valueExp, e.Property.PropertyType),
+ Expression.Return(returnTarget,
+ Expression.Call(MethodJsonConvertSerializeObject, Expression.Convert(valueExp, typeof(object)), Expression.Constant(options)), typeof(object)),
+ elseExp);
+ });
+ }
+ }
+ }
+ };
+ switch (fsql.Ado.DataType)
+ {
+ case DataType.Sqlite:
+ case DataType.MySql:
+ case DataType.OdbcMySql:
+ case DataType.CustomMySql:
+ case DataType.SqlServer:
+ case DataType.OdbcSqlServer:
+ case DataType.CustomSqlServer:
+ case DataType.Oracle:
+ case DataType.OdbcOracle:
+ case DataType.CustomOracle:
+ case DataType.Dameng:
+ case DataType.DuckDB:
+ fsql.Aop.ParseExpression += (_, e) =>
+ {
+ //if (e.Expression is MethodCallExpression callExp)
+ //{
+ // var objExp = callExp.Object;
+ // var objType = objExp?.Type;
+ // if (objType?.FullName == "System.Byte[]") return;
+
+ // if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
+ // {
+ // objExp = callExp.Arguments.FirstOrDefault();
+ // objType = objExp?.Type;
+ // }
+ // if (objType == null) objType = callExp.Method.DeclaringType;
+ // if (objType != null || objType.IsArrayOrList())
+ // {
+ // string left = null;
+ // switch (callExp.Method.Name)
+ // {
+ // case "Any":
+ // left = objExp == null ? null : getExp(objExp);
+ // if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
+ // return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
+ // case "Contains":
+ // }
+ // }
+ //}
+ //解析 POCO Json a.Customer.Name
+ if (e.Expression is MemberExpression memExp)
+ {
+ if (e.Expression.IsParameter() == false) return;
+ var parentMemExps = new Stack();
+ parentMemExps.Push(memExp);
+ while (true)
+ {
+ switch (memExp.Expression?.NodeType)
+ {
+ case ExpressionType.MemberAccess:
+ case ExpressionType.Parameter: break;
+ default: return;
+ }
+
+ switch (memExp.Expression.NodeType)
+ {
+ case ExpressionType.MemberAccess:
+ memExp = memExp.Expression as MemberExpression;
+ if (memExp == null) return;
+ parentMemExps.Push(memExp);
+ break;
+ case ExpressionType.Parameter:
+ var tb = fsql.CodeFirst.GetTableByEntity(memExp.Expression.Type);
+ if (tb == null) return;
+ if (tb.ColumnsByCs.TryGetValue(parentMemExps.Pop().Member.Name, out var trycol) == false) return;
+ if (DicTypes.ContainsKey(trycol.CsType) == false) return;
+ var result = e.FreeParse(Expression.MakeMemberAccess(memExp.Expression, tb.Properties[trycol.CsName]));
+ if (parentMemExps.Any() == false)
+ {
+ e.Result = result;
+ return;
+ }
+
+ var jsonPath = "";
+ switch (fsql.Ado.DataType)
+ {
+ case DataType.Sqlite:
+ case DataType.MySql:
+ case DataType.OdbcMySql:
+ case DataType.CustomMySql:
+ StyleJsonExtract();
+ return;
+ case DataType.SqlServer:
+ case DataType.OdbcSqlServer:
+ case DataType.CustomSqlServer:
+ case DataType.Oracle:
+ case DataType.OdbcOracle:
+ case DataType.CustomOracle:
+ case DataType.Dameng:
+ StyleJsonValue();
+ return;
+ case DataType.DuckDB:
+ StyleDotAccess();
+ return;
+ }
+
+ StylePgJson();
+ return;
+
+ void StyleJsonExtract()
+ {
+ while (parentMemExps.Any())
+ {
+ memExp = parentMemExps.Pop();
+ jsonPath = $"{jsonPath}.{memExp.Member.Name}";
+ }
+
+ e.Result = $"json_extract({result},'${jsonPath}')";
+ }
+
+ void StyleJsonValue()
+ {
+ while (parentMemExps.Any())
+ {
+ memExp = parentMemExps.Pop();
+ jsonPath = $"{jsonPath}.{memExp.Member.Name}";
+ }
+
+ e.Result = $"json_value({result},'${jsonPath}')";
+ }
+
+ void StyleDotAccess()
+ {
+ while (parentMemExps.Any())
+ {
+ memExp = parentMemExps.Pop();
+ result = $"{result}['{memExp.Member.Name}']";
+ }
+
+ e.Result = result;
+ }
+
+ void StylePgJson()
+ {
+ while (parentMemExps.Any())
+ {
+ memExp = parentMemExps.Pop();
+ var opt = parentMemExps.Any() ? "->" : $"->>{(memExp.Type.IsArrayOrList() ? "/*json array*/" : "")}";
+ result = $"{result}{opt}'{memExp.Member.Name}'";
+ }
+
+ e.Result = result;
+ }
+ }
+ }
+ }
+ };
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DownKyi/ViewModels/Dialogs/NewVersionAvailableDialogViewModel.cs b/DownKyi/ViewModels/Dialogs/NewVersionAvailableDialogViewModel.cs
index 6c06d89..47d7879 100644
--- a/DownKyi/ViewModels/Dialogs/NewVersionAvailableDialogViewModel.cs
+++ b/DownKyi/ViewModels/Dialogs/NewVersionAvailableDialogViewModel.cs
@@ -3,7 +3,6 @@ using Avalonia.Controls.Documents;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Services.Dialogs;
-using SqlSugar;
using System.Linq;
using DownKyi.Core.Settings;
using DownKyi.Models;
diff --git a/DownKyi/ViewModels/Dialogs/ViewUpgradingDialogViewModel.cs b/DownKyi/ViewModels/Dialogs/ViewUpgradingDialogViewModel.cs
index 3be559a..42a0040 100644
--- a/DownKyi/ViewModels/Dialogs/ViewUpgradingDialogViewModel.cs
+++ b/DownKyi/ViewModels/Dialogs/ViewUpgradingDialogViewModel.cs
@@ -12,17 +12,16 @@ using DownKyi.Core.BiliApi.Login;
using DownKyi.Core.Storage;
using DownKyi.Core.Storage.Database;
using DownKyi.Models;
+using FreeSql;
using Prism.Commands;
using Prism.Services.Dialogs;
-using SqlSugar;
-using Exception = System.Exception;
namespace DownKyi.ViewModels.Dialogs;
public class ViewUpgradingDialogViewModel : BaseDialogViewModel
{
public const string Tag = "DialogLoading";
- private readonly ISqlSugarClient _sqlSugarClient;
+ private readonly IBaseRepository _downloadedRepository;
#region 页面属性申明
@@ -70,9 +69,9 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
#endregion
- public ViewUpgradingDialogViewModel(ISqlSugarClient sqlSugarClient)
+ public ViewUpgradingDialogViewModel(IBaseRepository downloadedRepository)
{
- _sqlSugarClient = sqlSugarClient;
+ _downloadedRepository = downloadedRepository;
Message = "数据迁移中、请不要关闭软件";
}
@@ -90,7 +89,6 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
{
Task.Run(() => { Upgrade1_0_20To1_0_21(); });
}
-
private void Upgrade1_0_20To1_0_21()
{
@@ -137,18 +135,25 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
{
noMigrate = true;
}
-
+
+#if DEBUG
+ var oldDbPath = StorageManager.GetDownload().Replace(".db", "_debug.db");
+#else
var oldDbPath = StorageManager.GetDownload();
+#endif
if (File.Exists(oldDbPath))
{
SetMessage("正在迁移下载信息");
-
+#if DEBUG
+ var dbHelper = new SqliteDatabase(oldDbPath);
+#else
var dbHelper = new SqliteDatabase(oldDbPath, "bdb8eb69-3698-4af9-b722-9312d0fba623");
+#endif
var validRecords = new Dictionary();
var totalCount = 0;
dbHelper.ExecuteQuery(@"SELECT d.id, d.data as downloaded_data, db.data as download_base_data
FROM downloaded d
- JOIN download_base db ON d.id = db.id",reader =>
+ JOIN download_base db ON d.id = db.id", reader =>
{
while (reader.Read())
{
@@ -161,23 +166,24 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
// 反序列化
var record = NrbfDecoder.DecodeClassRecord(stream);
if (!record.TypeNameMatches(typeof(Downloaded))) continue;
-
+
var downloadedObj = new Downloaded
{
+ Id = reader["id"].ToString() ?? Guid.NewGuid().ToString("N"),
MaxSpeedDisplay = record.GetString($"<{nameof(Downloaded.MaxSpeedDisplay)}>k__BackingField"),
FinishedTime = record.GetString($"<{nameof(Downloaded.FinishedTime)}>k__BackingField") ?? "",
FinishedTimestamp = record.GetInt64($"<{nameof(Downloaded.FinishedTimestamp)}>k__BackingField")
};
-
-
+
+
validRecords.Add(
- (string)reader["id"],
- new DownloadedWithData
- {
+ (string)reader["id"],
+ new DownloadedWithData
+ {
Downloaded = downloadedObj,
DownloadBaseData = (byte[])reader["download_base_data"]
});
-
+
totalCount++;
}
catch (Exception e)
@@ -212,15 +218,13 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
return quality;
});
- var i = 0;
-
+
try
{
- int batchSize = 200;
+ const int batchSize = 200;
var downloadedList = new List();
- int processedCount = 0;
+ var processedCount = 0;
- _sqlSugarClient.Ado.BeginTran();
foreach (var item in validRecords)
{
try
@@ -229,17 +233,16 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
var record = NrbfDecoder.DecodeClassRecord(stream);
if (record.TypeNameMatches(typeof(DownloadBase)))
{
- var needDownloadContentRecord =
- record.GetClassRecord($"<{nameof(DownloadBase.NeedDownloadContent)}>k__BackingField");
- var needDownloadContent = needDownloadContentRecord != null
- ? readNeedDownloadContent(needDownloadContentRecord)
- : new Dictionary();
+ var needDownloadContentRecord = record.GetClassRecord($"<{nameof(DownloadBase.NeedDownloadContent)}>k__BackingField");
+ var needDownloadContent = needDownloadContentRecord != null ? readNeedDownloadContent(needDownloadContentRecord) : new Dictionary();
var download = new Downloaded
{
+ Id = item.Value.Downloaded.Id,
MaxSpeedDisplay = item.Value.Downloaded.MaxSpeedDisplay,
FinishedTime = item.Value.Downloaded.FinishedTime,
FinishedTimestamp = item.Value.Downloaded.FinishedTimestamp,
+
DownloadBase = new DownloadBase
{
NeedDownloadContent = needDownloadContent,
@@ -247,77 +250,56 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
Avid = record.GetInt64($"<{nameof(DownloadBase.Avid)}>k__BackingField"),
Cid = record.GetInt64($"<{nameof(DownloadBase.Cid)}>k__BackingField"),
EpisodeId = record.GetInt64($"<{nameof(DownloadBase.EpisodeId)}>k__BackingField"),
- CoverUrl = record.GetString($"<{nameof(DownloadBase.CoverUrl)}>k__BackingField") ??
- "",
- PageCoverUrl =
- record.GetString($"<{nameof(DownloadBase.PageCoverUrl)}>k__BackingField") ?? "",
+ CoverUrl = record.GetString($"<{nameof(DownloadBase.CoverUrl)}>k__BackingField") ?? "",
+ PageCoverUrl = record.GetString($"<{nameof(DownloadBase.PageCoverUrl)}>k__BackingField") ?? "",
ZoneId = record.GetInt32($"<{nameof(DownloadBase.ZoneId)}>k__BackingField"),
Order = record.GetInt32($"<{nameof(DownloadBase.Order)}>k__BackingField"),
- MainTitle =
- record.GetString($"<{nameof(DownloadBase.MainTitle)}>k__BackingField") ?? "",
+ MainTitle = record.GetString($"<{nameof(DownloadBase.MainTitle)}>k__BackingField") ?? "",
Name = record.GetString($"<{nameof(DownloadBase.Name)}>k__BackingField") ?? "",
- Duration = record.GetString($"<{nameof(DownloadBase.Duration)}>k__BackingField") ??
- "",
- VideoCodecName =
- record.GetString($"<{nameof(DownloadBase.VideoCodecName)}>k__BackingField") ??
- "",
- Resolution =
- readQuality(
- record.GetClassRecord(
- $"<{nameof(DownloadBase.Resolution)}>k__BackingField")),
- AudioCodec =
- readQuality(
- record.GetClassRecord(
- $"<{nameof(DownloadBase.AudioCodec)}>k__BackingField")),
- FilePath = record.GetString($"<{nameof(DownloadBase.FilePath)}>k__BackingField") ??
- "",
- FileSize = record.GetString($"<{nameof(DownloadBase.FileSize)}>k__BackingField") ??
- "",
+ Duration = record.GetString($"<{nameof(DownloadBase.Duration)}>k__BackingField") ?? "",
+ VideoCodecName = record.GetString($"<{nameof(DownloadBase.VideoCodecName)}>k__BackingField") ?? "",
+ Resolution = readQuality(record.GetClassRecord($"<{nameof(DownloadBase.Resolution)}>k__BackingField")),
+ AudioCodec = readQuality(record.GetClassRecord($"<{nameof(DownloadBase.AudioCodec)}>k__BackingField")),
+ FilePath = record.GetString($"<{nameof(DownloadBase.FilePath)}>k__BackingField") ?? "",
+ FileSize = record.GetString($"<{nameof(DownloadBase.FileSize)}>k__BackingField") ?? "",
Page = record.GetInt32($"<{nameof(DownloadBase.Page)}>k__BackingField")
}
};
downloadedList.Add(download);
processedCount++;
- if (processedCount % batchSize == 0 || processedCount == totalCount)
+ if (processedCount % batchSize != 0 && processedCount != totalCount) continue;
+ _downloadedRepository.Insert(downloadedList);
+ downloadedList.Clear();
+
+ // 更新进度
+ var percent = processedCount / (double)totalCount * 100;
+ Dispatcher.UIThread.Invoke(() =>
{
- _sqlSugarClient.InsertNav(downloadedList)
- .Include(o1 => o1.DownloadBase)
- .ExecuteCommand();
-
-
- downloadedList.Clear();
-
- // 更新进度
- var percent = processedCount / (double)totalCount * 100;
- Dispatcher.UIThread.Invoke(() =>
- {
- Percent = percent;
- SetMessage($"正在迁移下载信息({processedCount}/{totalCount})");
- });
- }
+ Percent = percent;
+ SetMessage($"正在迁移下载信息({processedCount}/{totalCount})");
+ });
}
}
catch (Exception ex)
{
- /*忽略*/
+ Console.WriteLine(ex.ToString());
}
}
- _sqlSugarClient.Ado.CommitTran();
+
dbHelper.Dispose();
File.Delete(oldDbPath);
-
+
Dispatcher.UIThread.Invoke(() =>
{
RestartVisible = true;
SetMessage("下载信息迁移完成");
+ App.Current.RefreshDownloadedList();
});
}
catch (Exception e)
{
- _sqlSugarClient.Ado.RollbackTran();
SetMessage($"迁移失败: {e.Message}");
}
-
}
else
{
@@ -329,11 +311,10 @@ public class ViewUpgradingDialogViewModel : BaseDialogViewModel
Dispatcher.UIThread.Invoke(() => RaiseRequestClose(new DialogResult()));
}
}
-
+
private class DownloadedWithData
{
- public Downloaded Downloaded { get; set; }
- public byte[] DownloadBaseData { get; set; }
+ public Downloaded Downloaded { get; set; } = new();
+ public byte[] DownloadBaseData { get; set; } = Array.Empty();
}
-
}
\ No newline at end of file
diff --git a/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs
index 5be5d12..d471c22 100644
--- a/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs
+++ b/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs
@@ -2,7 +2,6 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.Zone;
using DownKyi.Models;
-using DownKyi.PrismExtension.Dialog;
using DownKyi.Utils;
using Prism.Mvvm;
@@ -10,18 +9,6 @@ namespace DownKyi.ViewModels.DownloadManager
{
public class DownloadBaseItem : BindableBase
{
- public IDialogService? DialogService;
-
- public DownloadBaseItem()
- {
- DialogService = null;
- }
-
- public DownloadBaseItem(IDialogService? dialogService)
- {
- DialogService = dialogService;
- }
-
// model数据
private DownloadBase? _downloadBase;
@@ -40,9 +27,9 @@ namespace DownKyi.ViewModels.DownloadManager
}
// 视频分区image
- private DrawingImage _zoneImage;
+ private DrawingImage? _zoneImage;
- public DrawingImage ZoneImage
+ public DrawingImage? ZoneImage
{
get => _zoneImage;
set => SetProperty(ref _zoneImage, value);
diff --git a/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs
index 9747e82..f75ac54 100644
--- a/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs
+++ b/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs
@@ -1,183 +1,76 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using DownKyi.Images;
+using DownKyi.Images;
using DownKyi.Models;
-using DownKyi.Services;
using DownKyi.Utils;
-using Prism.Commands;
-using Prism.Services.Dialogs;
-using IDialogService = DownKyi.PrismExtension.Dialog.IDialogService;
-namespace DownKyi.ViewModels.DownloadManager
+namespace DownKyi.ViewModels.DownloadManager;
+
+public class DownloadedItem : DownloadBaseItem
{
- public class DownloadedItem : DownloadBaseItem
+ public DownloadedItem()
{
- public DownloadedItem() : this(null)
- {
- }
+ // 打开文件夹按钮
+ OpenFolder = ButtonIcon.Instance().Folder;
+ OpenFolder.Fill = DictionaryResource.GetColor("ColorPrimary");
- public DownloadedItem(IDialogService? dialogService) : base(dialogService)
- {
- // 打开文件夹按钮
- OpenFolder = ButtonIcon.Instance().Folder;
- OpenFolder.Fill = DictionaryResource.GetColor("ColorPrimary");
+ // 打开视频按钮
+ OpenVideo = ButtonIcon.Instance().Start;
+ OpenVideo.Fill = DictionaryResource.GetColor("ColorPrimary");
- // 打开视频按钮
- OpenVideo = ButtonIcon.Instance().Start;
- OpenVideo.Fill = DictionaryResource.GetColor("ColorPrimary");
-
- // 删除按钮
- RemoveVideo = ButtonIcon.Instance().Trash;
- RemoveVideo.Fill = DictionaryResource.GetColor("ColorWarning");
- }
-
- // model数据
- public Downloaded Downloaded { get; set; }
-
- // 下载速度
- public string? MaxSpeedDisplay
- {
- get => Downloaded.MaxSpeedDisplay;
- set
- {
- Downloaded.MaxSpeedDisplay = value;
- RaisePropertyChanged();
- }
- }
-
- // 完成时间
- public string FinishedTime
- {
- get => Downloaded.FinishedTime;
- set
- {
- Downloaded.FinishedTime = value;
- RaisePropertyChanged("FinishedTime");
- }
- }
-
- #region 控制按钮
-
- private VectorImage _openFolder;
-
- public VectorImage OpenFolder
- {
- get => _openFolder;
- set => SetProperty(ref _openFolder, value);
- }
-
- private VectorImage _openVideo;
-
- public VectorImage OpenVideo
- {
- get => _openVideo;
- set => SetProperty(ref _openVideo, value);
- }
-
- private VectorImage _removeVideo;
-
- public VectorImage RemoveVideo
- {
- get => _removeVideo;
- set => SetProperty(ref _removeVideo, value);
- }
-
- #endregion
-
- #region 命令申明
-
- // 打开文件夹事件
- private DelegateCommand? _openFolderCommand;
-
- public DelegateCommand OpenFolderCommand => _openFolderCommand ??= new DelegateCommand(ExecuteOpenFolderCommand);
-
-
- private static readonly IReadOnlyDictionary FileSuffixMap = new Dictionary
- {
- { "downloadVideo", new[] { ".mp4", ".flv" } },
- { "downloadAudio", new[] { ".aac", ".mp3" } },
- { "downloadCover", new[] { ".jpg" } },
- { "downloadDanmaku", new[] { ".ass" } },
- { "downloadSubtitle", new[] { ".srt" } }
- };
-
- ///
- /// 打开文件夹事件
- ///
- private void ExecuteOpenFolderCommand()
- {
- if (DownloadBase == null)
- {
- return;
- }
-
- var downLoadContents = DownloadBase.NeedDownloadContent.Where(e => e.Value == true).Select(e => e.Key);
- var fileSuffixes = downLoadContents
- .Where(content => FileSuffixMap.ContainsKey(content))
- .SelectMany(content => FileSuffixMap[content])
- .ToArray();
- if (fileSuffixes.Length <= 0) return;
- foreach (var suffix in fileSuffixes)
- {
- var videoPath = $"{DownloadBase.FilePath}{suffix}";
- var fileInfo = new FileInfo(videoPath);
- if (File.Exists(fileInfo.FullName) && fileInfo.DirectoryName != null)
- {
- PlatformHelper.OpenFolder(fileInfo.DirectoryName);
- return;
- }
- }
- // eventAggregator.GetEvent().Publish("没有找到视频文件,可能被删除或移动!");
- }
-
- // 打开视频事件
- private DelegateCommand? _openVideoCommand;
- public DelegateCommand OpenVideoCommand => _openVideoCommand ??= new DelegateCommand(ExecuteOpenVideoCommand);
-
- ///
- /// 打开视频事件
- ///
- private void ExecuteOpenVideoCommand()
- {
- if (DownloadBase == null)
- {
- return;
- }
-
- var videoPath = $"{DownloadBase.FilePath}.mp4";
- var fileInfo = new FileInfo(videoPath);
- if (File.Exists(fileInfo.FullName))
- {
- PlatformHelper.Open(fileInfo.FullName);
- }
- else
- {
- //eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
- //eventAggregator.GetEvent().Publish("没有找到视频文件,可能被删除或移动!");
- }
- }
-
- // 删除事件
- private DelegateCommand? _removeVideoCommand;
-
- public DelegateCommand RemoveVideoCommand => _removeVideoCommand ??= new DelegateCommand(ExecuteRemoveVideoCommand);
-
- ///
- /// 删除事件
- ///
- private async void ExecuteRemoveVideoCommand()
- {
- var alertService = new AlertService(DialogService);
- var result = await alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete"), 2);
- if (result != ButtonResult.OK)
- {
- return;
- }
-
- App.DownloadedList?.Remove(this);
- }
-
- #endregion
+ // 删除按钮
+ RemoveVideo = ButtonIcon.Instance().Trash;
+ RemoveVideo.Fill = DictionaryResource.GetColor("ColorWarning");
}
+
+ // model数据
+ public Downloaded Downloaded { get; set; }
+
+ // 下载速度
+ public string? MaxSpeedDisplay
+ {
+ get => Downloaded.MaxSpeedDisplay;
+ set
+ {
+ Downloaded.MaxSpeedDisplay = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ // 完成时间
+ public string FinishedTime
+ {
+ get => Downloaded.FinishedTime;
+ set
+ {
+ Downloaded.FinishedTime = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ #region 控制按钮
+
+ private VectorImage _openFolder;
+
+ public VectorImage OpenFolder
+ {
+ get => _openFolder;
+ set => SetProperty(ref _openFolder, value);
+ }
+
+ private VectorImage _openVideo;
+
+ public VectorImage OpenVideo
+ {
+ get => _openVideo;
+ set => SetProperty(ref _openVideo, value);
+ }
+
+ private VectorImage _removeVideo;
+
+ public VectorImage RemoveVideo
+ {
+ get => _removeVideo;
+ set => SetProperty(ref _removeVideo, value);
+ }
+
+ #endregion
}
\ No newline at end of file
diff --git a/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs
index 102bf9a..bae4e64 100644
--- a/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs
+++ b/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs
@@ -1,23 +1,17 @@
using DownKyi.Core.BiliApi.VideoStream.Models;
using DownKyi.Images;
using DownKyi.Models;
-using DownKyi.Services;
using DownKyi.Utils;
using Downloader;
using Prism.Commands;
-using Prism.Services.Dialogs;
using DownloadStatus = DownKyi.Models.DownloadStatus;
-using IDialogService = DownKyi.PrismExtension.Dialog.IDialogService;
namespace DownKyi.ViewModels.DownloadManager
{
public class DownloadingItem : DownloadBaseItem
{
- public DownloadingItem() : this(null)
- {
- }
- public DownloadingItem(IDialogService? dialogService) : base(dialogService)
+ public DownloadingItem()
{
// 暂停继续按钮
StartOrPause = ButtonIcon.Instance().Pause;
@@ -218,25 +212,6 @@ namespace DownKyi.ViewModels.DownloadManager
}
}
- // 下载列表删除事件
- private DelegateCommand? _deleteCommand;
- public DelegateCommand DeleteCommand => _deleteCommand ??= new DelegateCommand(ExecuteDeleteCommand);
-
- ///
- /// 下载列表删除事件
- ///
- private async void ExecuteDeleteCommand()
- {
- var alertService = new AlertService(DialogService);
- var result = await alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete"), 2);
- if (result != ButtonResult.OK)
- {
- return;
- }
-
- App.DownloadingList?.Remove(this);
- }
-
#endregion
}
}
\ No newline at end of file
diff --git a/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs b/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs
index 94a2d18..349a7a0 100644
--- a/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs
+++ b/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs
@@ -1,115 +1,120 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Collections.Specialized;
+using System.IO;
using System.Linq;
-using System.Threading.Tasks;
-using Avalonia.Threading;
-using DownKyi.Core.Logging;
using DownKyi.Core.Settings;
+using DownKyi.Events;
using DownKyi.Services;
+using DownKyi.Services.Download;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
-using Prism.Regions;
using Prism.Services.Dialogs;
-using Console = DownKyi.Core.Utils.Debugging.Console;
using IDialogService = DownKyi.PrismExtension.Dialog.IDialogService;
-namespace DownKyi.ViewModels.DownloadManager
+namespace DownKyi.ViewModels.DownloadManager;
+
+public class ViewDownloadFinishedViewModel : ViewModelBase
{
- public class ViewDownloadFinishedViewModel : ViewModelBase
+ public const string Tag = "PageDownloadManagerDownloadFinished";
+
+ private DownloadStorageService _downloadStorageService;
+
+ #region 页面属性申明
+
+ private ObservableCollection _downloadedList = new();
+
+ public ObservableCollection DownloadedList
{
- public const string Tag = "PageDownloadManagerDownloadFinished";
+ get => _downloadedList;
+ set => SetProperty(ref _downloadedList, value);
+ }
- #region 页面属性申明
+ private int _finishedSortBy;
- private ObservableCollection _downloadedList;
- public ObservableCollection DownloadedList
+ public int FinishedSortBy
+ {
+ get => _finishedSortBy;
+ set => SetProperty(ref _finishedSortBy, value);
+ }
+
+ #endregion
+
+ public ViewDownloadFinishedViewModel(
+ IEventAggregator eventAggregator,
+ IDialogService dialogService,
+ DownloadStorageService downloadStorageService
+ ) : base(eventAggregator,
+ dialogService)
+ {
+ // 初始化DownloadedList
+ DownloadedList = App.DownloadedList;
+ _downloadStorageService = downloadStorageService;
+
+ var finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort();
+ FinishedSortBy = finishedSort switch
{
- get => _downloadedList;
- set => SetProperty(ref _downloadedList, value);
+ DownloadFinishedSort.DownloadAsc => 0,
+ DownloadFinishedSort.DownloadDesc => 1,
+ DownloadFinishedSort.Number => 2,
+ _ => 0
+ };
+ App.SortDownloadedList(finishedSort);
+ }
+
+ #region 命令申明
+
+ // 下载完成列表排序事件
+ private DelegateCommand