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/AriaDownloadService.cs

406 lines
15 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.Aria2cNet;
using DownKyi.Core.Aria2cNet.Client;
using DownKyi.Core.Aria2cNet.Client.Entity;
using DownKyi.Core.Aria2cNet.Server;
using DownKyi.Core.BiliApi.Login;
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Danmaku2Ass;
using DownKyi.Core.Logging;
using DownKyi.Core.Settings;
using DownKyi.Core.Storage;
using DownKyi.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace DownKyi.Services.Download
{
/// <summary>
/// 音视频采用Aria下载其余采用WebClient下载
/// </summary>
public class AriaDownloadService : DownloadService, IDownloadService
{
private CancellationTokenSource tokenSource;
public AriaDownloadService(ObservableCollection<DownloadingItem> downloadingList, ObservableCollection<DownloadedItem> downloadedList) : base(downloadingList, downloadedList)
{
Tag = "AriaDownloadService";
}
public string DownloadAudio(DownloadingItem downloading)
{
// 如果没有Dash返回null
if(downloading.PlayUrl.Dash == null) { return null; }
// 如果audio列表没有内容则返回null
if (downloading.PlayUrl.Dash.Audio == null) { return null; }
else if (downloading.PlayUrl.Dash.Audio.Count == 0) { return null; }
throw new NotImplementedException();
}
/// <summary>
/// 下载封面
/// </summary>
/// <param name="downloading"></param>
public void DownloadCover(DownloadingItem downloading)
{
// 查询、保存封面
StorageCover storageCover = new StorageCover();
string cover = storageCover.GetCover(downloading.Avid, downloading.Bvid, downloading.Cid, downloading.CoverUrl);
if (cover == null)
{
return;
}
// 图片的扩展名
string[] temp = downloading.CoverUrl.Split('.');
string fileExtension = temp[temp.Length - 1];
// 图片的地址
string coverPath = $"{StorageManager.GetCover()}/{cover}";
// 复制图片到指定位置
try
{
File.Copy(coverPath, $"{downloading.FilePath}.{fileExtension}");
}
catch (Exception e)
{
Core.Utils.Debugging.Console.PrintLine(e);
LogManager.Error(Tag, e);
}
}
/// <summary>
/// 下载弹幕
/// </summary>
/// <param name="downloading"></param>
public void DownloadDanmaku(DownloadingItem downloading)
{
string title = $"{downloading.Name}";
string assFile = $"{downloading.FilePath}.ass";
int screenWidth = SettingsManager.GetInstance().GetDanmakuScreenWidth();
int screenHeight = SettingsManager.GetInstance().GetDanmakuScreenHeight();
//if (SettingsManager.GetInstance().IsCustomDanmakuResolution() != AllowStatus.YES)
//{
// if (downloadingEntity.Width > 0 && downloadingEntity.Height > 0)
// {
// screenWidth = downloadingEntity.Width;
// screenHeight = downloadingEntity.Height;
// }
//}
// 字幕配置
var subtitleConfig = new Config
{
Title = title,
ScreenWidth = screenWidth,
ScreenHeight = screenHeight,
FontName = SettingsManager.GetInstance().GetDanmakuFontName(),
BaseFontSize = SettingsManager.GetInstance().GetDanmakuFontSize(),
LineCount = SettingsManager.GetInstance().GetDanmakuLineCount(),
LayoutAlgorithm = SettingsManager.GetInstance().GetDanmakuLayoutAlgorithm().ToString("G").ToLower(), // async/sync
TuneDuration = 0,
DropOffset = 0,
BottomMargin = 0,
CustomOffset = 0
};
Core.Danmaku2Ass.Bilibili.GetInstance()
.SetTopFilter(SettingsManager.GetInstance().GetDanmakuTopFilter() == AllowStatus.YES)
.SetBottomFilter(SettingsManager.GetInstance().GetDanmakuBottomFilter() == AllowStatus.YES)
.SetScrollFilter(SettingsManager.GetInstance().GetDanmakuScrollFilter() == AllowStatus.YES)
.Create(downloading.Avid, downloading.Cid, subtitleConfig, assFile);
}
/// <summary>
/// 下载字幕
/// </summary>
/// <param name="downloading"></param>
public void DownloadSubtitle(DownloadingItem downloading)
{
var subRipTexts = VideoStream.GetSubtitle(downloading.Avid, downloading.Bvid, downloading.Cid);
foreach (var subRip in subRipTexts)
{
string srtFile = $"{downloading.FilePath}_{subRip.LanDoc}.srt";
try
{
File.WriteAllText(srtFile, subRip.SrtString);
}
catch (Exception e)
{
Core.Utils.Debugging.Console.PrintLine("DownloadSubtitle()发生异常: {0}", e);
LogManager.Error("DownloadSubtitle()", e);
}
}
}
public string DownloadVideo(DownloadingItem downloading)
{
throw new NotImplementedException();
}
/// <summary>
/// 停止下载服务
/// </summary>
public void End()
{
// TODO something
// 关闭Aria服务器
CloseAriaServer();
// 结束任务
tokenSource.Cancel();
}
public void MixedFlow(DownloadingItem downloading, string audioUid, string videoUid)
{
throw new NotImplementedException();
}
/// <summary>
/// 解析视频流的下载链接
/// </summary>
/// <param name="downloading"></param>
public void Parse(DownloadingItem downloading)
{
if (downloading.PlayUrl != null && downloading.DownloadStatus == DownloadStatus.NOT_STARTED)
{
return;
}
switch (downloading.PlayStreamType)
{
case PlayStreamType.VIDEO:
downloading.PlayUrl = VideoStream.GetVideoPlayUrl(downloading.Avid, downloading.Bvid, downloading.Cid);
break;
case PlayStreamType.BANGUMI:
downloading.PlayUrl = VideoStream.GetBangumiPlayUrl(downloading.Avid, downloading.Bvid, downloading.Cid);
break;
case PlayStreamType.CHEESE:
downloading.PlayUrl = VideoStream.GetCheesePlayUrl(downloading.Avid, downloading.Bvid, downloading.Cid, downloading.EpisodeId);
break;
default:
break;
}
}
/// <summary>
/// 启动下载服务
/// </summary>
public async void Start()
{
// 启动Aria服务器
StartAriaServer();
await Task.Run(DoWork, (tokenSource = new CancellationTokenSource()).Token);
}
/// <summary>
/// 执行任务
/// </summary>
private async void DoWork()
{
CancellationToken cancellationToken = tokenSource.Token;
while (true)
{
int maxDownloading = SettingsManager.GetInstance().GetAriaMaxConcurrentDownloads();
int countDownloading = 0;
bool isOutOfMaxDownloading = false;
foreach (DownloadingItem downloading in downloadingList)
{
// 对正在下载的元素计数
if (downloading.DownloadStatus == DownloadStatus.DOWNLOADING)
{
countDownloading++;
}
// 正在下载数量等于最大下载数量,退出本次循环
if (countDownloading == maxDownloading)
{
break;
}
// 正在下载数量大于最大下载数量
if (countDownloading > maxDownloading)
{
isOutOfMaxDownloading = true;
}
// 将超过下载数量的元素暂停
if (isOutOfMaxDownloading)
{
if (downloading.DownloadStatus == DownloadStatus.DOWNLOADING)
{
downloading.DownloadStatus = DownloadStatus.PAUSE;
}
}
await Task.Run(new Action(() =>
{
downloading.DownloadStatus = DownloadStatus.DOWNLOADING;
// 依次下载音频、视频、弹幕、字幕、封面等内容
Parse(downloading);
string audioUid = DownloadAudio(downloading);
string videoUid = DownloadVideo(downloading);
DownloadDanmaku(downloading);
DownloadSubtitle(downloading);
DownloadCover(downloading);
MixedFlow(downloading, audioUid, videoUid);
}),
(tokenSource = new CancellationTokenSource()).Token);
}
// 判断是否该结束线程若为true跳出while循环
if (cancellationToken.IsCancellationRequested)
{
Core.Utils.Debugging.Console.PrintLine("AriaDownloadService: 下载服务结束跳出while循环");
LogManager.Debug(Tag, "下载服务结束");
break;
}
// 降低CPU占用
Thread.Sleep(500);
}
}
/// <summary>
/// 启动Aria服务器
/// </summary>
private async void StartAriaServer()
{
List<string> header = new List<string>
{
$"Cookie: {LoginHelper.GetLoginInfoCookiesString()}",
$"Origin: https://www.bilibili.com",
$"Referer: https://www.bilibili.com",
$"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 91.0.4472.77 Safari / 537.36"
};
AriaConfig config = new AriaConfig()
{
ListenPort = SettingsManager.GetInstance().GetAriaListenPort(),
Token = "downkyi",
LogLevel = SettingsManager.GetInstance().GetAriaLogLevel(),
MaxConcurrentDownloads = SettingsManager.GetInstance().GetAriaMaxConcurrentDownloads(),
MaxConnectionPerServer = 16, // 最大取16
Split = SettingsManager.GetInstance().GetAriaSplit(),
//MaxTries = 5,
MinSplitSize = 10, // 10MB
MaxOverallDownloadLimit = SettingsManager.GetInstance().GetAriaMaxOverallDownloadLimit() * 1024L, // 输入的单位是KB/s所以需要乘以1024
MaxDownloadLimit = SettingsManager.GetInstance().GetAriaMaxDownloadLimit() * 1024L, // 输入的单位是KB/s所以需要乘以1024
MaxOverallUploadLimit = 0,
MaxUploadLimit = 0,
ContinueDownload = true,
FileAllocation = SettingsManager.GetInstance().GetAriaFileAllocation(),
Headers = header
};
var task = await AriaServer.StartServerAsync(config);
if (task) { Console.WriteLine("Start ServerAsync Completed"); }
Console.WriteLine("Start ServerAsync end");
// 恢复所有下载
//var ariaPause = await AriaClient.UnpauseAllAsync();
//if (ariaPause != null)
//{
// Core.Utils.Debugging.Console.PrintLine(ariaPause.ToString());
//}
}
/// <summary>
/// 关闭Aria服务器
/// </summary>
private void CloseAriaServer()
{
new Thread(() =>
{
// 暂停所有下载
var ariaPause = AriaClient.PauseAllAsync();
Core.Utils.Debugging.Console.PrintLine(ariaPause.ToString());
// 关闭服务器
bool close = AriaServer.CloseServer();
Core.Utils.Debugging.Console.PrintLine(close);
})
{ IsBackground = false }
.Start();
}
/// <summary>
/// 采用Aria下载文件
/// </summary>
/// <param name="downloading"></param>
/// <returns></returns>
private DownloadResult DownloadByAria(DownloadingItem downloading, List<string> urls, string localFileName)
{
string[] temp = downloading.FilePath.Split('/');
string path = downloading.FilePath.Replace(temp[temp.Length - 1], "");
AriaSendOption option = new AriaSendOption
{
//HttpProxy = $"http://{Settings.GetAriaHttpProxy()}:{Settings.GetAriaHttpProxyListenPort()}",
Dir = path,
Out = localFileName
//Header = $"cookie: {Login.GetLoginInfoCookiesString()}\nreferer: https://www.bilibili.com",
//UseHead = "true",
//UserAgent = Utils.GetUserAgent()
};
// 如果设置了代理则增加HttpProxy
if (SettingsManager.GetInstance().IsAriaHttpProxy() == AllowStatus.YES)
{
option.HttpProxy = $"http://{SettingsManager.GetInstance().GetAriaHttpProxy()}:{SettingsManager.GetInstance().GetAriaHttpProxyListenPort()}";
}
// 添加一个下载
var ariaAddUri = AriaClient.AddUriAsync(urls, option);
if (ariaAddUri == null || ariaAddUri.Result == null || ariaAddUri.Result.Result == null)
{
return DownloadResult.FAILED;
}
// 保存gid
string gid = ariaAddUri.Result.Result;
downloading.Gid = gid;
// 管理下载
AriaManager ariaManager = new AriaManager();
ariaManager.TellStatus += AriaTellStatus;
ariaManager.DownloadFinish += AriaDownloadFinish;
return ariaManager.GetDownloadStatus(gid, new Action(() =>
{
switch (downloading.DownloadStatus)
{
case DownloadStatus.PAUSE:
var ariaPause = AriaClient.PauseAsync(downloading.Gid);
// TODO
break;
case DownloadStatus.DOWNLOADING:
var ariaUnpause = AriaClient.UnpauseAsync(downloading.Gid);
// TODO
break;
}
}));
}
private void AriaTellStatus(long totalLength, long completedLength, long speed, string gid)
{
throw new NotImplementedException();
}
private void AriaDownloadFinish(bool isSuccess, string downloadPath, string gid, string msg)
{
throw new NotImplementedException();
}
}
}