diff --git a/DownKyi.Core/BiliApi/BiliUtils/Quality.cs b/DownKyi.Core/BiliApi/BiliUtils/Quality.cs index 6295881..60aa324 100644 --- a/DownKyi.Core/BiliApi/BiliUtils/Quality.cs +++ b/DownKyi.Core/BiliApi/BiliUtils/Quality.cs @@ -1,5 +1,8 @@ -namespace DownKyi.Core.BiliApi.BiliUtils +using System; + +namespace DownKyi.Core.BiliApi.BiliUtils { + [Serializable] public class Quality { public string Name { get; set; } diff --git a/DownKyi.Core/Storage/Database/CoverDb.cs b/DownKyi.Core/Storage/Database/CoverDb.cs index fa53abb..8bca281 100644 --- a/DownKyi.Core/Storage/Database/CoverDb.cs +++ b/DownKyi.Core/Storage/Database/CoverDb.cs @@ -79,7 +79,6 @@ namespace DownKyi.Core.Storage.Database { string sql = $"select * from {tableName} where url glob '{url}'"; List query = Query(sql); - return query.Count > 0 ? query[0] : null; } @@ -91,16 +90,8 @@ namespace DownKyi.Core.Storage.Database public Cover QueryByMd5(string md5) { string sql = $"select * from {tableName} where md5 glob '{md5}'"; - var query = Query(sql); - - if (query.Count > 0) - { - return query[0]; - } - else - { - return null; - } + List query = Query(sql); + return query.Count > 0 ? query[0] : null; } /// diff --git a/DownKyi.Core/Storage/Database/Download/DownloadDb.cs b/DownKyi.Core/Storage/Database/Download/DownloadDb.cs index eff2c98..a467891 100644 --- a/DownKyi.Core/Storage/Database/Download/DownloadDb.cs +++ b/DownKyi.Core/Storage/Database/Download/DownloadDb.cs @@ -57,7 +57,60 @@ namespace DownKyi.Core.Storage.Database.Download catch (Exception e) { Utils.Debugging.Console.PrintLine("Insert()发生异常: {0}", e); - LogManager.Error("DownloadingDb", e); + LogManager.Error($"{tableName}", e); + } + } + + /// + /// 删除uuid对应的数据 + /// + /// + public void Delete(string uuid) + { + try + { + string sql = $"delete from {tableName} where id glob '{uuid}'"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("Delete()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + } + + public void Update(string uuid, object obj) + { + // 定义一个流 + Stream stream = new MemoryStream(); + // 定义一个格式化器 + BinaryFormatter formatter = new BinaryFormatter(); + // 序列化 + formatter.Serialize(stream, obj); + + byte[] array = null; + array = new byte[stream.Length]; + + //将二进制流写入数组 + stream.Position = 0; + stream.Read(array, 0, (int)stream.Length); + + //关闭流 + stream.Close(); + + try + { + string sql = $"update {tableName} set data=@data where id glob @id"; + dbHelper.ExecuteNonQuery(sql, new Action((para) => + { + para.Add("@id", DbType.String).Value = uuid; + para.Add("@data", DbType.Binary).Value = array; + })); + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("Insert()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); } } @@ -72,6 +125,27 @@ namespace DownKyi.Core.Storage.Database.Download return Query(sql); } + /// + /// 查询uuid对应的数据 + /// + /// + /// + public object QueryById(string uuid) + { + string sql = $"select * from {tableName} where id glob '{uuid}'"; + Dictionary query = Query(sql); + + if (query.ContainsKey(uuid)) + { + query.TryGetValue(uuid, out object obj); + return obj; + } + else + { + return null; + } + } + /// /// 查询数据 /// @@ -88,7 +162,7 @@ namespace DownKyi.Core.Storage.Database.Download // 读取字节数组 byte[] array = (byte[])reader["data"]; // 定义一个流 - MemoryStream stream = new MemoryStream(null); + MemoryStream stream = new MemoryStream(array); //定义一个格式化器 BinaryFormatter formatter = new BinaryFormatter(); // 反序列化 diff --git a/DownKyi.Core/Storage/Database/HeaderDb.cs b/DownKyi.Core/Storage/Database/HeaderDb.cs index 6fe2645..d1d11c2 100644 --- a/DownKyi.Core/Storage/Database/HeaderDb.cs +++ b/DownKyi.Core/Storage/Database/HeaderDb.cs @@ -78,11 +78,9 @@ namespace DownKyi.Core.Storage.Database { string sql = $"select * from {tableName} where mid={mid}"; List
query = Query(sql); - return query.Count > 0 ? query[0] : null; } - /// /// 查询数据 /// diff --git a/DownKyi/App.xaml.cs b/DownKyi/App.xaml.cs index ed5b1d0..ace8540 100644 --- a/DownKyi/App.xaml.cs +++ b/DownKyi/App.xaml.cs @@ -15,7 +15,9 @@ using Prism.Ioc; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Linq; +using System.Threading; using System.Windows; namespace DownKyi @@ -25,6 +27,7 @@ namespace DownKyi ///
public partial class App { + public static Dictionary Dictionary = new Dictionary(); public static ObservableCollection DownloadingList { get; set; } public static ObservableCollection DownloadedList { get; set; } @@ -45,7 +48,68 @@ namespace DownKyi DownloadingList = new ObservableCollection(); DownloadedList = new ObservableCollection(); - // TODO 从数据库读取 + // 下载数据存储服务 + DownloadStorageService downloadStorageService = new DownloadStorageService(); + + // 从数据库读取 + List downloadingItems = downloadStorageService.GetDownloading(); + List downloadedItems = downloadStorageService.GetDownloaded(); + DownloadingList.AddRange(downloadingItems); + DownloadedList.AddRange(downloadedItems); + + // 下载列表发生变化时执行的任务 + DownloadingList.CollectionChanged += new NotifyCollectionChangedEventHandler((object sender, NotifyCollectionChangedEventArgs e) => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (object item in e.NewItems) + { + if (item is DownloadingItem downloading) + { + //Console.WriteLine("DownloadingList添加"); + downloadStorageService.AddDownloading(downloading); + } + } + } + if (e.Action == NotifyCollectionChangedAction.Remove) + { + foreach (object item in e.OldItems) + { + if (item is DownloadingItem downloading) + { + //Console.WriteLine("DownloadingList移除"); + downloadStorageService.RemoveDownloading(downloading); + } + } + } + }); + + // 下载完成列表发生变化时执行的任务 + DownloadedList.CollectionChanged += new NotifyCollectionChangedEventHandler((object sender, NotifyCollectionChangedEventArgs e) => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (object item in e.NewItems) + { + if (item is DownloadedItem downloaded) + { + //Console.WriteLine("DownloadedList添加"); + downloadStorageService.AddDownloaded(downloaded); + } + } + } + if (e.Action == NotifyCollectionChangedAction.Remove) + { + foreach (object item in e.OldItems) + { + if (item is DownloadedItem downloaded) + { + //Console.WriteLine("DownloadedList移除"); + downloadStorageService.RemoveDownloaded(downloaded); + } + } + } + }); // 启动下载服务 downloadService = new AriaDownloadService(DownloadingList, DownloadedList); @@ -54,6 +118,23 @@ namespace DownKyi return Container.Resolve(); } + protected override void OnStartup(StartupEventArgs e) + { + Thread thread = new Thread(() => + { + SplashWindow sw = new SplashWindow(); + // 储存 + Dictionary["SplashWindow"] = sw; + // 不能用Show + sw.ShowDialog(); + }); + // 设置单线程 + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + base.OnStartup(e); + } + protected override void OnExit(ExitEventArgs e) { // 关闭下载服务 diff --git a/DownKyi/DownKyi.csproj b/DownKyi/DownKyi.csproj index 4458ad1..73f09d2 100644 --- a/DownKyi/DownKyi.csproj +++ b/DownKyi/DownKyi.csproj @@ -92,6 +92,7 @@ + @@ -168,6 +169,9 @@ ViewVideo.xaml + + SplashWindow.xaml + ViewBiliHelper.xaml @@ -320,6 +324,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/DownKyi/Models/DownloadBase.cs b/DownKyi/Models/DownloadBase.cs index 53b3514..51b221e 100644 --- a/DownKyi/Models/DownloadBase.cs +++ b/DownKyi/Models/DownloadBase.cs @@ -27,7 +27,7 @@ namespace DownKyi.Models public string Uuid { get; } // 需要下载的内容 - public Dictionary NeedDownloadContent { get; private set; } + public Dictionary NeedDownloadContent { get; set; } // 视频的id public string Bvid { get; set; } diff --git a/DownKyi/Models/Downloading.cs b/DownKyi/Models/Downloading.cs index 7147489..6add5c5 100644 --- a/DownKyi/Models/Downloading.cs +++ b/DownKyi/Models/Downloading.cs @@ -10,14 +10,14 @@ namespace DownKyi.Models public Downloading() : base() { // 初始化下载的文件列表 - DownloadFiles = new List(); + DownloadFiles = new Dictionary(); } // Aria相关 public string Gid { get; set; } // 下载的文件 - public List DownloadFiles { get; private set; } + public Dictionary DownloadFiles { get; set; } // 视频类别 public PlayStreamType PlayStreamType { get; set; } diff --git a/DownKyi/Services/Download/AriaDownloadService.cs b/DownKyi/Services/Download/AriaDownloadService.cs index 8bebe9c..31885ac 100644 --- a/DownKyi/Services/Download/AriaDownloadService.cs +++ b/DownKyi/Services/Download/AriaDownloadService.cs @@ -125,8 +125,18 @@ namespace DownKyi.Services.Download // 下载文件名 string fileName = Guid.NewGuid().ToString("N"); - // 记录本次下载的文件 - downloading.Downloading.DownloadFiles.Add(fileName); + string key = $"{downloadVideo.Id}_{downloadVideo.Codecs}"; + if (downloading.Downloading.DownloadFiles.ContainsKey(key)) + { + // 如果存在,表示下载过, + // 则继续使用上次下载的文件名 + fileName = downloading.Downloading.DownloadFiles[key]; + } + else + { + // 记录本次下载的文件 + downloading.Downloading.DownloadFiles.Add(key, fileName); + } // 开始下载 DownloadResult downloadStatus = DownloadByAria(downloading, urls, path, fileName); @@ -173,7 +183,10 @@ namespace DownKyi.Services.Download File.Copy(cover, fileName, true); // 记录本次下载的文件 - downloading.Downloading.DownloadFiles.Add(fileName); + if (!downloading.Downloading.DownloadFiles.ContainsKey(coverUrl)) + { + downloading.Downloading.DownloadFiles.Add(coverUrl, fileName); + } return fileName; } @@ -204,7 +217,10 @@ namespace DownKyi.Services.Download string assFile = $"{downloading.DownloadBase.FilePath}.ass"; // 记录本次下载的文件 - downloading.Downloading.DownloadFiles.Add(assFile); + if (!downloading.Downloading.DownloadFiles.ContainsKey("danmaku")) + { + downloading.Downloading.DownloadFiles.Add("danmaku", assFile); + } int screenWidth = SettingsManager.GetInstance().GetDanmakuScreenWidth(); int screenHeight = SettingsManager.GetInstance().GetDanmakuScreenHeight(); @@ -272,7 +288,10 @@ namespace DownKyi.Services.Download File.WriteAllText(srtFile, subRip.SrtString); // 记录本次下载的文件 - downloading.Downloading.DownloadFiles.Add(srtFile); + if (!downloading.Downloading.DownloadFiles.ContainsKey("subtitle")) + { + downloading.Downloading.DownloadFiles.Add("subtitle", srtFile); + } srtFiles.Add(srtFile); } @@ -345,6 +364,9 @@ namespace DownKyi.Services.Download return; } + // 设置下载状态 + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; + // 解析 switch (downloading.Downloading.PlayStreamType) { @@ -367,8 +389,18 @@ namespace DownKyi.Services.Download /// public void End() { - // TODO + // 下载数据存储服务 + DownloadStorageService downloadStorageService = new DownloadStorageService(); // 保存数据 + foreach (DownloadingItem item in downloadingList) + { + item.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + downloadStorageService.UpdateDownloading(item); + } + foreach (DownloadedItem item in downloadedList) + { + downloadStorageService.UpdateDownloaded(item); + } // 关闭Aria服务器 CloseAriaServer(); @@ -430,7 +462,7 @@ namespace DownKyi.Services.Download } // 降低CPU占用 - Thread.Sleep(100); + Thread.Sleep(200); } } @@ -452,12 +484,10 @@ namespace DownKyi.Services.Download await Task.Run(new Action(() => { - downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; - // 初始化 downloading.DownloadStatusTitle = string.Empty; downloading.DownloadContent = string.Empty; - downloading.Downloading.DownloadFiles.Clear(); + //downloading.Downloading.DownloadFiles.Clear(); // 解析并依次下载音频、视频、弹幕、字幕、封面等内容 Parse(downloading); @@ -465,6 +495,9 @@ namespace DownKyi.Services.Download // 暂停 Pause(downloading); + // 设置下载状态 + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; + string audioUid = null; // 如果需要下载音频 if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"]) @@ -509,7 +542,6 @@ namespace DownKyi.Services.Download // 如果需要下载封面 if (downloading.DownloadBase.NeedDownloadContent["downloadCover"]) { - string fileName = $"{downloading.DownloadBase.FilePath}.{GetImageExtension(downloading.DownloadBase.PageCoverUrl)}"; // page的封面 @@ -595,8 +627,8 @@ namespace DownKyi.Services.Download App.PropertyChangeAsync(new Action(() => { // 加入到下载完成list中,并从下载中list去除 - App.DownloadedList.Add(downloadedItem); - App.DownloadingList.Remove(downloading); + downloadedList.Add(downloadedItem); + downloadingList.Remove(downloading); // 下载完成列表排序 DownloadFinishedSort finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort(); diff --git a/DownKyi/Services/Download/DownloadStorageService.cs b/DownKyi/Services/Download/DownloadStorageService.cs new file mode 100644 index 0000000..e13deec --- /dev/null +++ b/DownKyi/Services/Download/DownloadStorageService.cs @@ -0,0 +1,219 @@ +using DownKyi.Core.Storage.Database.Download; +using DownKyi.Models; +using DownKyi.ViewModels.DownloadManager; +using System.Collections.Generic; + +namespace DownKyi.Services.Download +{ + public class DownloadStorageService + { + #region 下载中数据 + + /// + /// 添加下载中数据 + /// + /// + public void AddDownloading(DownloadingItem downloadingItem) + { + AddDownloadBase(downloadingItem.DownloadBase); + + DownloadingDb downloadingDb = new DownloadingDb(); + object obj = downloadingDb.QueryById(downloadingItem.DownloadBase.Uuid); + if (obj == null) + { + downloadingDb.Insert(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading); + } + downloadingDb.Close(); + } + + /// + /// 删除下载中数据 + /// + /// + public void RemoveDownloading(DownloadingItem downloadingItem) + { + RemoveDownloadBase(downloadingItem.DownloadBase.Uuid); + + DownloadingDb downloadingDb = new DownloadingDb(); + downloadingDb.Delete(downloadingItem.DownloadBase.Uuid); + downloadingDb.Close(); + } + + /// + /// 获取所有的下载中数据 + /// + /// + public List GetDownloading() + { + // 从数据库获取数据 + DownloadingDb downloadingDb = new DownloadingDb(); + Dictionary dic = downloadingDb.QueryAll(); + downloadingDb.Close(); + + // 遍历 + List list = new List(); + foreach (KeyValuePair item in dic) + { + if (item.Value is Downloading downloading) + { + DownloadingItem downloadingItem = new DownloadingItem + { + DownloadBase = GetDownloadBase(item.Key), + Downloading = downloading + }; + + list.Add(downloadingItem); + } + } + + return list; + } + + /// + /// 修改下载中数据 + /// + /// + public void UpdateDownloading(DownloadingItem downloadingItem) + { + UpdateDownloadBase(downloadingItem.DownloadBase); + + DownloadingDb downloadingDb = new DownloadingDb(); + downloadingDb.Update(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading); + downloadingDb.Close(); + } + + #endregion + + #region 下载完成数据 + + /// + /// 添加下载完成数据 + /// + /// + public void AddDownloaded(DownloadedItem downloadedItem) + { + AddDownloadBase(downloadedItem.DownloadBase); + + DownloadedDb downloadedDb = new DownloadedDb(); + object obj = downloadedDb.QueryById(downloadedItem.DownloadBase.Uuid); + if (obj == null) + { + downloadedDb.Insert(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded); + } + downloadedDb.Close(); + } + + /// + /// 删除下载完成数据 + /// + /// + public void RemoveDownloaded(DownloadedItem downloadedItem) + { + RemoveDownloadBase(downloadedItem.DownloadBase.Uuid); + + DownloadedDb downloadedDb = new DownloadedDb(); + downloadedDb.Delete(downloadedItem.DownloadBase.Uuid); + downloadedDb.Close(); + } + + /// + /// 获取所有的下载完成数据 + /// + /// + public List GetDownloaded() + { + // 从数据库获取数据 + DownloadedDb downloadedDb = new DownloadedDb(); + Dictionary dic = downloadedDb.QueryAll(); + downloadedDb.Close(); + + // 遍历 + List list = new List(); + foreach (KeyValuePair item in dic) + { + if (item.Value is Downloaded downloaded) + { + DownloadedItem downloadingItem = new DownloadedItem + { + DownloadBase = GetDownloadBase(item.Key), + Downloaded = downloaded + }; + + list.Add(downloadingItem); + } + } + + return list; + } + + /// + /// 修改下载完成数据 + /// + /// + public void UpdateDownloaded(DownloadedItem downloadedItem) + { + UpdateDownloadBase(downloadedItem.DownloadBase); + + DownloadedDb downloadedDb = new DownloadedDb(); + downloadedDb.Update(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded); + downloadedDb.Close(); + } + + #endregion + + #region DownloadBase + + /// + /// 向数据库添加DownloadBase + /// + /// + private void AddDownloadBase(DownloadBase downloadBase) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + object obj = downloadBaseDb.QueryById(downloadBase.Uuid); + if (obj == null) + { + downloadBaseDb.Insert(downloadBase.Uuid, downloadBase); + } + downloadBaseDb.Close(); + } + + /// + /// 从数据库删除DownloadBase + /// + /// + private void RemoveDownloadBase(string uuid) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + downloadBaseDb.Delete(uuid); + downloadBaseDb.Close(); + } + + /// + /// 从数据库获取所有的DownloadBase + /// + /// + private DownloadBase GetDownloadBase(string uuid) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + object obj = downloadBaseDb.QueryById(uuid); + downloadBaseDb.Close(); + + return obj is DownloadBase downloadBase ? downloadBase : null; + } + + /// + /// 从数据库修改DownloadBase + /// + /// + private void UpdateDownloadBase(DownloadBase downloadBase) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + downloadBaseDb.Update(downloadBase.Uuid, downloadBase); + downloadBaseDb.Close(); + } + + #endregion + + } +} diff --git a/DownKyi/ViewModels/MainWindowViewModel.cs b/DownKyi/ViewModels/MainWindowViewModel.cs index 8066cf0..5167f55 100644 --- a/DownKyi/ViewModels/MainWindowViewModel.cs +++ b/DownKyi/ViewModels/MainWindowViewModel.cs @@ -156,6 +156,17 @@ namespace DownKyi.ViewModels { "Parameter", "start" } }; regionManager.RequestNavigate("ContentRegion", ViewIndexViewModel.Tag, param); + + // 关闭欢迎页 + if (App.Dictionary.ContainsKey("SplashWindow")) + { + Views.SplashWindow sw = App.Dictionary["SplashWindow"] as Views.SplashWindow; + // 在sw的线程上关闭SplashWindow + sw.Dispatcher.Invoke(() => sw.Close()); + } + + // 设置焦点 + Application.Current.MainWindow.Activate(); }); // 顶部caption栏的点击事件,包括双击和拖动 diff --git a/DownKyi/Views/Dialogs/ViewDownloadSetter.xaml b/DownKyi/Views/Dialogs/ViewDownloadSetter.xaml index 0320c5a..f354ee8 100644 --- a/DownKyi/Views/Dialogs/ViewDownloadSetter.xaml +++ b/DownKyi/Views/Dialogs/ViewDownloadSetter.xaml @@ -26,11 +26,11 @@ Grid.Row="0" Background="{DynamicResource BrushCaptionBackground}" KeyboardNavigation.TabNavigation="None"> - + diff --git a/DownKyi/Views/Dialogs/ViewParsingSelector.xaml b/DownKyi/Views/Dialogs/ViewParsingSelector.xaml index d53ff4b..9b4dd48 100644 --- a/DownKyi/Views/Dialogs/ViewParsingSelector.xaml +++ b/DownKyi/Views/Dialogs/ViewParsingSelector.xaml @@ -26,11 +26,11 @@ Grid.Row="0" Background="{DynamicResource BrushCaptionBackground}" KeyboardNavigation.TabNavigation="None"> - + diff --git a/DownKyi/Views/SplashWindow.xaml b/DownKyi/Views/SplashWindow.xaml new file mode 100644 index 0000000..c2f8d97 --- /dev/null +++ b/DownKyi/Views/SplashWindow.xaml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/DownKyi/Views/SplashWindow.xaml.cs b/DownKyi/Views/SplashWindow.xaml.cs new file mode 100644 index 0000000..fac9b76 --- /dev/null +++ b/DownKyi/Views/SplashWindow.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace DownKyi.Views +{ + /// + /// SplashWindow.xaml 的交互逻辑 + /// + public partial class SplashWindow : Window + { + public SplashWindow() + { + InitializeComponent(); + } + } +}