mirror of
https://github.com/leiurayer/downkyi.git
synced 2026-10-20 00:17:44 +00:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d37387e08d | ||
|
|
4f10bbf1b6 | ||
|
|
95a02925d5 | ||
|
|
d6cfc47b50 | ||
|
|
0e2058548f | ||
|
|
4fd747d382 | ||
|
|
bc03b53ee8 | ||
|
|
e69fd47e30 | ||
|
|
99f8bb6ca5 | ||
|
|
bbfa57f407 | ||
|
|
6652d27bfe | ||
|
|
c5e277941a | ||
|
|
f2804b3cd7 | ||
|
|
c42147cf28 | ||
|
|
577631c295 | ||
|
|
0caa3a6629 | ||
|
|
4cf196cdc2 | ||
|
|
cf41095725 |
@@ -1,5 +1,33 @@
|
||||
# 更新日志
|
||||
|
||||
* `2022/03/20` v1.5.0-alpha6
|
||||
1. [修复] 一些已知问题。
|
||||
|
||||
* `2022/03/19` v1.5.0-alpha5
|
||||
1. [优化] 文件命名格式中,时间格式可设置。
|
||||
2. [修复] 数据库异常锁定的问题。
|
||||
3. [修复] 视频标题和分P标题相同时找不到下载文件的问题。
|
||||
4. [修复] 150%缩放下的窗口不超出屏幕。
|
||||
5. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/13` v1.5.0-alpha4
|
||||
1. [优化] 配置文件目录改为当前程序目录。
|
||||
2. [修复] 部分UI显示。
|
||||
3. [修复] 因数据库中的重复内容导致的闪退问题。
|
||||
4. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/12` v1.5.0-alpha3
|
||||
1. [修复] 当用户性别为保密时,程序闪退的问题。
|
||||
2. [修复] 批量下载UP主视频时,程序偶尔闪退的问题。
|
||||
3. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/07` v1.5.0-alpha2
|
||||
1. [优化] 重构程序架构,解决一些已知问题。
|
||||
2. [优化] 界面UI的显示与操作。
|
||||
3. [新增] 文件命名格式:avid、bvid、cid、UP主信息、视频发布时间。
|
||||
4. [修复] 视频音质列表导致的闪退问题。
|
||||
5. [修复] 图片下载导致的闪退问题。
|
||||
|
||||
* `2022/03/05` v1.5.0-alpha1
|
||||
1. [优化] 重构程序架构,解决一些已知问题。
|
||||
2. [新增] 最高支持8K视频。
|
||||
|
||||
@@ -9,28 +9,27 @@
|
||||
|
||||
[全部更新日志](CHANGELOG.md)
|
||||
|
||||
* `2022/03/05` v1.5.0-alpha1
|
||||
1. [优化] 重构程序架构,解决一些已知问题。
|
||||
2. [新增] 最高支持8K视频。
|
||||
3. [新增] 支持杜比全景声和杜比视界。
|
||||
4. [新增] 支持字幕下载。
|
||||
5. [新增] 支持部分短链接(如 https://b23.tv/BV17x411w7KC )。
|
||||
6. [新增] 下载内容可选,可根据需要选择下载视频、音频、弹幕、字幕、封面。
|
||||
7. [新增] 下载文件命名模块,可自主设置文件名。
|
||||
* `2022/03/20` v1.5.0-alpha6
|
||||
1. [修复] 一些已知问题。
|
||||
|
||||
## 下载
|
||||
|
||||
- [哔哩下载姬最新版](https://github.com/FlySelfLog/downkyi/releases/download/v1.5.0-alpha1/DownKyi-1.5.0-alpha1.zip)
|
||||
- [哔哩下载姬最新版](https://github.com/FlySelfLog/downkyi/releases/download/v1.5.0-alpha6/DownKyi-1.5.0-alpha6.zip)
|
||||
|
||||
- [下载页面](https://github.com/FlySelfLog/downkyi/releases)
|
||||
|
||||
|
||||
## 赞助
|
||||
|
||||
如果这个项目对您有很大帮助,并且您希望支持该项目的开发和维护,请随时扫描一下二维码进行捐赠。非常感谢您的捐款,谢谢!
|
||||
|
||||

|
||||
|
||||
## 开发
|
||||
|
||||
### 相关项目
|
||||
|
||||
- [哔哩哔哩-API收集整理](https://github.com/SocialSisterYi/bilibili-API-collect)
|
||||
|
||||
## 免责申明
|
||||
|
||||
1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace DownKyi.Core.Aria2cNet.Client.Entity
|
||||
//[JsonProperty("use-head")]
|
||||
//public string UseHead { get; set; }
|
||||
|
||||
//[JsonProperty("user-agent")]
|
||||
//public string UserAgent { get; set; }
|
||||
[JsonProperty("user-agent")]
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -137,6 +137,18 @@ namespace DownKyi.Core.Aria2cNet.Server
|
||||
public static async Task<bool> CloseServerAsync()
|
||||
{
|
||||
await AriaClient.ShutdownAsync();
|
||||
// 等待进程结束
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Server.WaitForExit(30000);
|
||||
try
|
||||
{
|
||||
Server.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -166,7 +178,18 @@ namespace DownKyi.Core.Aria2cNet.Server
|
||||
{
|
||||
var task = AriaClient.ShutdownAsync();
|
||||
if (task.Result != null && task.Result.Result != null && task.Result.Result == "OK")
|
||||
{ return true; }
|
||||
{
|
||||
// 等待进程结束
|
||||
Server.WaitForExit(30000);
|
||||
try
|
||||
{
|
||||
Server.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -208,39 +231,35 @@ namespace DownKyi.Core.Aria2cNet.Server
|
||||
|
||||
private static void ExcuteProcess(string exe, string arg, string workingDirectory, DataReceivedEventHandler output)
|
||||
{
|
||||
using (var p = new Process())
|
||||
var p = new Process();
|
||||
Server = p;
|
||||
|
||||
p.StartInfo.FileName = exe;
|
||||
p.StartInfo.Arguments = arg;
|
||||
|
||||
// 工作目录
|
||||
if (workingDirectory != null)
|
||||
{
|
||||
Server = p;
|
||||
|
||||
p.StartInfo.FileName = exe;
|
||||
p.StartInfo.Arguments = arg;
|
||||
|
||||
// 工作目录
|
||||
if (workingDirectory != null)
|
||||
{
|
||||
p.StartInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
// 输出信息重定向
|
||||
p.StartInfo.UseShellExecute = false;
|
||||
p.StartInfo.CreateNoWindow = true;
|
||||
p.StartInfo.RedirectStandardError = true;
|
||||
p.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
// 将 StandardErrorEncoding 改为 UTF-8 才不会出现中文乱码
|
||||
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
p.StartInfo.StandardErrorEncoding = Encoding.UTF8;
|
||||
|
||||
p.OutputDataReceived += output;
|
||||
p.ErrorDataReceived += output;
|
||||
|
||||
// 启动线程
|
||||
p.Start();
|
||||
p.BeginOutputReadLine();
|
||||
p.BeginErrorReadLine();
|
||||
// 等待进程结束
|
||||
p.WaitForExit();
|
||||
p.StartInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
// 输出信息重定向
|
||||
p.StartInfo.UseShellExecute = false;
|
||||
p.StartInfo.CreateNoWindow = true;
|
||||
p.StartInfo.RedirectStandardError = true;
|
||||
p.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
// 将 StandardErrorEncoding 改为 UTF-8 才不会出现中文乱码
|
||||
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
p.StartInfo.StandardErrorEncoding = Encoding.UTF8;
|
||||
|
||||
p.OutputDataReceived += output;
|
||||
p.ErrorDataReceived += output;
|
||||
|
||||
// 启动线程
|
||||
p.Start();
|
||||
p.BeginOutputReadLine();
|
||||
p.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,10 @@ namespace DownKyi.Core.BiliApi.BiliUtils
|
||||
/// <returns></returns>
|
||||
public static List<Quality> GetResolutions()
|
||||
{
|
||||
return resolutions;
|
||||
// 使用深复制,
|
||||
// 保证外部修改list后,
|
||||
// 不会影响其他调用处
|
||||
return new List<Quality>(resolutions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,7 +45,10 @@ namespace DownKyi.Core.BiliApi.BiliUtils
|
||||
/// <returns></returns>
|
||||
public static List<Quality> GetAudioQualities()
|
||||
{
|
||||
return qualities;
|
||||
// 使用深复制,
|
||||
// 保证外部修改list后,
|
||||
// 不会影响其他调用处
|
||||
return new List<Quality>(qualities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace DownKyi.Core.BiliApi.BiliUtils
|
||||
/// 解析输入的字符串<para/>
|
||||
/// 支持的格式有:<para/>
|
||||
/// av号:av170001, AV170001, https://www.bilibili.com/video/av170001 <para/>
|
||||
/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC <para/>
|
||||
/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC <para/>
|
||||
/// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 <para/>
|
||||
/// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 <para/>
|
||||
/// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 <para/>
|
||||
/// 课程ss号:https://www.bilibili.com/cheese/play/ss205 <para/>
|
||||
/// 课程ep号:https://www.bilibili.com/cheese/play/ep3489 <para/>
|
||||
/// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876 <para/>
|
||||
/// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/ <para/>
|
||||
/// 用户空间:uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123
|
||||
/// </summary>
|
||||
public static class ParseEntrance
|
||||
|
||||
@@ -17,14 +17,14 @@ namespace DownKyi.Core.FFmpeg
|
||||
/// <param name="destVideo"></param>
|
||||
public static bool MergeVideo(string video1, string video2, string destVideo)
|
||||
{
|
||||
string param = $"-i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
|
||||
string param = $"-y -i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
|
||||
if (video1 == null || !File.Exists(video1))
|
||||
{
|
||||
param = $"-i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
|
||||
param = $"-y -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
|
||||
}
|
||||
if (video2 == null || !File.Exists(video2))
|
||||
{
|
||||
param = $"-i \"{video1}\" -acodec copy -f aac \"{destVideo}\"";
|
||||
param = $"-y -i \"{video1}\" -acodec copy -f aac \"{destVideo}\"";
|
||||
}
|
||||
if (!File.Exists(video1) && !File.Exists(video2)) { return false; }
|
||||
|
||||
@@ -89,9 +89,9 @@ namespace DownKyi.Core.FFmpeg
|
||||
return false;
|
||||
}
|
||||
|
||||
// ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mkv
|
||||
// ffmpeg -y -f concat -safe 0 -i filelist.txt -c copy output.mkv
|
||||
// 加上-y,表示如果有同名文件,则默认覆盖
|
||||
string param = $"-f concat -safe 0 -i {concatFileName} -c copy \"{destVideo}\" -y";
|
||||
string param = $"-y -f concat -safe 0 -i {concatFileName} -c copy \"{destVideo}\" -y";
|
||||
ExcuteProcess("ffmpeg.exe", param, workingDirectory, (s, e) => Console.WriteLine(e.Data));
|
||||
|
||||
// 删除临时文件
|
||||
@@ -126,8 +126,8 @@ namespace DownKyi.Core.FFmpeg
|
||||
/// <param name="action"></param>
|
||||
public static void Delogo(string video, string destVideo, int x, int y, int width, int height, Action<string> action)
|
||||
{
|
||||
// ffmpeg -i "video.mp4" -vf delogo=x=1670:y=50:w=180:h=70:show=1 "delogo.mp4"
|
||||
string param = $"-i \"{video}\" -vf delogo=x={x}:y={y}:w={width}:h={height}:show=0 \"{destVideo}\" -hide_banner -y";
|
||||
// ffmpeg -y -i "video.mp4" -vf delogo=x=1670:y=50:w=180:h=70:show=1 "delogo.mp4"
|
||||
string param = $"-y -i \"{video}\" -vf delogo=x={x}:y={y}:w={width}:h={height}:show=0 \"{destVideo}\" -hide_banner";
|
||||
ExcuteProcess("ffmpeg.exe", param, null, (s, e) =>
|
||||
{
|
||||
Console.WriteLine(e.Data);
|
||||
|
||||
@@ -15,6 +15,15 @@ namespace DownKyi.Core.FileName
|
||||
private string videoQuality = "VIDEO_QUALITY";
|
||||
private string videoCodec = "VIDEO_CODEC";
|
||||
|
||||
private string videoPublishTime = "VIDEO_PUBLISH_TIME";
|
||||
|
||||
private long avid = -1;
|
||||
private string bvid = "BVID";
|
||||
private long cid = -1;
|
||||
|
||||
private long upMid = -1;
|
||||
private string upName = "UP_NAME";
|
||||
|
||||
private FileName(List<FileNamePart> nameParts)
|
||||
{
|
||||
this.nameParts = nameParts;
|
||||
@@ -73,6 +82,42 @@ namespace DownKyi.Core.FileName
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetVideoPublishTime(string videoPublishTime)
|
||||
{
|
||||
this.videoPublishTime = videoPublishTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetAvid(long avid)
|
||||
{
|
||||
this.avid = avid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetBvid(string bvid)
|
||||
{
|
||||
this.bvid = bvid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetCid(long cid)
|
||||
{
|
||||
this.cid = cid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetUpMid(long upMid)
|
||||
{
|
||||
this.upMid = upMid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileName SetUpName(string upName)
|
||||
{
|
||||
this.upName = upName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public string RelativePath()
|
||||
{
|
||||
string path = string.Empty;
|
||||
@@ -112,6 +157,24 @@ namespace DownKyi.Core.FileName
|
||||
case FileNamePart.VIDEO_CODEC:
|
||||
path += videoCodec;
|
||||
break;
|
||||
case FileNamePart.VIDEO_PUBLISH_TIME:
|
||||
path += videoPublishTime;
|
||||
break;
|
||||
case FileNamePart.AVID:
|
||||
path += avid;
|
||||
break;
|
||||
case FileNamePart.BVID:
|
||||
path += bvid;
|
||||
break;
|
||||
case FileNamePart.CID:
|
||||
path += cid;
|
||||
break;
|
||||
case FileNamePart.UP_MID:
|
||||
path += upMid;
|
||||
break;
|
||||
case FileNamePart.UP_NAME:
|
||||
path += upName;
|
||||
break;
|
||||
}
|
||||
|
||||
if (((int)part) >= 100)
|
||||
|
||||
@@ -12,6 +12,15 @@
|
||||
VIDEO_QUALITY,
|
||||
VIDEO_CODEC,
|
||||
|
||||
VIDEO_PUBLISH_TIME,
|
||||
|
||||
AVID,
|
||||
BVID,
|
||||
CID,
|
||||
|
||||
UP_MID,
|
||||
UP_NAME,
|
||||
|
||||
// 斜杠
|
||||
SLASH = 100,
|
||||
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
public VideoSettings Video { get; set; } = new VideoSettings();
|
||||
public DanmakuSettings Danmaku { get; set; } = new DanmakuSettings();
|
||||
public AboutSettings About { get; set; } = new AboutSettings();
|
||||
public UserInfoSettings UserInfo { get; set; }
|
||||
public UserInfoSettings UserInfo { get; set; } = new UserInfoSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,6 @@ namespace DownKyi.Core.Settings.Models
|
||||
public List<string> HistoryVideoRootPaths { get; set; } // 历史视频保存路径
|
||||
public AllowStatus IsUseSaveVideoRootPath { get; set; } // 是否使用默认视频保存路径
|
||||
public List<FileNamePart> FileNameParts { get; set; } // 文件命名格式
|
||||
public string FileNamePartTimeFormat { get; set; } // 文件命名中的时间格式
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace DownKyi.Core.Settings
|
||||
FileNamePart.VIDEO_CODEC,
|
||||
};
|
||||
|
||||
// 文件命名中的时间格式
|
||||
private readonly string fileNamePartTimeFormat = "yyyy-MM-dd";
|
||||
|
||||
/// <summary>
|
||||
/// 获取优先下载的视频编码
|
||||
/// </summary>
|
||||
@@ -260,5 +263,32 @@ namespace DownKyi.Core.Settings
|
||||
return SetSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件命名中的时间格式
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetFileNamePartTimeFormat()
|
||||
{
|
||||
appSettings = GetSettings();
|
||||
if (appSettings.Video.FileNamePartTimeFormat == null || appSettings.Video.FileNamePartTimeFormat == string.Empty)
|
||||
{
|
||||
// 第一次获取,先设置默认值
|
||||
SetFileNamePartTimeFormat(fileNamePartTimeFormat);
|
||||
return fileNamePartTimeFormat;
|
||||
}
|
||||
return appSettings.Video.FileNamePartTimeFormat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置文件命名中的时间格式
|
||||
/// </summary>
|
||||
/// <param name="fileNamePartTimeFormat"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetFileNamePartTimeFormat(string fileNamePartTimeFormat)
|
||||
{
|
||||
appSettings.Video.FileNamePartTimeFormat = fileNamePartTimeFormat;
|
||||
return SetSettings();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,16 +82,16 @@ namespace DownKyi.Core.Settings
|
||||
/// <returns></returns>
|
||||
private bool SetSettings()
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(appSettings);
|
||||
try
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(appSettings);
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
// 加密字符串
|
||||
json = Encryptor.EncryptString(json, password);
|
||||
// 加密字符串
|
||||
json = Encryptor.EncryptString(json, password);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(settingsName, json);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ namespace DownKyi.Core.Storage
|
||||
internal static class Constant
|
||||
{
|
||||
// 根目录
|
||||
private static string Root { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Downkyi";
|
||||
//private static string Root { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Downkyi";
|
||||
private static string Root { get; } = Environment.CurrentDirectory;
|
||||
|
||||
// Aria
|
||||
public static string Aria { get; } = $"{Root}/Aria";
|
||||
|
||||
@@ -7,9 +7,14 @@ namespace DownKyi.Core.Storage.Database
|
||||
public class CoverDb
|
||||
{
|
||||
private const string key = "b5018ecc-09d1-4da2-aa49-4625e41e623e";
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetCoverIndex(), key);
|
||||
private readonly string tableName = "cover";
|
||||
|
||||
#if DEBUG
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetCoverIndex().Replace(".db", "_debug.db"));
|
||||
#else
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetCoverIndex(), key);
|
||||
#endif
|
||||
|
||||
public CoverDb()
|
||||
{
|
||||
CreateTable();
|
||||
@@ -103,21 +108,30 @@ namespace DownKyi.Core.Storage.Database
|
||||
{
|
||||
List<Cover> covers = new List<Cover>();
|
||||
|
||||
dbHelper.ExecuteQuery(sql, reader =>
|
||||
try
|
||||
{
|
||||
while (reader.Read())
|
||||
dbHelper.ExecuteQuery(sql, reader =>
|
||||
{
|
||||
Cover cover = new Cover
|
||||
while (reader.Read())
|
||||
{
|
||||
Avid = (long)reader["avid"],
|
||||
Bvid = (string)reader["bvid"],
|
||||
Cid = (long)reader["cid"],
|
||||
Url = (string)reader["url"],
|
||||
Md5 = (string)reader["md5"]
|
||||
};
|
||||
covers.Add(cover);
|
||||
}
|
||||
});
|
||||
Cover cover = new Cover
|
||||
{
|
||||
Avid = (long)reader["avid"],
|
||||
Bvid = (string)reader["bvid"],
|
||||
Cid = (long)reader["cid"],
|
||||
Url = (string)reader["url"],
|
||||
Md5 = (string)reader["md5"]
|
||||
};
|
||||
covers.Add(cover);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("Query()发生异常: {0}", e);
|
||||
LogManager.Error($"{tableName}", e);
|
||||
}
|
||||
|
||||
return covers;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,37 @@
|
||||
using System;
|
||||
using DownKyi.Core.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
|
||||
namespace DownKyi.Core.Storage.Database
|
||||
{
|
||||
public class DbHelper
|
||||
{
|
||||
private readonly string connStr;
|
||||
private readonly SQLiteConnection conn;
|
||||
|
||||
private static readonly Dictionary<string, SQLiteConnection> database = new Dictionary<string, SQLiteConnection>();
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个数据库
|
||||
/// </summary>
|
||||
/// <param name="dbPath"></param>
|
||||
public DbHelper(string dbPath)
|
||||
{
|
||||
string connStr = $"Data Source={dbPath};Version=3;";
|
||||
connStr = $"Data Source={dbPath};Version=3;";
|
||||
|
||||
if (database.ContainsKey(connStr))
|
||||
{
|
||||
conn = database[connStr];
|
||||
|
||||
if (conn != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
conn = new SQLiteConnection(connStr);
|
||||
database.Add(connStr, conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -25,8 +42,20 @@ namespace DownKyi.Core.Storage.Database
|
||||
public DbHelper(string dbPath, string secretKey)
|
||||
{
|
||||
string connStr = $"Data Source={dbPath};Version=3;";
|
||||
|
||||
if (database.ContainsKey(connStr))
|
||||
{
|
||||
conn = database[connStr];
|
||||
|
||||
if (conn != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
conn = new SQLiteConnection(connStr);
|
||||
conn.SetPassword(secretKey);
|
||||
database.Add(connStr, conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,6 +86,8 @@ namespace DownKyi.Core.Storage.Database
|
||||
if (IsOpen())
|
||||
{
|
||||
conn.Close();
|
||||
|
||||
database.Remove(connStr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,21 +97,29 @@ namespace DownKyi.Core.Storage.Database
|
||||
/// <param name="sql"></param>
|
||||
public void ExecuteNonQuery(string sql, Action<SQLiteParameterCollection> action = null)
|
||||
{
|
||||
lock (conn)
|
||||
try
|
||||
{
|
||||
Open();
|
||||
using (var tr = conn.BeginTransaction())
|
||||
lock (conn)
|
||||
{
|
||||
using (var command = conn.CreateCommand())
|
||||
Open();
|
||||
using (var tr = conn.BeginTransaction())
|
||||
{
|
||||
command.CommandText = sql;
|
||||
// 添加参数
|
||||
action?.Invoke(command.Parameters);
|
||||
command.ExecuteNonQuery();
|
||||
using (var command = conn.CreateCommand())
|
||||
{
|
||||
command.CommandText = sql;
|
||||
// 添加参数
|
||||
action?.Invoke(command.Parameters);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
tr.Commit();
|
||||
}
|
||||
tr.Commit();
|
||||
}
|
||||
}
|
||||
catch (SQLiteException e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("DbHelper ExecuteNonQuery()发生异常: {0}", e);
|
||||
LogManager.Error("DbHelper ExecuteNonQuery()", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,16 +129,24 @@ namespace DownKyi.Core.Storage.Database
|
||||
/// <param name="action"></param>
|
||||
public void ExecuteQuery(string sql, Action<SQLiteDataReader> action)
|
||||
{
|
||||
lock (conn)
|
||||
try
|
||||
{
|
||||
Open();
|
||||
using (var command = conn.CreateCommand())
|
||||
lock (conn)
|
||||
{
|
||||
command.CommandText = sql;
|
||||
var reader = command.ExecuteReader();
|
||||
action(reader);
|
||||
Open();
|
||||
using (var command = conn.CreateCommand())
|
||||
{
|
||||
command.CommandText = sql;
|
||||
var reader = command.ExecuteReader();
|
||||
action(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLiteException e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("DbHelper ExecuteQuery()发生异常: {0}", e);
|
||||
LogManager.Error("DbHelper ExecuteQuery()", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace DownKyi.Core.Storage.Database.Download
|
||||
protected string tableName = "download";
|
||||
|
||||
#if DEBUG
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetDownload().Replace(".db","_debug.db"));
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetDownload().Replace(".db", "_debug.db"));
|
||||
#else
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetDownload(), key);
|
||||
#endif
|
||||
@@ -33,25 +33,25 @@ namespace DownKyi.Core.Storage.Database.Download
|
||||
/// <param name="obj"></param>
|
||||
public void Insert(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
|
||||
{
|
||||
// 定义一个流
|
||||
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();
|
||||
|
||||
string sql = $"insert into {tableName}(id, data) values (@id, @data)";
|
||||
dbHelper.ExecuteNonQuery(sql, new Action<SQLiteParameterCollection>((para) =>
|
||||
{
|
||||
@@ -86,25 +86,25 @@ namespace DownKyi.Core.Storage.Database.Download
|
||||
|
||||
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
|
||||
{
|
||||
// 定义一个流
|
||||
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();
|
||||
|
||||
string sql = $"update {tableName} set data=@data where id glob @id";
|
||||
dbHelper.ExecuteNonQuery(sql, new Action<SQLiteParameterCollection>((para) =>
|
||||
{
|
||||
@@ -164,22 +164,30 @@ namespace DownKyi.Core.Storage.Database.Download
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
// 读取字节数组
|
||||
byte[] array = (byte[])reader["data"];
|
||||
// 定义一个流
|
||||
MemoryStream stream = new MemoryStream(array);
|
||||
//定义一个格式化器
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
// 反序列化
|
||||
object obj = formatter.Deserialize(stream);
|
||||
try
|
||||
{
|
||||
// 读取字节数组
|
||||
byte[] array = (byte[])reader["data"];
|
||||
// 定义一个流
|
||||
MemoryStream stream = new MemoryStream(array);
|
||||
//定义一个格式化器
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
// 反序列化
|
||||
object obj = formatter.Deserialize(stream);
|
||||
|
||||
objects.Add((string)reader["id"], obj);
|
||||
objects.Add((string)reader["id"], obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("Query()发生异常: {0}", e);
|
||||
LogManager.Error($"{tableName}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 如果表不存在则创建表
|
||||
/// </summary>
|
||||
|
||||
@@ -7,9 +7,14 @@ namespace DownKyi.Core.Storage.Database
|
||||
public class HeaderDb
|
||||
{
|
||||
private const string key = "7c1f1f40-7cdf-4d11-ad28-f0137a3c5308";
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetHeaderIndex(), key);
|
||||
private readonly string tableName = "header";
|
||||
|
||||
#if DEBUG
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetHeaderIndex().Replace(".db", "_debug.db"));
|
||||
#else
|
||||
private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetHeaderIndex(), key);
|
||||
#endif
|
||||
|
||||
public HeaderDb()
|
||||
{
|
||||
CreateTable();
|
||||
@@ -90,20 +95,29 @@ namespace DownKyi.Core.Storage.Database
|
||||
{
|
||||
List<Header> headers = new List<Header>();
|
||||
|
||||
dbHelper.ExecuteQuery(sql, reader =>
|
||||
try
|
||||
{
|
||||
while (reader.Read())
|
||||
dbHelper.ExecuteQuery(sql, reader =>
|
||||
{
|
||||
Header header = new Header
|
||||
while (reader.Read())
|
||||
{
|
||||
Mid = (long)reader["mid"],
|
||||
Name = (string)reader["name"],
|
||||
Url = (string)reader["url"],
|
||||
Md5 = (string)reader["md5"]
|
||||
};
|
||||
headers.Add(header);
|
||||
}
|
||||
});
|
||||
Header header = new Header
|
||||
{
|
||||
Mid = (long)reader["mid"],
|
||||
Name = (string)reader["name"],
|
||||
Url = (string)reader["url"],
|
||||
Md5 = (string)reader["md5"]
|
||||
};
|
||||
headers.Add(header);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("Query()发生异常: {0}", e);
|
||||
LogManager.Error($"{tableName}", e);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace DownKyi.Core.Storage
|
||||
};
|
||||
coverDb.Update(newCover);
|
||||
|
||||
coverDb.Close();
|
||||
//coverDb.Close();
|
||||
return $"{StorageManager.GetCover()}/{cover.Md5}";
|
||||
}
|
||||
else
|
||||
@@ -108,12 +108,12 @@ namespace DownKyi.Core.Storage
|
||||
};
|
||||
coverDb.Update(newCover);
|
||||
|
||||
coverDb.Close();
|
||||
//coverDb.Close();
|
||||
return $"{StorageManager.GetCover()}/{md5}";
|
||||
}
|
||||
else
|
||||
{
|
||||
coverDb.Close();
|
||||
//coverDb.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -133,12 +133,12 @@ namespace DownKyi.Core.Storage
|
||||
};
|
||||
coverDb.Insert(newCover);
|
||||
|
||||
coverDb.Close();
|
||||
//coverDb.Close();
|
||||
return $"{StorageManager.GetCover()}/{md5}";
|
||||
}
|
||||
else
|
||||
{
|
||||
coverDb.Close();
|
||||
//coverDb.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -165,12 +165,14 @@ namespace DownKyi.Core.Storage
|
||||
{
|
||||
string destFile = $"{StorageManager.GetCover()}/{md5}";
|
||||
|
||||
// 如果不存在
|
||||
if (!File.Exists(destFile))
|
||||
try
|
||||
{
|
||||
// 移动到指定位置
|
||||
File.Move(localFile, destFile);
|
||||
File.Delete(destFile);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 移动到指定位置
|
||||
File.Move(localFile, destFile);
|
||||
|
||||
return md5;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace DownKyi.Core.Storage
|
||||
public BitmapImage GetHeaderThumbnail(long mid, string name, string url, int width, int height)
|
||||
{
|
||||
string header = GetHeader(mid, name, url);
|
||||
if(header == null) { return null; }
|
||||
if (header == null) { return null; }
|
||||
|
||||
return GetHeaderThumbnail(header, width, height);
|
||||
}
|
||||
@@ -42,6 +42,8 @@ namespace DownKyi.Core.Storage
|
||||
/// <returns></returns>
|
||||
public BitmapImage GetHeaderThumbnail(string header, int width, int height)
|
||||
{
|
||||
if (header == null) { return null; }
|
||||
|
||||
var bitmap = new Bitmap(header);
|
||||
var thumbnail = bitmap.GetThumbnailImage(width, height, null, IntPtr.Zero);
|
||||
|
||||
@@ -71,7 +73,7 @@ namespace DownKyi.Core.Storage
|
||||
Md5 = header.Md5
|
||||
};
|
||||
headerDb.Update(newHeader);
|
||||
headerDb.Close();
|
||||
//headerDb.Close();
|
||||
return $"{StorageManager.GetHeader()}/{header.Md5}";
|
||||
}
|
||||
else
|
||||
@@ -87,12 +89,12 @@ namespace DownKyi.Core.Storage
|
||||
Md5 = md5
|
||||
};
|
||||
headerDb.Insert(newHeader);
|
||||
headerDb.Close();
|
||||
//headerDb.Close();
|
||||
return $"{StorageManager.GetHeader()}/{md5}";
|
||||
}
|
||||
else
|
||||
{
|
||||
headerDb.Close();
|
||||
//headerDb.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -110,12 +112,12 @@ namespace DownKyi.Core.Storage
|
||||
Md5 = md5
|
||||
};
|
||||
headerDb.Insert(newHeader);
|
||||
headerDb.Close();
|
||||
//headerDb.Close();
|
||||
return $"{StorageManager.GetHeader()}/{md5}";
|
||||
}
|
||||
else
|
||||
{
|
||||
headerDb.Close();
|
||||
//headerDb.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -141,7 +143,16 @@ namespace DownKyi.Core.Storage
|
||||
|
||||
if (File.Exists(localFile))
|
||||
{
|
||||
File.Move(localFile, $"{StorageManager.GetHeader()}/{md5}");
|
||||
string destFile = $"{StorageManager.GetHeader()}/{md5}";
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(destFile);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 移动到指定位置
|
||||
File.Move(localFile, destFile);
|
||||
|
||||
return md5;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.IO;
|
||||
using DownKyi.Core.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DownKyi.Core.Utils
|
||||
{
|
||||
@@ -11,17 +13,26 @@ namespace DownKyi.Core.Utils
|
||||
/// <returns></returns>
|
||||
public static long GetHardDiskSpace(string hardDiskName)
|
||||
{
|
||||
long totalSize = new long();
|
||||
hardDiskName = $"{hardDiskName}:\\";
|
||||
DriveInfo[] drives = DriveInfo.GetDrives();
|
||||
long totalSize = 0;
|
||||
|
||||
foreach (DriveInfo drive in drives)
|
||||
try
|
||||
{
|
||||
if (drive.Name == hardDiskName)
|
||||
hardDiskName = $"{hardDiskName}:\\";
|
||||
DriveInfo[] drives = DriveInfo.GetDrives();
|
||||
|
||||
foreach (DriveInfo drive in drives)
|
||||
{
|
||||
totalSize = drive.TotalSize;
|
||||
if (drive.Name == hardDiskName)
|
||||
{
|
||||
totalSize = drive.TotalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debugging.Console.PrintLine("GetHardDiskSpace()发生异常: {0}", e);
|
||||
LogManager.Error("HardDisk", e);
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
@@ -33,17 +44,25 @@ namespace DownKyi.Core.Utils
|
||||
/// <returns></returns>
|
||||
public static long GetHardDiskFreeSpace(string hardDiskName)
|
||||
{
|
||||
long freeSpace = new long();
|
||||
hardDiskName = $"{hardDiskName}:\\";
|
||||
DriveInfo[] drives = DriveInfo.GetDrives();
|
||||
|
||||
foreach (DriveInfo drive in drives)
|
||||
long freeSpace = 0;
|
||||
try
|
||||
{
|
||||
if (drive.Name == hardDiskName)
|
||||
hardDiskName = $"{hardDiskName}:\\";
|
||||
DriveInfo[] drives = DriveInfo.GetDrives();
|
||||
|
||||
foreach (DriveInfo drive in drives)
|
||||
{
|
||||
freeSpace = drive.TotalFreeSpace;
|
||||
if (drive.Name == hardDiskName)
|
||||
{
|
||||
freeSpace = drive.TotalFreeSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debugging.Console.PrintLine("GetHardDiskFreeSpace()发生异常: {0}", e);
|
||||
LogManager.Error("HardDisk", e);
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace DownKyi.Core.Utils
|
||||
|
||||
string machineCodeString = "PC." +
|
||||
machineCode.GetMainBordId() + "." +
|
||||
machineCode.GetCpuInfo() + "." +
|
||||
machineCode.GetDiskID();// + "." +
|
||||
machineCode.GetCpuInfo();// + "." +
|
||||
//machineCode.GetDiskID();// + "." +
|
||||
//machineCode.GetMoAddress();
|
||||
return machineCodeString.Replace(" ", "");
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
<Compile Include="Services\Download\AddToDownloadService.cs" />
|
||||
<Compile Include="Services\Download\DownloadStorageService.cs" />
|
||||
<Compile Include="Services\SearchService.cs" />
|
||||
<Compile Include="Utils\WindowAdaptation.cs" />
|
||||
<Compile Include="ViewModels\PageViewModels\BangumiFollowMedia.cs" />
|
||||
<Compile Include="ViewModels\PageViewModels\Favorites.cs" />
|
||||
<Compile Include="ViewModels\PageViewModels\FavoritesMedia.cs" />
|
||||
|
||||
@@ -214,8 +214,12 @@
|
||||
<system:String x:Key="DisplayAudioQuality">音质</system:String>
|
||||
<system:String x:Key="DisplayVideoQuality">画质</system:String>
|
||||
<system:String x:Key="DisplayVideoCodec">视频编码</system:String>
|
||||
<system:String x:Key="DisplayVideoPublishTime">视频发布时间</system:String>
|
||||
<system:String x:Key="DisplaySpace">空格</system:String>
|
||||
<system:String x:Key="DisplayUpMid">UP主ID</system:String>
|
||||
<system:String x:Key="DisplayUpName">UP主昵称</system:String>
|
||||
<system:String x:Key="Reset">恢复默认</system:String>
|
||||
<system:String x:Key="FileNameTimeFormat">时间格式:</system:String>
|
||||
|
||||
<system:String x:Key="SettingDanmaku">弹幕</system:String>
|
||||
<system:String x:Key="FilterType">按类型屏蔽</system:String>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
public class AppInfo
|
||||
{
|
||||
public string Name { get; } = "哔哩下载姬";
|
||||
public int VersionCode { get; } = 500;
|
||||
public int VersionCode { get; } = 505;
|
||||
|
||||
#if DEBUG
|
||||
public string VersionName { get; } = "1.5.0-alpha1 Debug";
|
||||
public string VersionName { get; } = "1.5.0-alpha6 Debug";
|
||||
#else
|
||||
public string VersionName { get; } = "1.5.0-alpha1";
|
||||
public string VersionName { get; } = "1.5.0-alpha6";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace DownKyi.Models
|
||||
{
|
||||
// 初始化下载的文件列表
|
||||
DownloadFiles = new Dictionary<string, string>();
|
||||
DownloadedFiles = new List<string>();
|
||||
}
|
||||
|
||||
// Aria相关
|
||||
@@ -19,6 +20,9 @@ namespace DownKyi.Models
|
||||
// 下载的文件
|
||||
public Dictionary<string, string> DownloadFiles { get; set; }
|
||||
|
||||
// 已下载的文件
|
||||
public List<string> DownloadedFiles { get; set; }
|
||||
|
||||
// 视频类别
|
||||
public PlayStreamType PlayStreamType { get; set; }
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using DownKyi.Core.BiliApi.Bangumi.Models;
|
||||
using DownKyi.Core.BiliApi.BiliUtils;
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using DownKyi.Core.BiliApi.VideoStream.Models;
|
||||
using DownKyi.Core.Settings;
|
||||
using DownKyi.Core.Storage;
|
||||
using DownKyi.Core.Utils;
|
||||
using DownKyi.Utils;
|
||||
@@ -99,6 +100,34 @@ namespace DownKyi.Services
|
||||
Name = name,
|
||||
Duration = "N/A"
|
||||
};
|
||||
|
||||
// UP主信息
|
||||
if (bangumiSeason.UpInfo != null)
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = bangumiSeason.UpInfo.Name,
|
||||
Face = bangumiSeason.UpInfo.Avatar,
|
||||
Mid = bangumiSeason.UpInfo.Mid,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = "",
|
||||
Face = "",
|
||||
Mid = -1,
|
||||
};
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
// 视频发布时间
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
|
||||
DateTime dateTime = startTime.AddSeconds(episode.PubTime);
|
||||
page.PublishTime = dateTime.ToString(timeFormat);
|
||||
|
||||
pages.Add(page);
|
||||
}
|
||||
|
||||
@@ -147,6 +176,34 @@ namespace DownKyi.Services
|
||||
Name = name,
|
||||
Duration = "N/A"
|
||||
};
|
||||
|
||||
// UP主信息
|
||||
if (bangumiSeason.UpInfo != null)
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = bangumiSeason.UpInfo.Name,
|
||||
Face = bangumiSeason.UpInfo.Avatar,
|
||||
Mid = bangumiSeason.UpInfo.Mid,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = "",
|
||||
Face = "",
|
||||
Mid = -1,
|
||||
};
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
// 视频发布时间
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
|
||||
DateTime dateTime = startTime.AddSeconds(episode.PubTime);
|
||||
page.PublishTime = dateTime.ToString(timeFormat);
|
||||
|
||||
pages.Add(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using DownKyi.Core.BiliApi.Cheese;
|
||||
using DownKyi.Core.BiliApi.Cheese.Models;
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using DownKyi.Core.BiliApi.VideoStream.Models;
|
||||
using DownKyi.Core.Settings;
|
||||
using DownKyi.Core.Storage;
|
||||
using DownKyi.Core.Utils;
|
||||
using DownKyi.Utils;
|
||||
@@ -67,6 +68,34 @@ namespace DownKyi.Services
|
||||
Name = name,
|
||||
Duration = "N/A"
|
||||
};
|
||||
|
||||
// UP主信息
|
||||
if (cheeseView.UpInfo != null)
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = cheeseView.UpInfo.Name,
|
||||
Face = cheeseView.UpInfo.Avatar,
|
||||
Mid = cheeseView.UpInfo.Mid,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = "",
|
||||
Face = "",
|
||||
Mid = -1,
|
||||
};
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
// 视频发布时间
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
|
||||
DateTime dateTime = startTime.AddSeconds(episode.ReleaseDate);
|
||||
page.PublishTime = dateTime.ToString(timeFormat);
|
||||
|
||||
pages.Add(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace DownKyi.Services.Download
|
||||
// 下载设置dialog中如果点击取消或者关闭窗口,
|
||||
// 会返回空字符串,
|
||||
// 这时直接退出
|
||||
if (directory == string.Empty) { return null; }
|
||||
if (directory == null || directory == string.Empty) { return null; }
|
||||
|
||||
// 文件夹不存在则创建
|
||||
if (!Directory.Exists(directory))
|
||||
@@ -207,6 +207,8 @@ namespace DownKyi.Services.Download
|
||||
// 添加到下载
|
||||
foreach (VideoSection section in videoSections)
|
||||
{
|
||||
if (section.VideoPages == null) { continue; }
|
||||
|
||||
foreach (VideoPage page in section.VideoPages)
|
||||
{
|
||||
// 只下载选中项,跳过未选中项
|
||||
@@ -294,7 +296,13 @@ namespace DownKyi.Services.Download
|
||||
.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" : "");
|
||||
.SetVideoCodec(page.VideoQuality == null ? "" : page.VideoQuality.SelectedVideoCodec.Contains("AVC") ? "AVC" : page.VideoQuality.SelectedVideoCodec.Contains("HEVC") ? "HEVC" : page.VideoQuality.SelectedVideoCodec.Contains("Dolby") ? "Dolby Vision" : "")
|
||||
.SetVideoPublishTime(page.PublishTime)
|
||||
.SetAvid(page.Avid)
|
||||
.SetBvid(page.Bvid)
|
||||
.SetCid(page.Cid)
|
||||
.SetUpMid(page.Owner.Mid)
|
||||
.SetUpName(Format.FormatFileName(page.Owner.Name));
|
||||
string filePath = Path.Combine(directory, fileName.RelativePath());
|
||||
|
||||
// 视频类别
|
||||
@@ -332,49 +340,49 @@ namespace DownKyi.Services.Download
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果不存在,直接添加到下载列表
|
||||
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.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);
|
||||
}));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DownKyi.Core.Aria2cNet;
|
||||
using DownKyi.Core.Aria2cNet;
|
||||
using DownKyi.Core.Aria2cNet.Client;
|
||||
using DownKyi.Core.Aria2cNet.Client.Entity;
|
||||
using DownKyi.Core.Aria2cNet.Server;
|
||||
@@ -30,10 +30,13 @@ namespace DownKyi.Services.Download
|
||||
/// </summary>
|
||||
public class AriaDownloadService : DownloadService, IDownloadService
|
||||
{
|
||||
private Task workTask;
|
||||
private CancellationTokenSource tokenSource;
|
||||
private CancellationToken cancellationToken;
|
||||
private List<Task> downloadingTasks = new List<Task>();
|
||||
|
||||
private int retry = 5;
|
||||
private string nullMark = "<null>";
|
||||
private readonly int retry = 5;
|
||||
private readonly string nullMark = "<null>";
|
||||
|
||||
public AriaDownloadService(ObservableCollection<DownloadingItem> downloadingList, ObservableCollection<DownloadedItem> downloadedList) : base(downloadingList, downloadedList)
|
||||
{
|
||||
@@ -135,17 +138,31 @@ namespace DownKyi.Services.Download
|
||||
|
||||
// 路径
|
||||
string[] temp = downloading.DownloadBase.FilePath.Split('/');
|
||||
string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], "");
|
||||
//string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], "");
|
||||
string path = downloading.DownloadBase.FilePath.TrimEnd(temp[temp.Length - 1].ToCharArray());
|
||||
|
||||
// 下载文件名
|
||||
string fileName = Guid.NewGuid().ToString("N");
|
||||
|
||||
string key = $"{downloadVideo.Id}_{downloadVideo.Codecs}";
|
||||
|
||||
// 老版本数据库没有这一项,会变成null
|
||||
if (downloading.Downloading.DownloadedFiles == null)
|
||||
{
|
||||
downloading.Downloading.DownloadedFiles = new List<string>();
|
||||
}
|
||||
|
||||
if (downloading.Downloading.DownloadFiles.ContainsKey(key))
|
||||
{
|
||||
// 如果存在,表示下载过,
|
||||
// 则继续使用上次下载的文件名
|
||||
fileName = downloading.Downloading.DownloadFiles[key];
|
||||
|
||||
// 还要检查一下文件有没有被人删掉,删掉的话重新下载
|
||||
// 如果下载视频之后音频文件被人删了。此时gid还是视频的,会下错文件
|
||||
if (downloading.Downloading.DownloadedFiles.Contains(key) && File.Exists(Path.Combine(path, fileName)))
|
||||
{
|
||||
return Path.Combine(path, fileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,6 +172,9 @@ namespace DownKyi.Services.Download
|
||||
downloading.Downloading.DownloadFiles.Add(key, fileName);
|
||||
}
|
||||
catch (ArgumentException) { }
|
||||
// Gid最好能是每个文件单独存储,现在复用有可能会混
|
||||
// 不过好消息是下载是按固定顺序的,而且下载了两个音频会混流不过
|
||||
downloading.Downloading.Gid = null;
|
||||
}
|
||||
|
||||
// 开始下载
|
||||
@@ -162,6 +182,8 @@ namespace DownKyi.Services.Download
|
||||
switch (downloadStatus)
|
||||
{
|
||||
case DownloadResult.SUCCESS:
|
||||
downloading.Downloading.DownloadedFiles.Add(key);
|
||||
downloading.Downloading.Gid = null;
|
||||
return Path.Combine(path, fileName);
|
||||
case DownloadResult.FAILED:
|
||||
case DownloadResult.ABORT:
|
||||
@@ -410,10 +432,17 @@ namespace DownKyi.Services.Download
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止下载服务
|
||||
/// 停止下载服务(转换await和Task.Wait两种调用形式)
|
||||
/// </summary>
|
||||
public void End()
|
||||
private async Task EndTask()
|
||||
{
|
||||
// 结束任务
|
||||
tokenSource.Cancel();
|
||||
|
||||
await workTask;
|
||||
|
||||
//先简单等待一下
|
||||
|
||||
// 下载数据存储服务
|
||||
DownloadStorageService downloadStorageService = new DownloadStorageService();
|
||||
// 保存数据
|
||||
@@ -432,7 +461,7 @@ namespace DownKyi.Services.Download
|
||||
case DownloadStatus.DOWNLOADING:
|
||||
// TODO 添加设置让用户选择重启后是否自动开始下载
|
||||
item.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD;
|
||||
item.Downloading.DownloadStatus = DownloadStatus.PAUSE;
|
||||
//item.Downloading.DownloadStatus = DownloadStatus.PAUSE;
|
||||
break;
|
||||
case DownloadStatus.DOWNLOAD_SUCCEED:
|
||||
case DownloadStatus.DOWNLOAD_FAILED:
|
||||
@@ -451,29 +480,35 @@ namespace DownKyi.Services.Download
|
||||
}
|
||||
|
||||
// 关闭Aria服务器
|
||||
CloseAriaServer();
|
||||
await CloseAriaServer();
|
||||
}
|
||||
|
||||
// 结束任务
|
||||
tokenSource.Cancel();
|
||||
/// <summary>
|
||||
/// 停止下载服务
|
||||
/// </summary>
|
||||
public void End()
|
||||
{
|
||||
Task.Run(EndTask).Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动下载服务
|
||||
/// </summary>
|
||||
public async void Start()
|
||||
public void Start()
|
||||
{
|
||||
// 启动Aria服务器
|
||||
StartAriaServer();
|
||||
|
||||
await Task.Run(DoWork, (tokenSource = new CancellationTokenSource()).Token);
|
||||
tokenSource = new CancellationTokenSource();
|
||||
cancellationToken = tokenSource.Token;
|
||||
workTask = Task.Run(DoWork);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行任务
|
||||
/// </summary>
|
||||
private void DoWork()
|
||||
private async Task DoWork()
|
||||
{
|
||||
CancellationToken cancellationToken = tokenSource.Token;
|
||||
while (true)
|
||||
{
|
||||
int maxDownloading = SettingsManager.GetInstance().GetAriaMaxConcurrentDownloads();
|
||||
@@ -481,6 +516,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
try
|
||||
{
|
||||
downloadingTasks.RemoveAll((m) => m.IsCompleted);
|
||||
foreach (DownloadingItem downloading in downloadingList)
|
||||
{
|
||||
if (downloading.Downloading.DownloadStatus == DownloadStatus.DOWNLOADING)
|
||||
@@ -499,7 +535,9 @@ namespace DownKyi.Services.Download
|
||||
// 开始下载
|
||||
if (downloading.Downloading.DownloadStatus == DownloadStatus.NOT_STARTED || downloading.Downloading.DownloadStatus == DownloadStatus.WAIT_FOR_DOWNLOAD)
|
||||
{
|
||||
SingleDownload(downloading);
|
||||
//这里需要立刻设置状态,否则如果SingleDownload没有及时执行,会重复创建任务
|
||||
downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING;
|
||||
downloadingTasks.Add(SingleDownload(downloading));
|
||||
downloadingCount++;
|
||||
}
|
||||
}
|
||||
@@ -524,7 +562,14 @@ namespace DownKyi.Services.Download
|
||||
}
|
||||
|
||||
// 降低CPU占用
|
||||
Thread.Sleep(500);
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
await Task.WhenAny(Task.WhenAll(downloadingTasks), Task.Delay(30000));
|
||||
foreach (Task tsk in downloadingTasks.FindAll((m) => !m.IsCompleted))
|
||||
{
|
||||
Core.Utils.Debugging.Console.PrintLine("AriaDownloadService: 任务结束超时");
|
||||
LogManager.Debug(Tag, "任务结束超时");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,267 +578,234 @@ namespace DownKyi.Services.Download
|
||||
/// </summary>
|
||||
/// <param name="downloading"></param>
|
||||
/// <returns></returns>
|
||||
private async void SingleDownload(DownloadingItem downloading)
|
||||
private async Task SingleDownload(DownloadingItem downloading)
|
||||
{
|
||||
// 路径
|
||||
string[] temp = downloading.DownloadBase.FilePath.Split('/');
|
||||
string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], "");
|
||||
//string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], "");
|
||||
string path = downloading.DownloadBase.FilePath.TrimEnd(temp[temp.Length - 1].ToCharArray());
|
||||
|
||||
// 路径不存在则创建
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
await Task.Run(new Action(() =>
|
||||
try
|
||||
{
|
||||
// 初始化
|
||||
downloading.DownloadStatusTitle = string.Empty;
|
||||
downloading.DownloadContent = string.Empty;
|
||||
//downloading.Downloading.DownloadFiles.Clear();
|
||||
|
||||
// 解析并依次下载音频、视频、弹幕、字幕、封面等内容
|
||||
Parse(downloading);
|
||||
|
||||
// 设置下载状态
|
||||
// 必须在解析之后设置为DOWNLOADING
|
||||
downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING;
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
var isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
await Task.Run(new Action(() =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 初始化
|
||||
downloading.DownloadStatusTitle = string.Empty;
|
||||
downloading.DownloadContent = string.Empty;
|
||||
//downloading.Downloading.DownloadFiles.Clear();
|
||||
|
||||
string audioUid = null;
|
||||
// 如果需要下载音频
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"])
|
||||
{
|
||||
//audioUid = DownloadAudio(downloading);
|
||||
for (int i = 0; i < retry; i++)
|
||||
// 解析并依次下载音频、视频、弹幕、字幕、封面等内容
|
||||
Parse(downloading);
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
string audioUid = null;
|
||||
// 如果需要下载音频
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"])
|
||||
{
|
||||
audioUid = DownloadAudio(downloading);
|
||||
if (audioUid != null && audioUid != "<null>")
|
||||
//audioUid = DownloadAudio(downloading);
|
||||
for (int i = 0; i < retry; i++)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (audioUid == "<null>")
|
||||
{
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string videoUid = null;
|
||||
// 如果需要下载视频
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
//videoUid = DownloadVideo(downloading);
|
||||
for (int i = 0; i < retry; i++)
|
||||
{
|
||||
videoUid = DownloadVideo(downloading);
|
||||
if (videoUid != null && videoUid != "<null>")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (videoUid == "<null>")
|
||||
{
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string outputDanmaku = null;
|
||||
// 如果需要下载弹幕
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"])
|
||||
{
|
||||
outputDanmaku = DownloadDanmaku(downloading);
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> outputSubtitles = null;
|
||||
// 如果需要下载字幕
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"])
|
||||
{
|
||||
outputSubtitles = DownloadSubtitle(downloading);
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string outputCover = null;
|
||||
string outputPageCover = null;
|
||||
// 如果需要下载封面
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadCover"])
|
||||
{
|
||||
string fileName = $"{downloading.DownloadBase.FilePath}.{GetImageExtension(downloading.DownloadBase.PageCoverUrl)}";
|
||||
|
||||
// page的封面
|
||||
outputPageCover = DownloadCover(downloading, downloading.DownloadBase.PageCoverUrl, fileName);
|
||||
// 封面
|
||||
outputCover = DownloadCover(downloading, downloading.DownloadBase.CoverUrl, $"{path}/Cover.{GetImageExtension(downloading.DownloadBase.CoverUrl)}");
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 混流
|
||||
string outputMedia = string.Empty;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
outputMedia = MixedFlow(downloading, audioUid, videoUid);
|
||||
}
|
||||
|
||||
// 暂停
|
||||
//Pause(downloading);
|
||||
// 是否存在
|
||||
isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 检测音频、视频是否下载成功
|
||||
bool isMediaSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
// 只有下载音频不下载视频时才输出aac
|
||||
// 只要下载视频就输出mp4
|
||||
if (File.Exists(outputMedia))
|
||||
{
|
||||
// 成功
|
||||
isMediaSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMediaSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测弹幕是否下载成功
|
||||
bool isDanmakuSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"])
|
||||
{
|
||||
if (File.Exists(outputDanmaku))
|
||||
{
|
||||
// 成功
|
||||
isDanmakuSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isDanmakuSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测字幕是否下载成功
|
||||
bool isSubtitleSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"])
|
||||
{
|
||||
if (outputSubtitles == null)
|
||||
{
|
||||
// 为null时表示不存在字幕
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string subtitle in outputSubtitles)
|
||||
{
|
||||
if (!File.Exists(subtitle))
|
||||
audioUid = DownloadAudio(downloading);
|
||||
if (audioUid != null && audioUid != nullMark)
|
||||
{
|
||||
// 如果有一个不存在则失败
|
||||
isSubtitleSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测封面是否下载成功
|
||||
bool isCover = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadCover"])
|
||||
{
|
||||
if (File.Exists(outputCover) || File.Exists(outputPageCover))
|
||||
if (audioUid == nullMark)
|
||||
{
|
||||
// 成功
|
||||
isCover = true;
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
string videoUid = null;
|
||||
// 如果需要下载视频
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
isCover = false;
|
||||
//videoUid = DownloadVideo(downloading);
|
||||
for (int i = 0; i < retry; i++)
|
||||
{
|
||||
videoUid = DownloadVideo(downloading);
|
||||
if (videoUid != null && videoUid != nullMark)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (videoUid == nullMark)
|
||||
{
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMediaSuccess || !isDanmakuSuccess || !isSubtitleSuccess || !isCover)
|
||||
{
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
// 下载完成后处理
|
||||
Downloaded downloaded = new Downloaded
|
||||
{
|
||||
MaxSpeedDisplay = Format.FormatSpeed(downloading.Downloading.MaxSpeed),
|
||||
};
|
||||
// 设置完成时间
|
||||
downloaded.SetFinishedTimestamp(new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds());
|
||||
string outputDanmaku = null;
|
||||
// 如果需要下载弹幕
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"])
|
||||
{
|
||||
outputDanmaku = DownloadDanmaku(downloading);
|
||||
}
|
||||
|
||||
DownloadedItem downloadedItem = new DownloadedItem
|
||||
{
|
||||
DownloadBase = downloading.DownloadBase,
|
||||
Downloaded = downloaded
|
||||
};
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
App.PropertyChangeAsync(new Action(() =>
|
||||
{
|
||||
// 加入到下载完成list中,并从下载中list去除
|
||||
downloadedList.Add(downloadedItem);
|
||||
downloadingList.Remove(downloading);
|
||||
List<string> outputSubtitles = null;
|
||||
// 如果需要下载字幕
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"])
|
||||
{
|
||||
outputSubtitles = DownloadSubtitle(downloading);
|
||||
}
|
||||
|
||||
// 下载完成列表排序
|
||||
DownloadFinishedSort finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort();
|
||||
App.SortDownloadedList(finishedSort);
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
string outputCover = null;
|
||||
string outputPageCover = null;
|
||||
// 如果需要下载封面
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadCover"])
|
||||
{
|
||||
string fileName = $"{downloading.DownloadBase.FilePath}.{GetImageExtension(downloading.DownloadBase.PageCoverUrl)}";
|
||||
|
||||
// page的封面
|
||||
outputPageCover = DownloadCover(downloading, downloading.DownloadBase.PageCoverUrl, fileName);
|
||||
// 封面
|
||||
outputCover = DownloadCover(downloading, downloading.DownloadBase.CoverUrl, $"{path}/Cover.{GetImageExtension(downloading.DownloadBase.CoverUrl)}");
|
||||
}
|
||||
|
||||
// 暂停
|
||||
Pause(downloading);
|
||||
|
||||
// 混流
|
||||
string outputMedia = string.Empty;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
outputMedia = MixedFlow(downloading, audioUid, videoUid);
|
||||
}
|
||||
|
||||
// 这里本来只有IsExist,没有pause,不知道怎么处理
|
||||
// 是否存在
|
||||
//isExist = IsExist(downloading);
|
||||
//if (!isExist.Result)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// 检测音频、视频是否下载成功
|
||||
bool isMediaSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || downloading.DownloadBase.NeedDownloadContent["downloadVideo"])
|
||||
{
|
||||
// 只有下载音频不下载视频时才输出aac
|
||||
// 只要下载视频就输出mp4
|
||||
if (File.Exists(outputMedia))
|
||||
{
|
||||
// 成功
|
||||
isMediaSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMediaSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测弹幕是否下载成功
|
||||
bool isDanmakuSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"])
|
||||
{
|
||||
if (File.Exists(outputDanmaku))
|
||||
{
|
||||
// 成功
|
||||
isDanmakuSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isDanmakuSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测字幕是否下载成功
|
||||
bool isSubtitleSuccess = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"])
|
||||
{
|
||||
if (outputSubtitles == null)
|
||||
{
|
||||
// 为null时表示不存在字幕
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string subtitle in outputSubtitles)
|
||||
{
|
||||
if (!File.Exists(subtitle))
|
||||
{
|
||||
// 如果有一个不存在则失败
|
||||
isSubtitleSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测封面是否下载成功
|
||||
bool isCover = true;
|
||||
if (downloading.DownloadBase.NeedDownloadContent["downloadCover"])
|
||||
{
|
||||
if (File.Exists(outputCover) || File.Exists(outputPageCover))
|
||||
{
|
||||
// 成功
|
||||
isCover = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCover = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMediaSuccess || !isDanmakuSuccess || !isSubtitleSuccess || !isCover)
|
||||
{
|
||||
DownloadFailed(downloading);
|
||||
return;
|
||||
}
|
||||
|
||||
// 下载完成后处理
|
||||
Downloaded downloaded = new Downloaded
|
||||
{
|
||||
MaxSpeedDisplay = Format.FormatSpeed(downloading.Downloading.MaxSpeed),
|
||||
};
|
||||
// 设置完成时间
|
||||
downloaded.SetFinishedTimestamp(new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds());
|
||||
|
||||
DownloadedItem downloadedItem = new DownloadedItem
|
||||
{
|
||||
DownloadBase = downloading.DownloadBase,
|
||||
Downloaded = downloaded
|
||||
};
|
||||
|
||||
App.PropertyChangeAsync(new Action(() =>
|
||||
{
|
||||
// 加入到下载完成list中,并从下载中list去除
|
||||
downloadedList.Add(downloadedItem);
|
||||
downloadingList.Remove(downloading);
|
||||
|
||||
// 下载完成列表排序
|
||||
DownloadFinishedSort finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort();
|
||||
App.SortDownloadedList(finishedSort);
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -836,33 +848,19 @@ namespace DownKyi.Services.Download
|
||||
/// <param name="downloading"></param>
|
||||
private void Pause(DownloadingItem downloading)
|
||||
{
|
||||
string oldStatus = downloading.DownloadStatusTitle;
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing");
|
||||
while (downloading.Downloading.DownloadStatus == DownloadStatus.PAUSE)
|
||||
if (downloading.Downloading.DownloadStatus == DownloadStatus.PAUSE)
|
||||
{
|
||||
// 降低CPU占用
|
||||
Thread.Sleep(100);
|
||||
throw new OperationCanceledException("Stop thread by pause");
|
||||
}
|
||||
downloading.DownloadStatusTitle = DictionaryResource.GetString("Waiting");
|
||||
|
||||
int maxDownloading = SettingsManager.GetInstance().GetAriaMaxConcurrentDownloads();
|
||||
int downloadingCount;
|
||||
do
|
||||
// 是否存在
|
||||
var isExist = IsExist(downloading);
|
||||
if (!isExist.Result)
|
||||
{
|
||||
downloadingCount = 0;
|
||||
foreach (DownloadingItem item in downloadingList)
|
||||
{
|
||||
if (item.Downloading.DownloadStatus == DownloadStatus.DOWNLOADING)
|
||||
{
|
||||
downloadingCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 降低CPU占用
|
||||
Thread.Sleep(100);
|
||||
} while (downloadingCount > maxDownloading);
|
||||
|
||||
downloading.DownloadStatusTitle = oldStatus;
|
||||
throw new OperationCanceledException("Task is deleted");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -926,26 +924,28 @@ namespace DownKyi.Services.Download
|
||||
};
|
||||
var task = await AriaServer.StartServerAsync(config);
|
||||
if (task) { Console.WriteLine("Start ServerAsync Completed"); }
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var globOpt = await AriaClient.GetGlobalOptionAsync();
|
||||
if (globOpt != null)
|
||||
break;
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
Console.WriteLine("Start ServerAsync end");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭Aria服务器
|
||||
/// </summary>
|
||||
private void CloseAriaServer()
|
||||
private async Task CloseAriaServer()
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
// 暂停所有下载
|
||||
var ariaPause = AriaClient.PauseAllAsync();
|
||||
Core.Utils.Debugging.Console.PrintLine(ariaPause.ToString());
|
||||
// 暂停所有下载
|
||||
var ariaPause = await AriaClient.PauseAllAsync();
|
||||
Core.Utils.Debugging.Console.PrintLine(ariaPause.ToString());
|
||||
|
||||
// 关闭服务器
|
||||
bool close = AriaServer.CloseServer();
|
||||
Core.Utils.Debugging.Console.PrintLine(close);
|
||||
})
|
||||
{ IsBackground = false }
|
||||
.Start();
|
||||
// 关闭服务器
|
||||
bool close = AriaServer.CloseServer();
|
||||
Core.Utils.Debugging.Console.PrintLine(close);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -958,39 +958,65 @@ namespace DownKyi.Services.Download
|
||||
// path已斜杠结尾,去掉斜杠
|
||||
path = path.TrimEnd('/').TrimEnd('\\');
|
||||
|
||||
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()
|
||||
};
|
||||
//检查gid对应任务,如果已创建那么直接使用
|
||||
//但是代理设置会出现不能随时更新的问题
|
||||
|
||||
// 如果设置了代理,则增加HttpProxy
|
||||
if (SettingsManager.GetInstance().IsAriaHttpProxy() == AllowStatus.YES)
|
||||
if (downloading.Downloading.Gid != null)
|
||||
{
|
||||
option.HttpProxy = $"http://{SettingsManager.GetInstance().GetAriaHttpProxy()}:{SettingsManager.GetInstance().GetAriaHttpProxyListenPort()}";
|
||||
Task<AriaTellStatus> status = AriaClient.TellStatus(downloading.Downloading.Gid);
|
||||
if (status == null || status.Result == null)
|
||||
downloading.Downloading.Gid = null;
|
||||
else if (status.Result.Result == null && status.Result.Error != null)
|
||||
{
|
||||
if (status.Result.Error.Message.Contains("is not found"))
|
||||
{
|
||||
downloading.Downloading.Gid = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 添加一个下载
|
||||
Task<AriaAddUri> ariaAddUri = AriaClient.AddUriAsync(urls, option);
|
||||
if (ariaAddUri == null || ariaAddUri.Result == null || ariaAddUri.Result.Result == null)
|
||||
if (downloading.Downloading.Gid == null)
|
||||
{
|
||||
return DownloadResult.FAILED;
|
||||
}
|
||||
AriaSendOption option = new AriaSendOption
|
||||
{
|
||||
//HttpProxy = $"http://{Settings.GetAriaHttpProxy()}:{Settings.GetAriaHttpProxyListenPort()}",
|
||||
Dir = path,
|
||||
Out = localFileName,
|
||||
//Header = $"cookie: {LoginHelper.GetLoginInfoCookiesString()}\nreferer: https://www.bilibili.com",
|
||||
//UseHead = "true",
|
||||
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36",
|
||||
};
|
||||
|
||||
// 保存gid
|
||||
string gid = ariaAddUri.Result.Result;
|
||||
downloading.Downloading.Gid = gid;
|
||||
// 如果设置了代理,则增加HttpProxy
|
||||
if (SettingsManager.GetInstance().IsAriaHttpProxy() == AllowStatus.YES)
|
||||
{
|
||||
option.HttpProxy = $"http://{SettingsManager.GetInstance().GetAriaHttpProxy()}:{SettingsManager.GetInstance().GetAriaHttpProxyListenPort()}";
|
||||
}
|
||||
|
||||
// 添加一个下载
|
||||
Task<AriaAddUri> 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.Downloading.Gid = gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task<AriaPause> ariaUnpause = AriaClient.UnpauseAsync(downloading.Downloading.Gid);
|
||||
}
|
||||
|
||||
// 管理下载
|
||||
AriaManager ariaManager = new AriaManager();
|
||||
ariaManager.TellStatus += AriaTellStatus;
|
||||
ariaManager.DownloadFinish += AriaDownloadFinish;
|
||||
return ariaManager.GetDownloadStatus(gid, new Action(() =>
|
||||
return ariaManager.GetDownloadStatus(downloading.Downloading.Gid, new Action(() =>
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
switch (downloading.Downloading.DownloadStatus)
|
||||
{
|
||||
case DownloadStatus.PAUSE:
|
||||
@@ -999,7 +1025,6 @@ namespace DownKyi.Services.Download
|
||||
Pause(downloading);
|
||||
break;
|
||||
case DownloadStatus.DOWNLOADING:
|
||||
Task<AriaPause> ariaUnpause = AriaClient.UnpauseAsync(downloading.Downloading.Gid);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -7,6 +7,16 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
public class DownloadStorageService
|
||||
{
|
||||
~DownloadStorageService()
|
||||
{
|
||||
DownloadingDb downloadingDb = new DownloadingDb();
|
||||
downloadingDb.Close();
|
||||
DownloadedDb downloadedDb = new DownloadedDb();
|
||||
downloadedDb.Close();
|
||||
DownloadBaseDb downloadBaseDb = new DownloadBaseDb();
|
||||
downloadBaseDb.Close();
|
||||
}
|
||||
|
||||
#region 下载中数据
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +35,7 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
downloadingDb.Insert(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading);
|
||||
}
|
||||
downloadingDb.Close();
|
||||
//downloadingDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,7 +50,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
DownloadingDb downloadingDb = new DownloadingDb();
|
||||
downloadingDb.Delete(downloadingItem.DownloadBase.Uuid);
|
||||
downloadingDb.Close();
|
||||
//downloadingDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,7 +62,7 @@ namespace DownKyi.Services.Download
|
||||
// 从数据库获取数据
|
||||
DownloadingDb downloadingDb = new DownloadingDb();
|
||||
Dictionary<string, object> dic = downloadingDb.QueryAll();
|
||||
downloadingDb.Close();
|
||||
//downloadingDb.Close();
|
||||
|
||||
// 遍历
|
||||
List<DownloadingItem> list = new List<DownloadingItem>();
|
||||
@@ -85,7 +95,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
DownloadingDb downloadingDb = new DownloadingDb();
|
||||
downloadingDb.Update(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading);
|
||||
downloadingDb.Close();
|
||||
//downloadingDb.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -108,7 +118,7 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
downloadedDb.Insert(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded);
|
||||
}
|
||||
downloadedDb.Close();
|
||||
//downloadedDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +133,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
DownloadedDb downloadedDb = new DownloadedDb();
|
||||
downloadedDb.Delete(downloadedItem.DownloadBase.Uuid);
|
||||
downloadedDb.Close();
|
||||
//downloadedDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,7 +145,7 @@ namespace DownKyi.Services.Download
|
||||
// 从数据库获取数据
|
||||
DownloadedDb downloadedDb = new DownloadedDb();
|
||||
Dictionary<string, object> dic = downloadedDb.QueryAll();
|
||||
downloadedDb.Close();
|
||||
//downloadedDb.Close();
|
||||
|
||||
// 遍历
|
||||
List<DownloadedItem> list = new List<DownloadedItem>();
|
||||
@@ -168,7 +178,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
DownloadedDb downloadedDb = new DownloadedDb();
|
||||
downloadedDb.Update(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded);
|
||||
downloadedDb.Close();
|
||||
//downloadedDb.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -189,7 +199,7 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
downloadBaseDb.Insert(downloadBase.Uuid, downloadBase);
|
||||
}
|
||||
downloadBaseDb.Close();
|
||||
//downloadBaseDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -200,7 +210,7 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
DownloadBaseDb downloadBaseDb = new DownloadBaseDb();
|
||||
downloadBaseDb.Delete(uuid);
|
||||
downloadBaseDb.Close();
|
||||
//downloadBaseDb.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,7 +221,7 @@ namespace DownKyi.Services.Download
|
||||
{
|
||||
DownloadBaseDb downloadBaseDb = new DownloadBaseDb();
|
||||
object obj = downloadBaseDb.QueryById(uuid);
|
||||
downloadBaseDb.Close();
|
||||
//downloadBaseDb.Close();
|
||||
|
||||
return obj is DownloadBase downloadBase ? downloadBase : null;
|
||||
}
|
||||
@@ -226,7 +236,7 @@ namespace DownKyi.Services.Download
|
||||
|
||||
DownloadBaseDb downloadBaseDb = new DownloadBaseDb();
|
||||
downloadBaseDb.Update(downloadBase.Uuid, downloadBase);
|
||||
downloadBaseDb.Close();
|
||||
//downloadBaseDb.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace DownKyi.Services
|
||||
/// 解析支持的输入,
|
||||
/// 支持的格式有:<para/>
|
||||
/// av号:av170001, AV170001, https://www.bilibili.com/video/av170001 <para/>
|
||||
/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC <para/>
|
||||
/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC <para/>
|
||||
/// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 <para/>
|
||||
/// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 <para/>
|
||||
/// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 <para/>
|
||||
|
||||
@@ -165,7 +165,10 @@ namespace DownKyi.Services
|
||||
if (videoQualityExist == null)
|
||||
{
|
||||
List<string> videoCodecList = new List<string>();
|
||||
ListHelper.AddUnique(videoCodecList, codecName);
|
||||
if (codecName != string.Empty)
|
||||
{
|
||||
ListHelper.AddUnique(videoCodecList, codecName);
|
||||
}
|
||||
|
||||
VideoQuality videoQuality = new VideoQuality()
|
||||
{
|
||||
@@ -179,12 +182,24 @@ namespace DownKyi.Services
|
||||
{
|
||||
if (!videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Exists(t => t.Equals(codecName)))
|
||||
{
|
||||
videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Add(codecName);
|
||||
if (codecName != string.Empty)
|
||||
{
|
||||
videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Add(codecName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选中的视频编码
|
||||
VideoQuality selectedVideoQuality = videoQualityList.FirstOrDefault(t => t.Quality == video.Id);
|
||||
if(selectedVideoQuality == null) { continue; }
|
||||
|
||||
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Count == 1)
|
||||
{
|
||||
// 当获取的视频没有设置的视频编码时,执行
|
||||
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList[0];
|
||||
}
|
||||
|
||||
// 设置选中的视频编码
|
||||
switch (videoCodecs)
|
||||
{
|
||||
case VideoCodecs.AVC:
|
||||
@@ -205,11 +220,6 @@ namespace DownKyi.Services
|
||||
break;
|
||||
}
|
||||
|
||||
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Count == 1)
|
||||
{
|
||||
// 当获取的视频没有设置的视频编码时,执行
|
||||
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList[0];
|
||||
}
|
||||
}
|
||||
|
||||
return videoQualityList;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using DownKyi.Core.BiliApi.Video;
|
||||
using DownKyi.Core.BiliApi.Video.Models;
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using DownKyi.Core.Settings;
|
||||
using DownKyi.Core.Storage;
|
||||
using DownKyi.Core.Utils;
|
||||
using DownKyi.ViewModels.PageViewModels;
|
||||
@@ -83,6 +84,26 @@ namespace DownKyi.Services
|
||||
Name = name,
|
||||
Duration = "N/A"
|
||||
};
|
||||
|
||||
// UP主信息
|
||||
videoPage.Owner = videoView.Owner;
|
||||
if (videoPage.Owner == null)
|
||||
{
|
||||
videoPage.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = "",
|
||||
Face = "",
|
||||
Mid = -1,
|
||||
};
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
// 视频发布时间
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
|
||||
DateTime dateTime = startTime.AddSeconds(videoView.Pubdate);
|
||||
videoPage.PublishTime = dateTime.ToString(timeFormat);
|
||||
|
||||
videoPages.Add(videoPage);
|
||||
}
|
||||
|
||||
@@ -120,6 +141,30 @@ namespace DownKyi.Services
|
||||
Name = episode.Title,
|
||||
Duration = "N/A"
|
||||
};
|
||||
|
||||
// UP主信息
|
||||
page.Owner = videoView.Owner;
|
||||
if (page.Owner == null)
|
||||
{
|
||||
page.Owner = new Core.BiliApi.Models.VideoOwner
|
||||
{
|
||||
Name = "",
|
||||
Face = "",
|
||||
Mid = -1,
|
||||
};
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
// 视频发布时间
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
|
||||
DateTime dateTime = startTime.AddSeconds(videoView.Pubdate);
|
||||
page.PublishTime = dateTime.ToString(timeFormat);
|
||||
// 这里的发布时间有问题,
|
||||
// 如果是合集,也会执行这里,
|
||||
// 但是发布时间是入口视频的,不是所有视频的
|
||||
// TODO 修复
|
||||
|
||||
pages.Add(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace DownKyi.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 为窗口<see cref="Window"/>添加附加属性的辅助类
|
||||
///
|
||||
/// https://www.cnblogs.com/kybs0/p/9834023.html
|
||||
/// </summary>
|
||||
public class WindowAdaptation
|
||||
{
|
||||
#region 窗口宽度比例
|
||||
/// <summary>
|
||||
/// 窗口宽度比例 单位:小数(0 - 1.0]
|
||||
/// <para>窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例</para>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty WidthByScreenRatioProperty = DependencyProperty.RegisterAttached(
|
||||
"WidthByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnWidthByScreenRatioPropertyChanged));
|
||||
|
||||
private static void OnWidthByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Window window && e.NewValue is double widthByScreenRatio)
|
||||
{
|
||||
if (widthByScreenRatio <= 0 || widthByScreenRatio > 1)
|
||||
{
|
||||
throw new ArgumentException($"屏幕比例不支持{widthByScreenRatio}");
|
||||
}
|
||||
|
||||
var screenDisplayArea = GetScreenSize(window);
|
||||
var screenRatioWidth = screenDisplayArea.Width * widthByScreenRatio;
|
||||
|
||||
//if (!double.IsNaN(window.Width) && screenDisplayArea.Width > window.Width)
|
||||
//{
|
||||
// window.Width = window.Width;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// window.Width = screenRatioWidth;
|
||||
//}
|
||||
|
||||
if (!double.IsNaN(window.Width) && screenRatioWidth > window.Width)
|
||||
{
|
||||
window.Width = window.Width;
|
||||
}
|
||||
else if (!double.IsNaN(window.MinWidth) && screenRatioWidth < window.MinWidth)
|
||||
{
|
||||
window.Width = screenDisplayArea.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Width = screenRatioWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetWidthByScreenRatio(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(WidthByScreenRatioProperty, value);
|
||||
}
|
||||
|
||||
public static double GetWidthByScreenRatio(DependencyObject element)
|
||||
{
|
||||
return (double)element.GetValue(WidthByScreenRatioProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 窗口高度比例
|
||||
/// <summary>
|
||||
/// 窗口宽度比例 单位:小数(0 - 1.0]
|
||||
/// <para>窗口实际宽度=使用屏幕可显示区域(屏幕高度-任务栏高度)* 窗口宽度比例</para>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty HeightByScreenRatioProperty = DependencyProperty.RegisterAttached(
|
||||
"HeightByScreenRatio", typeof(double), typeof(WindowAdaptation), new PropertyMetadata(1.0, OnHeightByScreenRatioPropertyChanged));
|
||||
|
||||
private static void OnHeightByScreenRatioPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Window window && e.NewValue is double heightByScreenRatio)
|
||||
{
|
||||
if (heightByScreenRatio <= 0 || heightByScreenRatio > 1)
|
||||
{
|
||||
throw new ArgumentException($"屏幕比例不支持{heightByScreenRatio}");
|
||||
}
|
||||
|
||||
var screenDisplayArea = GetScreenSize(window);
|
||||
var screenRatioHeight = screenDisplayArea.Height * heightByScreenRatio;
|
||||
|
||||
if (!double.IsNaN(window.Height) && screenDisplayArea.Height > window.Height)
|
||||
{
|
||||
window.Height = window.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Height = screenRatioHeight;
|
||||
}
|
||||
|
||||
//if (!double.IsNaN(window.Height) && screenRatioHeight > window.Height)
|
||||
//{
|
||||
// window.Height = window.Height;
|
||||
//}
|
||||
//else if (!double.IsNaN(window.MinHeight) && screenRatioHeight < window.MinHeight)
|
||||
//{
|
||||
// window.Height = screenDisplayArea.Height;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// window.Height = screenRatioHeight;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHeightByScreenRatio(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(HeightByScreenRatioProperty, value);
|
||||
}
|
||||
|
||||
public static double GetHeightByScreenRatio(DependencyObject element)
|
||||
{
|
||||
return (double)element.GetValue(HeightByScreenRatioProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
const int DpiPercent = 96;
|
||||
private static dynamic GetScreenSize(Window window)
|
||||
{
|
||||
var intPtr = new WindowInteropHelper(window).Handle;//获取当前窗口的句柄
|
||||
var screen = Screen.FromHandle(intPtr);//获取当前屏幕
|
||||
using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
|
||||
{
|
||||
//分别获取当前屏幕X/Y方向的DPI
|
||||
double dpiXRatio = currentGraphics.DpiX / DpiPercent;
|
||||
double dpiYRatio = currentGraphics.DpiY / DpiPercent;
|
||||
|
||||
var width = screen.WorkingArea.Width / dpiXRatio;
|
||||
var height = screen.WorkingArea.Height / dpiYRatio;
|
||||
|
||||
return new { Width = width, Height = height };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace DownKyi.ViewModels.Dialogs
|
||||
{
|
||||
SetProperty(ref directory, value);
|
||||
|
||||
if (directory != string.Empty)
|
||||
if (directory != null && directory != string.Empty)
|
||||
{
|
||||
DriveName = directory.Substring(0, 1).ToUpper();
|
||||
DriveNameFreeSpace = Format.FormatFileSize(HardDisk.GetHardDiskFreeSpace(DriveName));
|
||||
@@ -381,7 +381,7 @@ namespace DownKyi.ViewModels.Dialogs
|
||||
|
||||
// 弹出选择下载目录的窗口
|
||||
path = DialogUtils.SetDownloadDirectory();
|
||||
if (path == null || path == "")
|
||||
if (path == null || path == string.Empty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ namespace DownKyi.ViewModels.DownloadManager
|
||||
/// </summary>
|
||||
private void ExecuteOpenFolderCommand()
|
||||
{
|
||||
if (DownloadBase == null) { return; }
|
||||
|
||||
string videoPath = $"{DownloadBase.FilePath}.mp4";
|
||||
FileInfo fileInfo = new FileInfo(videoPath);
|
||||
if (File.Exists(fileInfo.FullName))
|
||||
@@ -105,6 +107,8 @@ namespace DownKyi.ViewModels.DownloadManager
|
||||
/// </summary>
|
||||
private void ExecuteOpenVideoCommand()
|
||||
{
|
||||
if (DownloadBase == null) { return; }
|
||||
|
||||
string videoPath = $"{DownloadBase.FilePath}.mp4";
|
||||
var fileInfo = new FileInfo(videoPath);
|
||||
if (File.Exists(fileInfo.FullName))
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using DownKyi.Core.BiliApi.BiliUtils;
|
||||
using DownKyi.Core.BiliApi.Models;
|
||||
using DownKyi.Core.BiliApi.VideoStream.Models;
|
||||
using DownKyi.Core.Logging;
|
||||
using DownKyi.Core.Utils;
|
||||
using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -16,6 +19,8 @@ namespace DownKyi.ViewModels.PageViewModels
|
||||
public string Bvid { get; set; }
|
||||
public long Cid { get; set; }
|
||||
public long EpisodeId { get; set; }
|
||||
public VideoOwner Owner { get; set; }
|
||||
public string PublishTime { get; set; }
|
||||
|
||||
public string FirstFrame { get; set; }
|
||||
|
||||
@@ -87,7 +92,18 @@ namespace DownKyi.ViewModels.PageViewModels
|
||||
private void ExecuteVideoQualitySelectedCommand()
|
||||
{
|
||||
// 杜比视界
|
||||
string dolby = Constant.GetAudioQualities()[3].Name;
|
||||
string dolby = string.Empty;
|
||||
try
|
||||
{
|
||||
var qualities = Constant.GetAudioQualities();
|
||||
dolby = qualities[3].Name;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Core.Utils.Debugging.Console.PrintLine("ExecuteVideoQualitySelectedCommand()发生异常: {0}", e);
|
||||
LogManager.Error("ExecuteVideoQualitySelectedCommand", e);
|
||||
}
|
||||
|
||||
if (VideoQuality != null && VideoQuality.Quality == 126)
|
||||
{
|
||||
ListHelper.AddUnique(AudioQualityFormatList, dolby);
|
||||
@@ -101,7 +117,6 @@ namespace DownKyi.ViewModels.PageViewModels
|
||||
AudioQualityFormat = AudioQualityFormatList[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -105,8 +105,21 @@ namespace DownKyi.ViewModels.Settings
|
||||
set => SetProperty(ref selectedOptionalField, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
private List<string> fileNamePartTimeFormatList;
|
||||
public List<string> FileNamePartTimeFormatList
|
||||
{
|
||||
get => fileNamePartTimeFormatList;
|
||||
set => SetProperty(ref fileNamePartTimeFormatList, value);
|
||||
}
|
||||
|
||||
private string selectedFileNamePartTimeFormat;
|
||||
public string SelectedFileNamePartTimeFormat
|
||||
{
|
||||
get => selectedFileNamePartTimeFormat;
|
||||
set => SetProperty(ref selectedFileNamePartTimeFormat, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ViewVideoViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
|
||||
{
|
||||
@@ -138,6 +151,13 @@ namespace DownKyi.ViewModels.Settings
|
||||
|
||||
SelectedOptionalField = -1;
|
||||
|
||||
// 文件命名中的时间格式
|
||||
FileNamePartTimeFormatList = new List<string>
|
||||
{
|
||||
"yyyy-MM-dd",
|
||||
"yyyy.MM.dd",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -184,6 +204,9 @@ namespace DownKyi.ViewModels.Settings
|
||||
SelectedFileName.Add(new DisplayFileNamePart { Id = item, Title = display });
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式
|
||||
SelectedFileNamePartTimeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat();
|
||||
|
||||
isOnNavigatedTo = false;
|
||||
}
|
||||
|
||||
@@ -313,6 +336,8 @@ namespace DownKyi.ViewModels.Settings
|
||||
|
||||
isSucceed = SettingsManager.GetInstance().SetFileNameParts(fileName);
|
||||
PublishTip(isSucceed);
|
||||
|
||||
SelectedOptionalField = -1;
|
||||
}
|
||||
|
||||
// 可选文件名字段点击事件
|
||||
@@ -363,8 +388,25 @@ namespace DownKyi.ViewModels.Settings
|
||||
string display = DisplayFileNamePart(item);
|
||||
SelectedFileName.Add(new DisplayFileNamePart { Id = item, Title = display });
|
||||
}
|
||||
|
||||
SelectedOptionalField = -1;
|
||||
}
|
||||
|
||||
// 文件命名中的时间格式事件
|
||||
private DelegateCommand<object> fileNamePartTimeFormatCommand;
|
||||
public DelegateCommand<object> FileNamePartTimeFormatCommand => fileNamePartTimeFormatCommand ?? (fileNamePartTimeFormatCommand = new DelegateCommand<object>(ExecuteFileNamePartTimeFormatCommand));
|
||||
|
||||
/// <summary>
|
||||
/// 文件命名中的时间格式事件
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
private void ExecuteFileNamePartTimeFormatCommand(object parameter)
|
||||
{
|
||||
if (!(parameter is string timeFormat)) { return; }
|
||||
|
||||
bool isSucceed = SettingsManager.GetInstance().SetFileNamePartTimeFormat(timeFormat);
|
||||
PublishTip(isSucceed);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -469,6 +511,24 @@ namespace DownKyi.ViewModels.Settings
|
||||
case FileNamePart.VIDEO_CODEC:
|
||||
display = DictionaryResource.GetString("DisplayVideoCodec");
|
||||
break;
|
||||
case FileNamePart.VIDEO_PUBLISH_TIME:
|
||||
display = DictionaryResource.GetString("DisplayVideoPublishTime");
|
||||
break;
|
||||
case FileNamePart.AVID:
|
||||
display = "avid";
|
||||
break;
|
||||
case FileNamePart.BVID:
|
||||
display = "bvid";
|
||||
break;
|
||||
case FileNamePart.CID:
|
||||
display = "cid";
|
||||
break;
|
||||
case FileNamePart.UP_MID:
|
||||
display = DictionaryResource.GetString("DisplayUpMid");
|
||||
break;
|
||||
case FileNamePart.UP_NAME:
|
||||
display = DictionaryResource.GetString("DisplayUpName");
|
||||
break;
|
||||
}
|
||||
|
||||
if (((int)item) >= 100)
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
@@ -297,6 +297,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
Medias.Clear();
|
||||
IsSelectAll = false;
|
||||
LoadingVisibility = Visibility.Visible;
|
||||
NoDataVisibility = Visibility.Collapsed;
|
||||
|
||||
|
||||
@@ -227,65 +227,73 @@ namespace DownKyi.ViewModels
|
||||
/// </summary>
|
||||
private async void UpdateUserInfo()
|
||||
{
|
||||
LoginPanelVisibility = Visibility.Hidden;
|
||||
|
||||
// 检查本地是否存在login文件,没有则说明未登录
|
||||
if (!File.Exists(StorageManager.GetLogin()))
|
||||
try
|
||||
{
|
||||
LoginPanelVisibility = Visibility.Visible;
|
||||
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
|
||||
UserName = null;
|
||||
return;
|
||||
}
|
||||
LoginPanelVisibility = Visibility.Hidden;
|
||||
|
||||
await Task.Run(new Action(() =>
|
||||
{
|
||||
// 获取用户信息
|
||||
var userInfo = UserInfo.GetUserInfoForNavigation();
|
||||
if (userInfo != null)
|
||||
{
|
||||
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
|
||||
{
|
||||
Mid = userInfo.Mid,
|
||||
Name = userInfo.Name,
|
||||
IsLogin = userInfo.IsLogin,
|
||||
IsVip = userInfo.VipStatus == 1
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
|
||||
{
|
||||
Mid = -1,
|
||||
Name = "",
|
||||
IsLogin = false,
|
||||
IsVip = false
|
||||
});
|
||||
}
|
||||
|
||||
PropertyChangeAsync(new Action(() =>
|
||||
// 检查本地是否存在login文件,没有则说明未登录
|
||||
if (!File.Exists(StorageManager.GetLogin()))
|
||||
{
|
||||
LoginPanelVisibility = Visibility.Visible;
|
||||
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
|
||||
UserName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Run(new Action(() =>
|
||||
{
|
||||
// 获取用户信息
|
||||
var userInfo = UserInfo.GetUserInfoForNavigation();
|
||||
if (userInfo != null)
|
||||
{
|
||||
if (userInfo.Face != null)
|
||||
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
|
||||
{
|
||||
Header = new StorageHeader().GetHeaderThumbnail(userInfo.Mid, userInfo.Name, userInfo.Face, 36, 36);
|
||||
Mid = userInfo.Mid,
|
||||
Name = userInfo.Name,
|
||||
IsLogin = userInfo.IsLogin,
|
||||
IsVip = userInfo.VipStatus == 1
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
|
||||
{
|
||||
Mid = -1,
|
||||
Name = "",
|
||||
IsLogin = false,
|
||||
IsVip = false
|
||||
});
|
||||
}
|
||||
|
||||
PropertyChangeAsync(new Action(() =>
|
||||
{
|
||||
LoginPanelVisibility = Visibility.Visible;
|
||||
|
||||
if (userInfo != null)
|
||||
{
|
||||
if (userInfo.Face != null)
|
||||
{
|
||||
Header = new StorageHeader().GetHeaderThumbnail(userInfo.Mid, userInfo.Name, userInfo.Face, 36, 36);
|
||||
}
|
||||
else
|
||||
{
|
||||
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
|
||||
}
|
||||
UserName = userInfo.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
|
||||
UserName = null;
|
||||
}
|
||||
UserName = userInfo.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
|
||||
UserName = null;
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Core.Utils.Debugging.Console.PrintLine("UpdateUserInfo()发生异常: {0}", e);
|
||||
LogManager.Error(Tag, e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -98,26 +98,34 @@ namespace DownKyi.ViewModels
|
||||
/// </summary>
|
||||
private void Login()
|
||||
{
|
||||
var loginUrl = LoginQR.GetLoginUrl();
|
||||
if (loginUrl == null) { return; }
|
||||
|
||||
if (loginUrl.Status != true)
|
||||
try
|
||||
{
|
||||
ExecuteBackSpace();
|
||||
return;
|
||||
}
|
||||
var loginUrl = LoginQR.GetLoginUrl();
|
||||
if (loginUrl == null) { return; }
|
||||
|
||||
if (loginUrl.Data == null || loginUrl.Data.Url == null)
|
||||
if (loginUrl.Status != true)
|
||||
{
|
||||
ExecuteBackSpace();
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginUrl.Data == null || loginUrl.Data.Url == null)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("GetLoginUrlFailed"));
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyChangeAsync(new Action(() => { LoginQRCode = LoginQR.GetLoginQRCode(loginUrl.Data.Url); }));
|
||||
Core.Utils.Debugging.Console.PrintLine(loginUrl.Data.Url + "\n");
|
||||
LogManager.Debug(Tag, loginUrl.Data.Url);
|
||||
|
||||
GetLoginStatus(loginUrl.Data.OauthKey);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("GetLoginUrlFailed"));
|
||||
return;
|
||||
Core.Utils.Debugging.Console.PrintLine("Login()发生异常: {0}", e);
|
||||
LogManager.Error(Tag, e);
|
||||
}
|
||||
|
||||
PropertyChangeAsync(new Action(() => { LoginQRCode = LoginQR.GetLoginQRCode(loginUrl.Data.Url); }));
|
||||
Core.Utils.Debugging.Console.PrintLine(loginUrl.Data.Url + "\n");
|
||||
LogManager.Debug(Tag, loginUrl.Data.Url);
|
||||
|
||||
GetLoginStatus(loginUrl.Data.OauthKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -190,6 +190,9 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
if (!(parameter is TabHeader tabHeader)) { return; }
|
||||
|
||||
// 顶部tab点击后,隐藏Content
|
||||
ContentVisibility = Visibility.Collapsed;
|
||||
|
||||
// 页面选择
|
||||
Pager = new CustomPagerViewModel(1, 1);
|
||||
Pager.CurrentChanged += OnCurrentChanged_Pager;
|
||||
@@ -326,7 +329,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
@@ -354,6 +357,8 @@ namespace DownKyi.ViewModels
|
||||
private async void UpdateBangumiMediaList(int current)
|
||||
{
|
||||
Medias.Clear();
|
||||
IsSelectAll = false;
|
||||
|
||||
LoadingVisibility = Visibility.Visible;
|
||||
NoDataVisibility = Visibility.Collapsed;
|
||||
|
||||
|
||||
@@ -80,6 +80,14 @@ namespace DownKyi.ViewModels
|
||||
set => SetProperty(ref mediaLoading, value);
|
||||
}
|
||||
|
||||
private Visibility mediaContentVisibility;
|
||||
public Visibility MediaContentVisibility
|
||||
{
|
||||
get => mediaContentVisibility;
|
||||
set => SetProperty(ref mediaContentVisibility, value);
|
||||
}
|
||||
|
||||
|
||||
private Visibility mediaLoadingVisibility;
|
||||
public Visibility MediaLoadingVisibility
|
||||
{
|
||||
@@ -211,6 +219,9 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
if (!(parameter is TabHeader tabHeader)) { return; }
|
||||
|
||||
// tab点击后,隐藏MediaContent
|
||||
MediaContentVisibility = Visibility.Collapsed;
|
||||
|
||||
// 页面选择
|
||||
Pager = new CustomPagerViewModel(1, (int)Math.Ceiling(double.Parse(tabHeader.SubTitle) / VideoNumberInPage));
|
||||
Pager.CurrentChanged += OnCurrentChanged_Pager;
|
||||
@@ -347,7 +358,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
@@ -375,6 +386,8 @@ namespace DownKyi.ViewModels
|
||||
private async void UpdateFavoritesMediaList(int current)
|
||||
{
|
||||
Medias.Clear();
|
||||
IsSelectAll = false;
|
||||
|
||||
MediaLoadingVisibility = Visibility.Visible;
|
||||
MediaNoDataVisibility = Visibility.Collapsed;
|
||||
|
||||
@@ -391,11 +404,13 @@ namespace DownKyi.ViewModels
|
||||
List<Core.BiliApi.Favorites.Models.FavoritesMedia> medias = FavoritesResource.GetFavoritesMedia(tab.Id, current, VideoNumberInPage);
|
||||
if (medias == null || medias.Count == 0)
|
||||
{
|
||||
MediaContentVisibility = Visibility.Visible;
|
||||
MediaLoadingVisibility = Visibility.Collapsed;
|
||||
MediaNoDataVisibility = Visibility.Visible;
|
||||
return;
|
||||
}
|
||||
|
||||
MediaContentVisibility = Visibility.Visible;
|
||||
MediaLoadingVisibility = Visibility.Collapsed;
|
||||
MediaNoDataVisibility = Visibility.Collapsed;
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Prism.Events;
|
||||
using Prism.Regions;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
@@ -22,6 +23,8 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
public const string Tag = "PageMySpace";
|
||||
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
// mid
|
||||
private long mid = -1;
|
||||
|
||||
@@ -291,6 +294,9 @@ namespace DownKyi.ViewModels
|
||||
/// </summary>
|
||||
private void ExecuteBackSpace()
|
||||
{
|
||||
// 结束任务
|
||||
tokenSource?.Cancel();
|
||||
|
||||
NavigationParam parameter = new NavigationParam
|
||||
{
|
||||
ViewName = ParentView,
|
||||
@@ -415,6 +421,7 @@ namespace DownKyi.ViewModels
|
||||
/// </summary>
|
||||
private async void UpdateSpaceInfo()
|
||||
{
|
||||
bool isCancel = false;
|
||||
bool isNoData = true;
|
||||
Uri toutuUri = null;
|
||||
string headerUri = null;
|
||||
@@ -423,6 +430,8 @@ namespace DownKyi.ViewModels
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
CancellationToken cancellationToken = tokenSource.Token;
|
||||
|
||||
// 背景图片
|
||||
SpaceSettings spaceSettings = Core.BiliApi.Users.UserSpace.GetSpaceSettings(mid);
|
||||
if (spaceSettings != null)
|
||||
@@ -505,7 +514,19 @@ namespace DownKyi.ViewModels
|
||||
// 没有数据
|
||||
isNoData = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 判断是否该结束线程
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
isCancel = true;
|
||||
}
|
||||
}, (tokenSource = new CancellationTokenSource()).Token);
|
||||
|
||||
// 是否该结束线程
|
||||
if (isCancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 是否获取到数据
|
||||
if (isNoData)
|
||||
@@ -526,9 +547,9 @@ namespace DownKyi.ViewModels
|
||||
StorageHeader storageHeader = new StorageHeader();
|
||||
Header = storageHeader.GetHeaderThumbnail(headerUri, 64, 64);
|
||||
// 性别
|
||||
Sex = new BitmapImage(sexUri);
|
||||
Sex = sexUri == null ? null : new BitmapImage(sexUri);
|
||||
// 等级
|
||||
Level = new BitmapImage(levelUri);
|
||||
Level = levelUri == null ? null : new BitmapImage(levelUri);
|
||||
|
||||
ArrowBack.Fill = DictionaryResource.GetColor("ColorText");
|
||||
Logout.Fill = DictionaryResource.GetColor("ColorText");
|
||||
|
||||
@@ -258,7 +258,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
@@ -334,6 +334,7 @@ namespace DownKyi.ViewModels
|
||||
}
|
||||
|
||||
Medias.Clear();
|
||||
IsSelectAll = false;
|
||||
LoadingVisibility = Visibility.Visible;
|
||||
NoDataVisibility = Visibility.Collapsed;
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace DownKyi.ViewModels
|
||||
// 性别
|
||||
Sex = sexUri == null ? null : new BitmapImage(sexUri);
|
||||
// 等级
|
||||
Level = new BitmapImage(levelUri);
|
||||
Level = levelUri == null ? null : new BitmapImage(levelUri);
|
||||
|
||||
ArrowBack.Fill = DictionaryResource.GetColor("ColorText");
|
||||
TopNavigationBg = DictionaryResource.GetColor("ColorMask100");
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace DownKyi.ViewModels
|
||||
|
||||
private readonly IDialogService dialogService;
|
||||
|
||||
// 保存输入字符串,避免被用户修改
|
||||
private string input;
|
||||
|
||||
#region 页面属性申明
|
||||
|
||||
private VectorImage arrowBack;
|
||||
@@ -184,8 +187,10 @@ namespace DownKyi.ViewModels
|
||||
|
||||
LogManager.Debug(Tag, $"InputText: {InputText}");
|
||||
|
||||
input = InputText;
|
||||
|
||||
// 更新页面
|
||||
UnityUpdateView(UpdateView, InputText, null);
|
||||
UnityUpdateView(UpdateView, input, null);
|
||||
|
||||
// 是否自动解析视频
|
||||
if (SettingsManager.GetInstance().IsAutoParseVideo() == AllowStatus.YES)
|
||||
@@ -362,7 +367,7 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
LogManager.Debug(Tag, $"Video Page: {videoPage.Cid}");
|
||||
|
||||
UnityUpdateView(ParseVideo, null, videoPage);
|
||||
UnityUpdateView(ParseVideo, input, videoPage);
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -430,12 +435,10 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
foreach (VideoPage page in section.VideoPages)
|
||||
{
|
||||
//VideoPage videoPage = section.VideoPages.FirstOrDefault(t => t == page);
|
||||
|
||||
if (page.IsSelected)
|
||||
{
|
||||
// 执行解析任务
|
||||
UnityUpdateView(ParseVideo, null, page);
|
||||
UnityUpdateView(ParseVideo, input, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,10 +450,8 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
foreach (VideoPage page in section.VideoPages)
|
||||
{
|
||||
//VideoPage videoPage = section.VideoPages.FirstOrDefault(t => t == page);
|
||||
|
||||
// 执行解析任务
|
||||
UnityUpdateView(ParseVideo, null, page);
|
||||
UnityUpdateView(ParseVideo, input, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,10 +461,8 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
foreach (VideoPage page in section.VideoPages)
|
||||
{
|
||||
//VideoPage videoPage = section.VideoPages.FirstOrDefault(t => t == page);
|
||||
|
||||
// 执行解析任务
|
||||
UnityUpdateView(ParseVideo, null, page);
|
||||
UnityUpdateView(ParseVideo, input, page);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -503,20 +502,24 @@ namespace DownKyi.ViewModels
|
||||
{
|
||||
AddToDownloadService addToDownloadService = null;
|
||||
// 视频
|
||||
if (ParseEntrance.IsAvUrl(InputText) || ParseEntrance.IsBvUrl(InputText))
|
||||
if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input))
|
||||
{
|
||||
addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO);
|
||||
}
|
||||
// 番剧(电影、电视剧)
|
||||
if (ParseEntrance.IsBangumiSeasonUrl(InputText) || ParseEntrance.IsBangumiEpisodeUrl(InputText) || ParseEntrance.IsBangumiMediaUrl(InputText))
|
||||
else if (ParseEntrance.IsBangumiSeasonUrl(input) || ParseEntrance.IsBangumiEpisodeUrl(input) || ParseEntrance.IsBangumiMediaUrl(input))
|
||||
{
|
||||
addToDownloadService = new AddToDownloadService(PlayStreamType.BANGUMI);
|
||||
}
|
||||
// 课程
|
||||
if (ParseEntrance.IsCheeseSeasonUrl(InputText) || ParseEntrance.IsCheeseEpisodeUrl(InputText))
|
||||
else if (ParseEntrance.IsCheeseSeasonUrl(input) || ParseEntrance.IsCheeseEpisodeUrl(input))
|
||||
{
|
||||
addToDownloadService = new AddToDownloadService(PlayStreamType.CHEESE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 选择文件夹
|
||||
string directory = addToDownloadService.SetDirectory(dialogService);
|
||||
@@ -531,8 +534,13 @@ namespace DownKyi.ViewModels
|
||||
i = addToDownloadService.AddToDownload(eventAggregator, directory);
|
||||
});
|
||||
|
||||
if (directory == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 通知用户添加到下载列表的结果
|
||||
if (i == 0)
|
||||
if (i <= 0)
|
||||
{
|
||||
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
|
||||
}
|
||||
@@ -578,19 +586,19 @@ namespace DownKyi.ViewModels
|
||||
private void UnityUpdateView(Action<IInfoService, VideoPage> action, string input, VideoPage page)
|
||||
{
|
||||
// 视频
|
||||
if (ParseEntrance.IsAvUrl(InputText) || ParseEntrance.IsBvUrl(InputText))
|
||||
if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input))
|
||||
{
|
||||
action(new VideoInfoService(input), page);
|
||||
}
|
||||
|
||||
// 番剧(电影、电视剧)
|
||||
if (ParseEntrance.IsBangumiSeasonUrl(InputText) || ParseEntrance.IsBangumiEpisodeUrl(InputText) || ParseEntrance.IsBangumiMediaUrl(InputText))
|
||||
if (ParseEntrance.IsBangumiSeasonUrl(input) || ParseEntrance.IsBangumiEpisodeUrl(input) || ParseEntrance.IsBangumiMediaUrl(input))
|
||||
{
|
||||
action(new BangumiInfoService(input), page);
|
||||
}
|
||||
|
||||
// 课程
|
||||
if (ParseEntrance.IsCheeseSeasonUrl(InputText) || ParseEntrance.IsCheeseEpisodeUrl(InputText))
|
||||
if (ParseEntrance.IsCheeseSeasonUrl(input) || ParseEntrance.IsCheeseEpisodeUrl(input))
|
||||
{
|
||||
action(new CheeseInfoService(input), page);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:DownKyi.Utils"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
Title="{DynamicResource AppName}"
|
||||
Width="1100"
|
||||
Height="750"
|
||||
MinWidth="1100"
|
||||
MinHeight="750"
|
||||
MinWidth="800"
|
||||
MinHeight="550"
|
||||
local:WindowAdaptation.HeightByScreenRatio="0.75"
|
||||
local:WindowAdaptation.WidthByScreenRatio="0.8"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
ResizeMode="CanResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
@@ -200,4 +203,5 @@
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Window>
|
||||
|
||||
@@ -403,6 +403,7 @@
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="10" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="10" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
ToolTip="{DynamicResource LayoutAlgorithmAsyncTip}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="10" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="10" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -178,34 +178,12 @@
|
||||
Grid.Column="0"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource BrushTextDark}"
|
||||
Text="{DynamicResource FileName}" />
|
||||
<ListBox
|
||||
x:Name="nameSelectedFileName"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
MinHeight="30"
|
||||
Margin="0,0,0,20"
|
||||
ItemContainerStyle="{StaticResource TagItem2Style}"
|
||||
ItemsSource="{Binding SelectedFileName, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
Style="{StaticResource Tag2Style}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<i:InvokeCommandAction Command="{Binding SelectedFileNameCommand}" CommandParameter="{Binding ElementName=nameSelectedFileName, Path=SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ListBox>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource BrushTextDark}"
|
||||
Text="{DynamicResource OptionalFields}" />
|
||||
<ListBox
|
||||
Name="nameOptionalFields"
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,0,20"
|
||||
ItemContainerStyle="{StaticResource TagItem2Style}"
|
||||
ItemsSource="{Binding OptionalFields, Mode=TwoWay}"
|
||||
SelectedIndex="{Binding SelectedOptionalField}"
|
||||
@@ -218,6 +196,54 @@
|
||||
</i:Interaction.Triggers>
|
||||
</ListBox>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource BrushTextDark}"
|
||||
Text="{DynamicResource FileName}" />
|
||||
<ListBox
|
||||
x:Name="nameSelectedFileName"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
MinHeight="30"
|
||||
ItemContainerStyle="{StaticResource TagItem2Style}"
|
||||
ItemsSource="{Binding SelectedFileName, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
Style="{StaticResource Tag2Style}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<i:InvokeCommandAction Command="{Binding SelectedFileNameCommand}" CommandParameter="{Binding ElementName=nameSelectedFileName, Path=SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ListBox>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource BrushTextDark}"
|
||||
Text="{DynamicResource FileNameTimeFormat}" />
|
||||
<ComboBox
|
||||
Name="nameFileNamePartTimeFormat"
|
||||
Width="120"
|
||||
VerticalAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
ItemsSource="{Binding FileNamePartTimeFormatList}"
|
||||
SelectedItem="{Binding SelectedFileNamePartTimeFormat}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<i:InvokeCommandAction Command="{Binding FileNamePartTimeFormatCommand}" CommandParameter="{Binding ElementName=nameFileNamePartTimeFormat, Path=SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
@@ -232,6 +258,7 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<StackPanel Margin="10" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -221,7 +221,10 @@
|
||||
</i:Interaction.Triggers>
|
||||
</ListBox>
|
||||
|
||||
<Grid Name="nameMediaPanel" Grid.Column="1">
|
||||
<Grid
|
||||
Name="nameMediaPanel"
|
||||
Grid.Column="1"
|
||||
Visibility="{Binding MediaContentVisibility}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="1" />
|
||||
@@ -268,27 +271,6 @@
|
||||
</ListBox.Style>
|
||||
</ListBox>
|
||||
|
||||
<!-- 加载gif -->
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical"
|
||||
Visibility="{Binding MediaLoadingVisibility}">
|
||||
<ContentControl
|
||||
Width="40"
|
||||
Height="40"
|
||||
Content="{Binding MediaLoading}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 没有数据提示 -->
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Width="256"
|
||||
Height="256"
|
||||
Source="/DownKyi;component/Resources/no-data.png"
|
||||
Visibility="{Binding MediaNoDataVisibility}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Background="{DynamicResource BrushBorder}" />
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
@@ -340,6 +322,28 @@
|
||||
Style="{StaticResource BtnStyle}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- 加载gif -->
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical"
|
||||
Visibility="{Binding MediaLoadingVisibility}">
|
||||
<ContentControl
|
||||
Width="40"
|
||||
Height="40"
|
||||
Content="{Binding MediaLoading}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 没有数据提示 -->
|
||||
<Image
|
||||
Grid.Column="1"
|
||||
Width="256"
|
||||
Height="256"
|
||||
Source="/DownKyi;component/Resources/no-data.png"
|
||||
Visibility="{Binding MediaNoDataVisibility}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- 加载gif -->
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
- [x] 支持封面下载
|
||||
|
||||
- [x] 支持自定义文件命名
|
||||
|
||||
- [x] 支持断点续传
|
||||
|
||||
- [x] 支持Aria2c
|
||||
@@ -60,7 +62,7 @@
|
||||
目前已支持的有:
|
||||
|
||||
- [x] av号:av170001,https://www.bilibili.com/video/av170001
|
||||
- [x] BV号:BV17x411w7KC,https://www.bilibili.com/video/BV17x411w7KC
|
||||
- [x] BV号:BV17x411w7KC,https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC
|
||||
- [x] 番剧(电影、电视剧)ss号:https://www.bilibili.com/bangumi/play/ss32982
|
||||
- [x] 番剧(电影、电视剧)ep号:https://www.bilibili.com/bangumi/play/ep317925
|
||||
- [x] 番剧(电影、电视剧)md号:https://www.bilibili.com/bangumi/media/md28228367
|
||||
|
||||
Reference in New Issue
Block a user