using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Avalonia.Threading; using DownKyi.Core.BiliApi.BiliUtils; using DownKyi.Core.BiliApi.VideoStream; using DownKyi.Core.BiliApi.Zone; using DownKyi.Core.FileName; using DownKyi.Core.Logging; using DownKyi.Core.Settings; using DownKyi.Core.Utils; using DownKyi.Events; using DownKyi.Models; using DownKyi.Utils; using DownKyi.ViewModels.Dialogs; using DownKyi.ViewModels.DownloadManager; using DownKyi.ViewModels.PageViewModels; using Prism.Events; using Prism.Services.Dialogs; using IDialogService = DownKyi.PrismExtension.Dialog.IDialogService; namespace DownKyi.Services.Download; /// /// 添加到下载列表服务 /// public class AddToDownloadService { private readonly string Tag = "AddToDownloadService"; private IInfoService _videoInfoService; private VideoInfoView? _videoInfoView; private List? _videoSections; // 下载内容 private bool _downloadAudio = true; private bool _downloadVideo = true; private bool _downloadDanmaku = true; private bool _downloadSubtitle = true; private bool _downloadCover = true; /// /// 添加下载 /// /// public AddToDownloadService(PlayStreamType streamType) { switch (streamType) { case PlayStreamType.Video: _videoInfoService = new VideoInfoService(null); break; case PlayStreamType.Bangumi: _videoInfoService = new BangumiInfoService(null); break; case PlayStreamType.Cheese: _videoInfoService = new CheeseInfoService(null); break; default: break; } } /// /// 添加下载 /// /// /// public AddToDownloadService(string id, PlayStreamType streamType) { switch (streamType) { case PlayStreamType.Video: _videoInfoService = new VideoInfoService(id); break; case PlayStreamType.Bangumi: _videoInfoService = new BangumiInfoService(id); break; case PlayStreamType.Cheese: _videoInfoService = new CheeseInfoService(id); break; default: break; } } public void SetVideoInfoService(IInfoService videoInfoService) { _videoInfoService = videoInfoService; } public void GetVideo(VideoInfoView videoInfoView, List videoSections) { _videoInfoView = videoInfoView; _videoSections = videoSections; } public void GetVideo() { _videoInfoView = _videoInfoService.GetVideoView(); if (_videoInfoView == null) { LogManager.Debug(Tag, "VideoInfoView is null."); return; } _videoSections = _videoInfoService.GetVideoSections(true); if (_videoSections == null) { LogManager.Debug(Tag, "videoSections is not exist."); _videoSections = new List { new() { Id = 0, Title = "default", IsSelected = true, VideoPages = _videoInfoService.GetVideoPages() } }; } // 将所有视频设置为选中 foreach (var section in _videoSections) { foreach (var item in section.VideoPages) { item.IsSelected = true; } } } /// /// 解析视频流 /// /// public void ParseVideo(IInfoService videoInfoService) { if (_videoSections == null) { return; } foreach (var section in _videoSections) { foreach (var page in section.VideoPages) { // 执行解析任务 videoInfoService.GetVideoStream(page); } } } /// /// 选择文件夹和下载项 /// /// public async Task SetDirectory(IDialogService? dialogService) { if (dialogService == null) return null; // 选择的下载文件夹 var directory = string.Empty; // 是否使用默认下载目录 if (SettingsManager.GetInstance().GetIsUseSaveVideoRootPath() == AllowStatus.Yes) { // 下载内容 var videoContent = SettingsManager.GetInstance().GetVideoContent(); _downloadAudio = videoContent.DownloadAudio; _downloadVideo = videoContent.DownloadVideo; _downloadDanmaku = videoContent.DownloadDanmaku; _downloadSubtitle = videoContent.DownloadSubtitle; _downloadCover = videoContent.DownloadCover; directory = SettingsManager.GetInstance().GetSaveVideoRootPath(); } else { // 打开文件夹选择器 await dialogService.ShowDialogAsync(ViewDownloadSetterViewModel.Tag, null, result => { if (result.Result != ButtonResult.OK) return; // 选择的下载文件夹 directory = result.Parameters.GetValue("directory"); // 下载内容 _downloadAudio = result.Parameters.GetValue("downloadAudio"); _downloadVideo = result.Parameters.GetValue("downloadVideo"); _downloadDanmaku = result.Parameters.GetValue("downloadDanmaku"); _downloadSubtitle = result.Parameters.GetValue("downloadSubtitle"); _downloadCover = result.Parameters.GetValue("downloadCover"); }); } if (directory == string.Empty) { return null; } if (!Directory.Exists(Directory.GetDirectoryRoot(directory))) { var alert = new AlertService(dialogService); await alert.ShowError(DictionaryResource.GetString("DriveNotFound")); directory = string.Empty; } // 下载设置dialog中如果点击取消或者关闭窗口, // 会返回空字符串, // 这时直接退出 if (string.IsNullOrEmpty(directory)) { return null; } // 文件夹不存在则创建 if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } return directory; } /// /// 添加到下载列表 /// /// 传递事件的对象 /// dialog /// 下载路径 /// 是否下载所有,包括未选中项 /// 添加的数量 public async Task AddToDownload(IEventAggregator eventAggregator, IDialogService? dialogService, string? directory, bool isAll = false) { if (string.IsNullOrEmpty(directory)) { return -1; } if (_videoSections == null) { return -1; } // 视频计数 var i = 0; // 添加到下载 foreach (var section in _videoSections) { if (section.VideoPages == null) { continue; } foreach (var page in section.VideoPages) { // 只下载选中项,跳过未选中项 if (!isAll && !page.IsSelected) { continue; } // 没有解析的也跳过 if (page.PlayUrl == null) { continue; } // 判断VideoQuality var retry = 0; while (page.VideoQuality == null && retry < 5) { // 执行解析任务 _videoInfoService.GetVideoStream(page); retry++; } if (page.VideoQuality == null) { continue; } // 判断是否同一个视频,需要cid、画质、音质、视频编码都相同 // 如果存在正在下载列表,则跳过,并提示 var isDownloading = false; foreach (var item in App.DownloadingList) { if (item.DownloadBase == null) { continue; } if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && item.AudioCodec.Name == page.AudioQualityFormat && item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) { eventAggregator.GetEvent() .Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloading")}"); isDownloading = true; break; } } if (isDownloading) { continue; } // TODO 如果存在下载完成列表,弹出选择框是否再次下载 var isDownloaded = false; foreach (var item in App.DownloadedList) { if (item.DownloadBase == null) { continue; } if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && item.AudioCodec.Name == page.AudioQualityFormat && item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) { // eventAggregator.GetEvent().Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloaded")}"); // isDownloaded = true; var repeatDownloadStrategy = SettingsManager.GetInstance().GetRepeatDownloadStrategy(); switch (repeatDownloadStrategy) { case RepeatDownloadStrategy.Ask: { var result = ButtonResult.Cancel; await Dispatcher.UIThread.Invoke(async () => { var param = new DialogParameters { { "message", $"{item.Name}已下载,是否重新下载" }, }; await dialogService.ShowDialogAsync(ViewAlreadyDownloadedDialogViewModel.Tag, param, buttonResult => { result = buttonResult.Result; }); }); if (result == ButtonResult.OK) { App.PropertyChangeAsync(() => { App.DownloadedList.Remove(item); }); isDownloaded = false; } else { isDownloaded = true; } break; } case RepeatDownloadStrategy.ReDownload: isDownloaded = false; break; case RepeatDownloadStrategy.JumpOver: isDownloaded = true; break; default: isDownloaded = true; break; } break; } } if (isDownloaded) { continue; } // 视频分区 var zoneId = -1; var zoneList = VideoZone.Instance().GetZones(); var zone = zoneList.Find(it => it.Id == _videoInfoView?.TypeId); if (zone != null) { if (zone.ParentId == 0) { zoneId = zone.Id; } else { var zoneParent = zoneList.Find(it => it.Id == zone.ParentId); if (zoneParent != null) { zoneId = zoneParent.Id; } } } // 如果只有一个视频章节,则不在命名中出现 var sectionName = string.Empty; if (_videoSections.Count > 1) { sectionName = section.Title; } // 文件路径 var fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); var fileName = FileName.Builder(fileNameParts) .SetSection(Format.FormatFileName(sectionName)) .SetMainTitle(Format.FormatFileName(_videoInfoView.Title)) .SetPageTitle(Format.FormatFileName(page.Name)) .SetVideoZone(_videoInfoView.VideoZone.Split('>')[0]) .SetAudioQuality(page.AudioQualityFormat) .SetVideoQuality(page.VideoQuality == null ? "" : page.VideoQuality.QualityFormat) .SetVideoCodec(page.VideoQuality == null ? "" : page.VideoQuality.SelectedVideoCodec.Contains("AVC") ? "AVC" : page.VideoQuality.SelectedVideoCodec.Contains("HEVC") ? "HEVC" : page.VideoQuality.SelectedVideoCodec.Contains("Dolby") ? "Dolby Vision" : page.VideoQuality.SelectedVideoCodec.Contains("AV1") ? "AV1" : "") .SetVideoPublishTime(page.PublishTime) .SetAvid(page.Avid) .SetBvid(page.Bvid) .SetCid(page.Cid) .SetUpMid(page.Owner.Mid) .SetUpName(Format.FormatFileName(page.Owner.Name)); // 序号设置 var orderFormat = SettingsManager.GetInstance().GetOrderFormat(); switch (orderFormat) { case OrderFormat.Natural: fileName.SetOrder(page.Order); break; case OrderFormat.LeadingZeros: fileName.SetOrder(page.Order, section.VideoPages.Count); break; } // 合成绝对路径 var filePath = Path.Combine(directory, fileName.RelativePath()); if (SettingsManager.GetInstance().IsRepeatFileAutoAddNumberSuffix()) { // 如果存在同名文件,自动重命名 // todo 如果重新下载呢。还没想好 var directoryName = Path.GetDirectoryName(filePath); if (Directory.Exists(directoryName)) { var files = Directory.GetFiles(directoryName).Select(Path.GetFileNameWithoutExtension).Distinct().ToList(); if (files.Contains(Path.GetFileNameWithoutExtension(filePath))) { var count = 1; var newFilePath = filePath; while (files.Contains(Path.GetFileNameWithoutExtension(newFilePath))) { newFilePath = Path.Combine(directory, $"{fileName.RelativePath()}({count})"); count++; } filePath = newFilePath; } } } // 视频类别 PlayStreamType playStreamType; switch (_videoInfoView.TypeId) { case -10: playStreamType = PlayStreamType.Cheese; break; case 13: case 23: case 177: case 167: case 11: playStreamType = PlayStreamType.Bangumi; break; case 1: case 3: case 129: case 4: case 36: case 188: case 234: case 223: case 160: case 211: case 217: case 119: case 155: case 202: case 5: case 181: default: playStreamType = PlayStreamType.Video; break; } // 添加到下载列表 App.PropertyChangeAsync(() => { // 如果不存在,直接添加到下载列表 var downloadBase = new DownloadBase { Bvid = page.Bvid, Avid = page.Avid, Cid = page.Cid, EpisodeId = page.EpisodeId, CoverUrl = _videoInfoView.CoverUrl, PageCoverUrl = page.FirstFrame, ZoneId = zoneId, FilePath = filePath, Order = page.Order, MainTitle = _videoInfoView.Title, Name = page.Name, Duration = page.Duration, VideoCodecName = page.VideoQuality.SelectedVideoCodec, Resolution = new Quality { Name = page.VideoQuality.QualityFormat, Id = page.VideoQuality.Quality }, AudioCodec = Constant.GetAudioQualities().FirstOrDefault(t => { return t.Name == page.AudioQualityFormat; }), Page = page.Page }; var downloading = new Downloading { PlayStreamType = playStreamType, DownloadStatus = DownloadStatus.NotStarted, }; // 需要下载的内容 downloadBase.NeedDownloadContent["downloadAudio"] = _downloadAudio; downloadBase.NeedDownloadContent["downloadVideo"] = _downloadVideo; downloadBase.NeedDownloadContent["downloadDanmaku"] = _downloadDanmaku; downloadBase.NeedDownloadContent["downloadSubtitle"] = _downloadSubtitle; downloadBase.NeedDownloadContent["downloadCover"] = _downloadCover; var downloadingItem = new DownloadingItem { DownloadBase = downloadBase, Downloading = downloading, PlayUrl = page.PlayUrl, }; App.DownloadingList.Add(downloadingItem); Thread.Sleep(10); }); i++; } } return i; } }