diff --git a/DownKyi.Core/BiliApi/History/Models/ToViewList.cs b/DownKyi.Core/BiliApi/History/Models/ToViewList.cs index cf22bdb..4458a94 100644 --- a/DownKyi.Core/BiliApi/History/Models/ToViewList.cs +++ b/DownKyi.Core/BiliApi/History/Models/ToViewList.cs @@ -1,10 +1,5 @@ using DownKyi.Core.BiliApi.Models; using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace DownKyi.Core.BiliApi.History.Models { diff --git a/DownKyi/App.xaml.cs b/DownKyi/App.xaml.cs index 906c020..6a5d6a9 100644 --- a/DownKyi/App.xaml.cs +++ b/DownKyi/App.xaml.cs @@ -170,6 +170,7 @@ namespace DownKyi containerRegistry.RegisterForNavigation(ViewMySpaceViewModel.Tag); containerRegistry.RegisterForNavigation(ViewMyFavoritesViewModel.Tag); containerRegistry.RegisterForNavigation(ViewMyBangumiFollowViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewMyToViewVideoViewModel.Tag); containerRegistry.RegisterForNavigation(ViewMyHistoryViewModel.Tag); // downloadManager pages diff --git a/DownKyi/DownKyi.csproj b/DownKyi/DownKyi.csproj index 5ec5bf9..1ee1080 100644 --- a/DownKyi/DownKyi.csproj +++ b/DownKyi/DownKyi.csproj @@ -107,6 +107,7 @@ + @@ -158,6 +159,7 @@ + @@ -234,6 +236,9 @@ ViewMySpace.xaml + + ViewMyToViewVideo.xaml + ViewPublication.xaml @@ -428,6 +433,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/DownKyi/Languages/Default.xaml b/DownKyi/Languages/Default.xaml index 8180f05..ea63788 100644 --- a/DownKyi/Languages/Default.xaml +++ b/DownKyi/Languages/Default.xaml @@ -88,6 +88,9 @@ 刚开始 看到 + + 稍后再看 + 下载选中项 下载全部 diff --git a/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs b/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs index 6d7516d..36d1a9b 100644 --- a/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs +++ b/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs @@ -154,12 +154,12 @@ namespace DownKyi.ViewModels.PageViewModels NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, Url); } - // 视频标题点击事件 + // UP主头像点击事件 private DelegateCommand upCommand; public DelegateCommand UpCommand => upCommand ?? (upCommand = new DelegateCommand(ExecuteUpCommand)); /// - /// 视频标题点击事件 + /// UP主头像点击事件 /// /// private void ExecuteUpCommand(object parameter) diff --git a/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs b/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs new file mode 100644 index 0000000..143caac --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs @@ -0,0 +1,107 @@ +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; +using System.Windows.Media.Imaging; + +namespace DownKyi.ViewModels.PageViewModels +{ + public class ToViewMedia : BindableBase + { + protected readonly IEventAggregator eventAggregator; + + public ToViewMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + // aid + public long Aid { get; set; } + + // bvid + public string Bvid { get; set; } + + // UP主的mid + public long UpMid { get; set; } + + #region 页面属性申明 + + // 是否选中 + private bool isSelected; + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + // 封面 + private BitmapImage cover; + public BitmapImage Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + // 视频标题 + private string title; + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + // UP主的昵称 + private string upName; + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + // UP主的头像 + private BitmapImage upHeader; + public BitmapImage UpHeader + { + get => upHeader; + set => SetProperty(ref upHeader, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + public DelegateCommand TitleCommand => titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) { return; } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, $"{ParseEntrance.VideoUrl}{Bvid}"); + } + + // UP主头像点击事件 + private DelegateCommand upCommand; + public DelegateCommand UpCommand => upCommand ?? (upCommand = new DelegateCommand(ExecuteUpCommand)); + + /// + /// UP主头像点击事件 + /// + /// + private void ExecuteUpCommand(object parameter) + { + if (!(parameter is string tag)) { return; } + + NavigateToView.NavigateToViewUserSpace(eventAggregator, tag, UpMid); + } + + #endregion + + } +} diff --git a/DownKyi/ViewModels/ViewChannelViewModel.cs b/DownKyi/ViewModels/ViewChannelViewModel.cs index 875953e..89d3087 100644 --- a/DownKyi/ViewModels/ViewChannelViewModel.cs +++ b/DownKyi/ViewModels/ViewChannelViewModel.cs @@ -237,7 +237,7 @@ namespace DownKyi.ViewModels /// private async void AddToDownload(bool isOnlySelected) { - // 收藏夹里只有视频 + // 频道里只有视频 AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); // 选择文件夹 diff --git a/DownKyi/ViewModels/ViewMySpaceViewModel.cs b/DownKyi/ViewModels/ViewMySpaceViewModel.cs index 40763e6..eca6626 100644 --- a/DownKyi/ViewModels/ViewMySpaceViewModel.cs +++ b/DownKyi/ViewModels/ViewMySpaceViewModel.cs @@ -346,7 +346,7 @@ namespace DownKyi.ViewModels NavigateToView.NavigationView(eventAggregator, ViewMyBangumiFollowViewModel.Tag, Tag, mid); break; case 2: - Console.WriteLine(SelectedPackage); + NavigateToView.NavigationView(eventAggregator, ViewMyToViewVideoViewModel.Tag, Tag, mid); break; case 3: NavigateToView.NavigationView(eventAggregator, ViewMyHistoryViewModel.Tag, Tag, mid); diff --git a/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs b/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs new file mode 100644 index 0000000..6c8a13d --- /dev/null +++ b/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs @@ -0,0 +1,400 @@ +using DownKyi.Core.BiliApi.History; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.CustomControl; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; + +namespace DownKyi.ViewModels +{ + public class ViewMyToViewVideoViewModel : BaseViewModel + { + public const string Tag = "PageMyToView"; + + private readonly IDialogService dialogService; + + private CancellationTokenSource tokenSource; + + #region 页面属性申明 + + private string pageName = Tag; + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private VectorImage arrowBack; + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private Visibility contentVisibility; + public Visibility ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private ObservableCollection medias; + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + private GifImage loading; + public GifImage Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private Visibility loadingVisibility; + public Visibility LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private Visibility noDataVisibility; + public Visibility NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + #endregion + + public ViewMyToViewVideoViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading gif + Loading = new GifImage(Properties.Resources.loading); + Loading.StartAnimate(); + LoadingVisibility = Visibility.Collapsed; + NoDataVisibility = Visibility.Collapsed; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + Medias = new ObservableCollection(); + + #endregion + + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + public DelegateCommand SelectAllCommand => selectAllCommand ?? (selectAllCommand = new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + public DelegateCommand MediasCommand => mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) { return; } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? (addToDownloadCommand = new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? (addAllToDownloadCommand = new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 稍后再看里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) { continue; } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i == 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent().Publish($"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private async void UpdateToViewMediaList() + { + LoadingVisibility = Visibility.Visible; + NoDataVisibility = Visibility.Collapsed; + Medias.Clear(); + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var toViewList = ToView.GetToView(); + if (toViewList == null || toViewList.Count == 0) + { + LoadingVisibility = Visibility.Collapsed; + NoDataVisibility = Visibility.Visible; + return; + } + + foreach (var toView in toViewList) + { + + // 查询、保存封面 + string coverUrl = toView.Pic; + BitmapImage cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{toView.Pic}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(toView.Aid, toView.Bvid, toView.Cid, coverUrl, 160, 100); + } + + // 获取用户头像 + long upMid = -1; + string upName; + BitmapImage upHeader; + if (toView.Owner != null && toView.Owner.Face != null) + { + upMid = toView.Owner.Mid; + upName = toView.Owner.Name; + StorageHeader storageHeader = new StorageHeader(); + upHeader = storageHeader.GetHeaderThumbnail(toView.Owner.Mid, upName, toView.Owner.Face, 24, 24); + } + else + { + upName = ""; + upHeader = null; + } + + App.PropertyChangeAsync(() => + { + ToViewMedia media = new ToViewMedia(eventAggregator) + { + Aid = toView.Aid, + Bvid = toView.Bvid, + UpMid = upMid, + Cover = cover ?? new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")), + Title = toView.Title, + UpName = upName, + UpHeader = upHeader + }; + + Medias.Add(media); + + ContentVisibility = Visibility.Visible; + LoadingVisibility = Visibility.Collapsed; + NoDataVisibility = Visibility.Collapsed; + }); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + ContentVisibility = Visibility.Collapsed; + LoadingVisibility = Visibility.Collapsed; + NoDataVisibility = Visibility.Collapsed; + + Medias.Clear(); + IsSelectAll = false; + } + + /// + /// 导航到VideoDetail页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 根据传入参数不同执行不同任务 + long mid = navigationContext.Parameters.GetValue("Parameter"); + if (mid == 0) + { + IsSelectAll = false; + foreach (var media in Medias) + { + media.IsSelected = false; + } + + return; + } + + InitView(); + + UpdateToViewMediaList(); + } + + } +} diff --git a/DownKyi/Views/ViewMyHistory.xaml b/DownKyi/Views/ViewMyHistory.xaml index 5b45f40..d8052bf 100644 --- a/DownKyi/Views/ViewMyHistory.xaml +++ b/DownKyi/Views/ViewMyHistory.xaml @@ -127,8 +127,7 @@ + Orientation="Horizontal"> diff --git a/DownKyi/Views/ViewMyToViewVideo.xaml b/DownKyi/Views/ViewMyToViewVideo.xaml new file mode 100644 index 0000000..a869876 --- /dev/null +++ b/DownKyi/Views/ViewMyToViewVideo.xaml @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +