You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
downkyi/DownKyi/Services/Download/AddToDownloadService.cs

434 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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.Settings.Models;
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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
namespace DownKyi.Services.Download
{
/// <summary>
/// 添加到下载列表服务
/// </summary>
public class AddToDownloadService
{
private readonly string Tag = "AddToDownloadService";
private IInfoService videoInfoService;
private VideoInfoView videoInfoView;
private List<VideoSection> videoSections;
// 下载内容
private bool downloadAudio = true;
private bool downloadVideo = true;
private bool downloadDanmaku = true;
private bool downloadSubtitle = true;
private bool downloadCover = true;
/// <summary>
/// 添加下载
/// </summary>
/// <param name="streamType"></param>
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;
}
}
/// <summary>
/// 添加下载
/// </summary>
/// <param name="id"></param>
/// <param name="streamType"></param>
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)
{
this.videoInfoService = videoInfoService;
}
public void GetVideo(VideoInfoView videoInfoView, List<VideoSection> videoSections)
{
this.videoInfoView = videoInfoView;
this.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<VideoSection>
{
new VideoSection
{
Id = 0,
Title = "default",
IsSelected = true,
VideoPages = videoInfoService.GetVideoPages()
}
};
}
// 将所有视频设置为选中
foreach (VideoSection section in videoSections)
{
foreach (var item in section.VideoPages)
{
item.IsSelected = true;
}
}
}
/// <summary>
/// 解析视频流
/// </summary>
/// <param name="videoInfoService"></param>
public void ParseVideo(IInfoService videoInfoService)
{
if (videoSections == null) { return; }
foreach (VideoSection section in videoSections)
{
foreach (VideoPage page in section.VideoPages)
{
// 执行解析任务
videoInfoService.GetVideoStream(page);
}
}
}
/// <summary>
/// 选择文件夹和下载项
/// </summary>
/// <param name="dialogService"></param>
public string SetDirectory(IDialogService dialogService)
{
// 选择的下载文件夹
string directory = string.Empty;
// 是否使用默认下载目录
if (SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES)
{
// 下载内容
VideoContentSettings videoContent = SettingsManager.GetInstance().GetVideoContent();
downloadAudio = videoContent.DownloadAudio;
downloadVideo = videoContent.DownloadVideo;
downloadDanmaku = videoContent.DownloadDanmaku;
downloadSubtitle = videoContent.DownloadSubtitle;
downloadCover = videoContent.DownloadCover;
directory = SettingsManager.GetInstance().GetSaveVideoRootPath();
}
else
{
// 打开文件夹选择器
dialogService.ShowDialog(ViewDownloadSetterViewModel.Tag, null, result =>
{
if (result.Result == ButtonResult.OK)
{
// 选择的下载文件夹
directory = result.Parameters.GetValue<string>("directory");
// 下载内容
downloadAudio = result.Parameters.GetValue<bool>("downloadAudio");
downloadVideo = result.Parameters.GetValue<bool>("downloadVideo");
downloadDanmaku = result.Parameters.GetValue<bool>("downloadDanmaku");
downloadSubtitle = result.Parameters.GetValue<bool>("downloadSubtitle");
downloadCover = result.Parameters.GetValue<bool>("downloadCover");
}
});
}
if (!Directory.Exists(Directory.GetDirectoryRoot(directory)))
{
var alert = new AlertService(dialogService);
alert.ShowError(DictionaryResource.GetString("DriveNotFound"));
directory = string.Empty;
}
// 下载设置dialog中如果点击取消或者关闭窗口
// 会返回空字符串,
// 这时直接退出
if (directory == null || directory == string.Empty) { return null; }
// 文件夹不存在则创建
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
return directory;
}
/// <summary>
/// 添加到下载列表
/// </summary>
/// <param name="eventAggregator">传递事件的对象</param>
/// <param name="directory">下载路径</param>
/// <param name="isAll">是否下载所有,包括未选中项</param>
/// <returns>添加的数量</returns>
public int AddToDownload(IEventAggregator eventAggregator, string directory, bool isAll = false)
{
if (directory == null || directory == string.Empty) { return -1; }
if (videoSections == null) { return -1; }
// 视频计数
int i = 0;
// 添加到下载
foreach (VideoSection section in videoSections)
{
if (section.VideoPages == null) { continue; }
foreach (VideoPage page in section.VideoPages)
{
// 只下载选中项,跳过未选中项
if (!isAll && !page.IsSelected) { continue; }
// 没有解析的也跳过
if (page.PlayUrl == null) { continue; }
// 判断VideoQuality
int retry = 0;
while (page.VideoQuality == null && retry < 5)
{
// 执行解析任务
videoInfoService.GetVideoStream(page);
retry++;
}
if (page.VideoQuality == null) { continue; }
// 判断是否同一个视频需要cid、画质、音质、视频编码都相同
// 如果存在正在下载列表,则跳过,并提示
bool isDownloading = false;
foreach (DownloadingItem 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<MessageEvent>().Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloading")}");
isDownloading = true;
break;
}
}
if (isDownloading) { continue; }
// TODO 如果存在下载完成列表,弹出选择框是否再次下载
bool isDownloaded = false;
foreach (DownloadedItem 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<MessageEvent>().Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloaded")}");
isDownloaded = true;
break;
}
}
if (isDownloaded) { continue; }
// 视频分区
int zoneId = -1;
List<ZoneAttr> zoneList = VideoZone.Instance().GetZones();
ZoneAttr zone = zoneList.Find(it => it.Id == videoInfoView.TypeId);
if (zone != null)
{
if (zone.ParentId == 0)
{
zoneId = zone.Id;
}
else
{
ZoneAttr zoneParent = zoneList.Find(it => it.Id == zone.ParentId);
if (zoneParent != null)
{
zoneId = zoneParent.Id;
}
}
}
// 如果只有一个视频章节,则不在命名中出现
string sectionName = string.Empty;
if (videoSections.Count > 1)
{
sectionName = section.Title;
}
// 文件路径
List<FileNamePart> fileNameParts = SettingsManager.GetInstance().GetFileNameParts();
FileName 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));
// 序号设置
OrderFormat orderFormat = SettingsManager.GetInstance().GetOrderFormat();
switch (orderFormat)
{
case OrderFormat.NATURAL:
fileName.SetOrder(page.Order);
break;
case OrderFormat.LEADING_ZEROS:
fileName.SetOrder(page.Order, section.VideoPages.Count);
break;
}
// 合成绝对路径
string filePath = Path.Combine(directory, fileName.RelativePath());
// 视频类别
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(new Action(() =>
{
// 如果不存在,直接添加到下载列表
DownloadBase 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; }),
};
Downloading downloading = new Downloading
{
PlayStreamType = playStreamType,
DownloadStatus = DownloadStatus.NOT_STARTED,
};
// 需要下载的内容
downloadBase.NeedDownloadContent["downloadAudio"] = downloadAudio;
downloadBase.NeedDownloadContent["downloadVideo"] = downloadVideo;
downloadBase.NeedDownloadContent["downloadDanmaku"] = downloadDanmaku;
downloadBase.NeedDownloadContent["downloadSubtitle"] = downloadSubtitle;
downloadBase.NeedDownloadContent["downloadCover"] = downloadCover;
DownloadingItem downloadingItem = new DownloadingItem
{
DownloadBase = downloadBase,
Downloading = downloading,
PlayUrl = page.PlayUrl,
};
App.DownloadingList.Add(downloadingItem);
Thread.Sleep(10);
}));
i++;
}
}
return i;
}
}
}