From 60f3fed69bb81af2c320f1f248880ecb25f7000e Mon Sep 17 00:00:00 2001 From: dogdie233 Date: Mon, 4 Sep 2023 23:59:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9#668=E7=9A=84=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BBDown.Core/Logger.cs | 29 ++++++- BBDown/BBDownMuxer.cs | 35 +++----- BBDown/BBDownUtil.cs | 4 + BBDown/CommandLineInvoker.cs | 27 +------ BBDown/MyOption.cs | 9 +-- BBDown/Program.cs | 150 ++++++++++++++++++----------------- 6 files changed, 126 insertions(+), 128 deletions(-) diff --git a/BBDown.Core/Logger.cs b/BBDown.Core/Logger.cs index 1569b392c..5b414fa3d 100644 --- a/BBDown.Core/Logger.cs +++ b/BBDown.Core/Logger.cs @@ -1,7 +1,11 @@ -namespace BBDown.Core +using System.Text; + +namespace BBDown.Core { public class Logger { + public static readonly string debugFileName = "debug.json"; + public static void Log(object text, bool enter = true) { Console.Write(DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss.fff]") + " - " + text); @@ -57,5 +61,28 @@ public static void LogDebug(string toFormat, params object[] args) Console.WriteLine(); } } + + public static void WriteDebugFile(string content) + { + if (!Config.DEBUG_LOG) + return; + FileStream fs; + if (File.Exists(debugFileName)) + { + using (fs = File.OpenWrite(debugFileName)) + { + fs.SetLength(0); + } + } + else + { + fs = File.Create(debugFileName); + } + using (fs) + using (var writer = new StreamWriter(fs, Encoding.UTF8)) + { + writer.Write(content); + } + } } } diff --git a/BBDown/BBDownMuxer.cs b/BBDown/BBDownMuxer.cs index 6578f19d8..0a0899f8e 100644 --- a/BBDown/BBDownMuxer.cs +++ b/BBDown/BBDownMuxer.cs @@ -44,7 +44,7 @@ private static string EscapeString(string str) return string.IsNullOrEmpty(str) ? str : str.Replace("\"", "'").Replace("\\", "\\\\"); } - private static int MuxByMp4box(string videoPath, string audioPath, string outPath, string desc, string title, string author, string episodeId, string pic, string lang, List? subs, bool audioOnly, bool videoOnly, List? points) + private static int MuxByMp4box(string? videoPath, string? audioPath, string outPath, string? desc, string? title, string? author, string? episodeId, string? pic, string lang, List? subs, List? points) { StringBuilder inputArg = new(); StringBuilder metaArg = new(); @@ -52,7 +52,7 @@ private static int MuxByMp4box(string videoPath, string audioPath, string outPat inputArg.Append(" -inter 500 -noprog "); if (!string.IsNullOrEmpty(videoPath)) { - inputArg.Append($" -add \"{videoPath}#trackID={(audioOnly && audioPath == "" ? "2" : "1")}:name=\" "); + inputArg.Append($" -add \"{videoPath}#trackID=1:name=\" "); nowId++; } if (!string.IsNullOrEmpty(audioPath)) @@ -95,28 +95,24 @@ private static int MuxByMp4box(string videoPath, string audioPath, string outPat return RunExe(MP4BOX, arguments, MP4BOX != "mp4box"); } - public static int MuxAV(bool useMp4box, string videoPath, string audioPath, List audioMaterial, string outPath, string desc = "", string title = "", string author = "", string episodeId = "", string pic = "", string lang = "", List? subs = null, bool audioOnly = false, bool videoOnly = false, List? points = null, long pubTime = 0) + public static int MuxAV(bool useMp4box, string? videoPath, string? audioPath, List? audioMaterial, string outPath, string desc = "", string title = "", string author = "", string episodeId = "", string pic = "", string lang = "", List? subs = null, List? points = null, long pubTime = 0) { - if (audioOnly && audioPath != "") - videoPath = ""; - if (videoOnly) - audioPath = ""; desc = EscapeString(desc); title = EscapeString(title); episodeId = EscapeString(episodeId); if (useMp4box) { - return MuxByMp4box(videoPath, audioPath, outPath, desc, title, author, episodeId, pic, lang, subs, audioOnly, videoOnly, points); + return MuxByMp4box(videoPath, audioPath, outPath, desc, title, author, episodeId, pic, lang, subs, points); } - if (outPath.Contains('/') && ! Directory.Exists(Path.GetDirectoryName(outPath))) + if (outPath.Contains('/') && !Directory.Exists(Path.GetDirectoryName(outPath))) Directory.CreateDirectory(Path.GetDirectoryName(outPath)!); //----分析并生成-i参数 StringBuilder inputArg = new(); StringBuilder metaArg = new(); byte inputCount = 0; - foreach (string path in new string[] { videoPath, audioPath }) + foreach (string? path in new[] { videoPath, audioPath }) { if (!string.IsNullOrEmpty(path)) { @@ -139,12 +135,6 @@ public static int MuxAV(bool useMp4box, string videoPath, string audioPath, List } } - if (!string.IsNullOrEmpty(pic)) - { - inputCount++; - inputArg.Append($"-i \"{pic}\" "); - } - if (subs != null) { for (int i = 0; i < subs.Count; i++) @@ -153,13 +143,14 @@ public static int MuxAV(bool useMp4box, string videoPath, string audioPath, List { inputCount++; inputArg.Append($"-i \"{subs[i].path}\" "); - metaArg.Append($"-metadata:s:s:{i} title=\"{GetSubtitleCode(subs[i].lan).Item2}\" -metadata:s:s:{i} language={GetSubtitleCode(subs[i].lan).Item1} "); + metaArg.Append($"-metadata:s:s:{i} title=\"{GetSubtitleCode(subs[i].lan).Item2}\" "); + metaArg.Append($"-metadata:s:s:{i} language={GetSubtitleCode(subs[i].lan).Item1} "); } } } - if (!string.IsNullOrEmpty(pic)) - metaArg.Append($"-disposition:v:{(audioOnly ? "0" : "1")} attached_pic "); + if (pic != null) + metaArg.Append($"-disposition:v:{(videoPath == null ? "0" : "1")} attached_pic "); // var inputCount = InputRegex().Matches(inputArg.ToString()).Count; if (points != null && points.Any()) @@ -183,10 +174,10 @@ public static int MuxAV(bool useMp4box, string videoPath, string audioPath, List if (!string.IsNullOrEmpty(author)) argsBuilder.Append($"-metadata artist=\"{author}\" "); if (episodeId != "") argsBuilder.Append($"-metadata album=\"{title}\" "); if (pubTime != 0) argsBuilder.Append($"-metadata creation_time=\"{(DateTimeOffset.FromUnixTimeSeconds(pubTime).ToString("yyyy-MM-ddTHH:mm:ss.ffffffZ"))}\" "); - argsBuilder.Append("-c copy "); - if (audioOnly && audioPath == "") argsBuilder.Append("-vn "); + if (outPath.EndsWith(".mp4") || outPath.EndsWith(".m4a")) argsBuilder.Append("-c copy "); + if (videoPath == null) argsBuilder.Append("-vn "); if (subs != null) argsBuilder.Append("-c:s mov_text "); - argsBuilder.Append($"-movflags faststart -strict unofficial -strict -2 -f mp4 -- \"{outPath}\""); + argsBuilder.Append($"-movflags faststart -strict unofficial -strict -2 -- \"{outPath}\""); string arguments = argsBuilder.ToString(); diff --git a/BBDown/BBDownUtil.cs b/BBDown/BBDownUtil.cs index aca7f9530..df29afbdb 100644 --- a/BBDown/BBDownUtil.cs +++ b/BBDown/BBDownUtil.cs @@ -775,6 +775,10 @@ public static async Task CheckLogin(string cookie) } } + public static double CalculateSize(int duration, long bandwith) => duration * bandwith * 1024 / 8; + public static double CalculateSize(Video video) => video.size > 0 ? video.size : CalculateSize(video.dur, video.bandwith); + public static double CalculateSize(Audio audio) => CalculateSize(audio.dur, audio.bandwith); + [GeneratedRegex("av(\\d+)")] private static partial Regex AvRegex(); [GeneratedRegex("[Bb][Vv](\\w+)")] diff --git a/BBDown/CommandLineInvoker.cs b/BBDown/CommandLineInvoker.cs index fac5e1eac..81db61fd5 100644 --- a/BBDown/CommandLineInvoker.cs +++ b/BBDown/CommandLineInvoker.cs @@ -26,17 +26,10 @@ internal class CommandLineInvoker private readonly static Option Aria2cArgs = new(new string[] { "--aria2c-args" }, "调用aria2c的附加参数(默认参数包含\"-x16 -s16 -j16 -k 5M\", 使用时注意字符串转义)"); private readonly static Option MultiThread = new(new string[] { "--multi-thread", "-mt" }, "使用多线程下载(默认开启)"); private readonly static Option SelectPage = new(new string[] { "--select-page", "-p" }, "选择指定分p或分p范围: (-p 8 或 -p 1,2 或 -p 3-5 或 -p ALL 或 -p LAST 或 -p 3,5,LATEST)"); - private readonly static Option AudioOnly = new(new string[] { "--audio-only" }, "仅下载音频"); - private readonly static Option VideoOnly = new(new string[] { "--video-only" }, "仅下载视频"); - private readonly static Option DanmakuOnly = new(new string[] { "--danmaku-only" }, "仅下载弹幕"); - private readonly static Option CoverOnly = new(new string[] { "--cover-only" }, "仅下载封面"); - private readonly static Option SubOnly = new(new string[] { "--sub-only" }, "仅下载字幕"); + private readonly static Option DownloadOnly = new(new string[] { "--only" }, "仅下载部分内容,'a'->音频,'v'->视频,'c'->封面,‘s’->字幕,'d'->弹幕,用例: --only avsc"); private readonly static Option Debug = new(new string[] { "--debug" }, "输出调试日志"); private readonly static Option SkipMux = new(new string[] { "--skip-mux" }, "跳过混流步骤"); - private readonly static Option SkipSubtitle = new(new string[] { "--skip-subtitle" }, "跳过字幕下载"); - private readonly static Option SkipCover = new(new string[] { "--skip-cover" }, "跳过封面下载"); private readonly static Option ForceHttp = new(new string[] { "--force-http" }, "下载音视频时强制使用HTTP协议替换HTTPS(默认开启)"); - private readonly static Option DownloadDanmaku = new(new string[] { "--download-danmaku", "-dd" }, "下载弹幕"); private readonly static Option SkipAi = new(new string[] { "--skip-ai" }, description: "跳过AI字幕下载(默认开启)"); private readonly static Option VideoAscending = new(new string[] { "--video-ascending" }, "视频升序(最小体积优先)"); private readonly static Option AudioAscending = new(new string[] { "--audio-ascending" }, "音频升序(最小体积优先)"); @@ -88,17 +81,10 @@ protected override MyOption GetBoundValue(BindingContext bindingContext) if (bindingContext.ParseResult.HasOption(Interactive)) option.Interactive = bindingContext.ParseResult.GetValueForOption(Interactive)!; if (bindingContext.ParseResult.HasOption(HideStreams)) option.HideStreams = bindingContext.ParseResult.GetValueForOption(HideStreams)!; if (bindingContext.ParseResult.HasOption(MultiThread)) option.MultiThread = bindingContext.ParseResult.GetValueForOption(MultiThread)!; - if (bindingContext.ParseResult.HasOption(VideoOnly)) option.VideoOnly = bindingContext.ParseResult.GetValueForOption(VideoOnly)!; - if (bindingContext.ParseResult.HasOption(AudioOnly)) option.AudioOnly = bindingContext.ParseResult.GetValueForOption(AudioOnly)!; - if (bindingContext.ParseResult.HasOption(DanmakuOnly)) option.DanmakuOnly = bindingContext.ParseResult.GetValueForOption(DanmakuOnly)!; - if (bindingContext.ParseResult.HasOption(CoverOnly)) option.CoverOnly = bindingContext.ParseResult.GetValueForOption(CoverOnly)!; - if (bindingContext.ParseResult.HasOption(SubOnly)) option.SubOnly = bindingContext.ParseResult.GetValueForOption(SubOnly)!; + if (bindingContext.ParseResult.HasOption(DownloadOnly)) option.DownloadOnly = bindingContext.ParseResult.GetValueForOption(DownloadOnly)!; if (bindingContext.ParseResult.HasOption(Debug)) option.Debug = bindingContext.ParseResult.GetValueForOption(Debug)!; if (bindingContext.ParseResult.HasOption(SkipMux)) option.SkipMux = bindingContext.ParseResult.GetValueForOption(SkipMux)!; - if (bindingContext.ParseResult.HasOption(SkipSubtitle)) option.SkipSubtitle = bindingContext.ParseResult.GetValueForOption(SkipSubtitle)!; - if (bindingContext.ParseResult.HasOption(SkipCover)) option.SkipCover = bindingContext.ParseResult.GetValueForOption(SkipCover)!; if (bindingContext.ParseResult.HasOption(ForceHttp)) option.ForceHttp = bindingContext.ParseResult.GetValueForOption(ForceHttp)!; - if (bindingContext.ParseResult.HasOption(DownloadDanmaku)) option.DownloadDanmaku = bindingContext.ParseResult.GetValueForOption(DownloadDanmaku)!; if (bindingContext.ParseResult.HasOption(SkipAi)) option.SkipAi = bindingContext.ParseResult.GetValueForOption(SkipAi)!; if (bindingContext.ParseResult.HasOption(VideoAscending)) option.VideoAscending = bindingContext.ParseResult.GetValueForOption(VideoAscending)!; if (bindingContext.ParseResult.HasOption(AudioAscending)) option.AudioAscending = bindingContext.ParseResult.GetValueForOption(AudioAscending)!; @@ -150,17 +136,9 @@ public static RootCommand GetRootCommand(Func action) Interactive, HideStreams, MultiThread, - VideoOnly, - AudioOnly, - DanmakuOnly, - SubOnly, - CoverOnly, Debug, SkipMux, - SkipSubtitle, - SkipCover, ForceHttp, - DownloadDanmaku, SkipAi, VideoAscending, AudioAscending, @@ -168,6 +146,7 @@ public static RootCommand GetRootCommand(Func action) FilePattern, MultiFilePattern, SelectPage, + DownloadOnly, Language, UserAgent, Cookie, diff --git a/BBDown/MyOption.cs b/BBDown/MyOption.cs index f0441f3d8..05f3e06ea 100644 --- a/BBDown/MyOption.cs +++ b/BBDown/MyOption.cs @@ -15,23 +15,16 @@ internal class MyOption public bool UseMP4box { get; set; } public string? EncodingPriority { get; set; } public string? DfnPriority { get; set; } + public string DownloadOnly { get; set; } = "avsc"; public bool OnlyShowInfo { get; set; } public bool ShowAll { get; set; } public bool UseAria2c { get; set; } public bool Interactive { get; set; } public bool HideStreams { get; set; } public bool MultiThread { get; set; } = true; - public bool VideoOnly { get; set; } - public bool AudioOnly { get; set; } - public bool DanmakuOnly { get; set; } - public bool CoverOnly { get; set; } - public bool SubOnly { get; set; } public bool Debug { get; set; } public bool SkipMux { get; set; } - public bool SkipSubtitle { get; set; } - public bool SkipCover { get; set; } public bool ForceHttp { get; set; } = true; - public bool DownloadDanmaku { get; set; } = false; public bool SkipAi { get; set; } = true; public bool VideoAscending { get; set; } = false; public bool AudioAscending { get; set; } = false; diff --git a/BBDown/Program.cs b/BBDown/Program.cs index b92bf4635..1926321d1 100644 --- a/BBDown/Program.cs +++ b/BBDown/Program.cs @@ -29,8 +29,8 @@ namespace BBDown partial class Program { private static readonly string BACKUP_HOST = "upos-sz-mirrorcoso1.bilivideo.com"; - public static string SinglePageDefaultSavePath { get; set; } = ""; - public static string MultiPageDefaultSavePath { get; set; } = "/[P]"; + public static string SinglePageDefaultSavePath { get; set; } = ".mp4"; + public static string MultiPageDefaultSavePath { get; set; } = "/[P].mp4"; public readonly static string APP_DIR = Path.GetDirectoryName(Environment.ProcessPath)!; @@ -232,16 +232,14 @@ private static async Task DoWorkAsync(MyOption myOption) bool hideStreams = myOption.HideStreams; bool multiThread = myOption.MultiThread; - bool audioOnly = myOption.AudioOnly; - bool videoOnly = myOption.VideoOnly; - bool danmakuOnly = myOption.DanmakuOnly; - bool coverOnly = myOption.CoverOnly; - bool subOnly = myOption.SubOnly; bool skipMux = myOption.SkipMux; - bool skipSubtitle = myOption.SkipSubtitle; - bool skipCover = myOption.SkipCover; bool forceHttp = myOption.ForceHttp; - bool downloadDanmaku = myOption.DownloadDanmaku || danmakuOnly; + bool downloadVideo = myOption.DownloadOnly.Contains('v'); + bool downloadAudio = myOption.DownloadOnly.Contains('a'); + bool downloadCover = myOption.DownloadOnly.Contains('c'); + bool downloadDanmaku = myOption.DownloadOnly.Contains('d'); + bool downloadSubtitle = myOption.DownloadOnly.Contains('s'); + bool onlyDownloadOneItem = new[] { downloadVideo, downloadAudio, downloadCover, downloadDanmaku, downloadSubtitle }.Count(v => v) == 1; bool skipAi = myOption.SkipAi; bool videoAscending = myOption.VideoAscending; bool audioAscending = myOption.AudioAscending; @@ -263,6 +261,12 @@ private static async Task DoWorkAsync(MyOption myOption) Config.COOKIE = myOption.Cookie; Config.TOKEN = myOption.AccessToken.Replace("access_token=", ""); + if (!downloadAudio && !downloadVideo && !downloadCover && !downloadDanmaku && !downloadSubtitle) + { + LogWarn($"未选择任何下载内容,请检查{nameof(MyOption.DownloadOnly)}参数是否正确"); + return; + } + if (!string.IsNullOrEmpty(myOption.UserAgent)) HTTPUtil.UserAgent = myOption.UserAgent; //优先使用用户设置的UA if (interactMode) hideStreams = false; //手动选择时不能隐藏流 @@ -330,17 +334,6 @@ private static async Task DoWorkAsync(MyOption myOption) } - - //audioOnly和videoOnly同时开启则全部忽视 - if (audioOnly && videoOnly) - { - audioOnly = false; - videoOnly = false; - } - - if (skipSubtitle) - subOnly = false; - LogDebug("AppDirectory: {0}", APP_DIR); LogDebug("运行参数:{0}", JsonSerializer.Serialize(myOption, MyOptionJsonContext.Default.MyOption)); if (string.IsNullOrEmpty(Config.COOKIE) && File.Exists(Path.Combine(APP_DIR, "BBDown.data"))) @@ -490,13 +483,16 @@ private static async Task DoWorkAsync(MyOption myOption) if (selectedPages != null) pagesInfo = pagesInfo.Where(p => selectedPages.Contains(p.index.ToString())).ToList(); - // 根据p数选择存储路径 - savePathFormat = string.IsNullOrEmpty(myOption.FilePattern) ? SinglePageDefaultSavePath : myOption.FilePattern; + // 设置文件保存格式 // 1. 多P; 2. 只有1P, 但是是番剧, 尚未完结时 按照多P处理 if (pagesCount > 1 || (bangumi && !vInfo.IsBangumiEnd)) { savePathFormat = string.IsNullOrEmpty(myOption.MultiFilePattern) ? MultiPageDefaultSavePath : myOption.MultiFilePattern; } + else // 单P + { + savePathFormat = string.IsNullOrEmpty(myOption.FilePattern) ? SinglePageDefaultSavePath : myOption.FilePattern; + } foreach (Page p in pagesInfo) { @@ -529,9 +525,16 @@ private static async Task DoWorkAsync(MyOption myOption) List audioMaterial = new(); List points = new(); + // 准备缓存文件夹 string videoPath = $"{p.aid}/{p.aid}.P{p.index}.{p.cid}.mp4"; string audioPath = $"{p.aid}/{p.aid}.P{p.index}.{p.cid}.m4a"; var coverPath = $"{p.aid}/{p.aid}.jpg"; + foreach (var path in new []{ videoPath, audioPath, coverPath }) + { + var directory = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + Directory.CreateDirectory(directory); + } //处理文件夹以.结尾导致的异常情况 if (title.EndsWith(".")) title += "_fix"; @@ -541,16 +544,20 @@ private static async Task DoWorkAsync(MyOption myOption) //处理封面&&字幕 if (!infoMode) { - if (!Directory.Exists(p.aid)) + if (downloadCover && !File.Exists(coverPath)) { - Directory.CreateDirectory(p.aid); - } - if (!skipCover && !subOnly && !File.Exists(coverPath) && !danmakuOnly && !coverOnly) - { - await DownloadFile((pic == "" ? p.cover : pic), coverPath, useAria2c, aria2cArgs); + await DownloadFile(pic == "" ? p.cover : pic, coverPath, useAria2c, aria2cArgs); + if (onlyDownloadOneItem) + { + var savePath = FormatSavePath(savePathFormat, title, null, null, p, pagesCount, tvApi, appApi, intlApi, pubTime); + // 理论上来讲这里还需要转码 + File.Move(coverPath, savePath); + if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0) Directory.Delete(p.aid, true); + continue; + } } - if (!skipSubtitle && !danmakuOnly && !coverOnly) + if (downloadSubtitle) { LogDebug("获取字幕..."); subtitleInfo = await SubUtil.GetSubtitlesAsync(p.aid, p.cid, p.epid, p.index, intlApi); @@ -564,7 +571,7 @@ private static async Task DoWorkAsync(MyOption myOption) Log($"下载字幕 {s.lan} => {SubUtil.GetSubtitleCode(s.lan).Item2}..."); LogDebug("下载:{0}", s.url); await SubUtil.SaveSubtitleAsync(s.url, s.path); - if (subOnly && File.Exists(s.path) && File.ReadAllText(s.path) != "") + if (onlyDownloadOneItem && File.Exists(s.path) && File.ReadAllText(s.path) != "") { var _outSubPath = FormatSavePath(savePathFormat, title, null, null, p, pagesCount, tvApi, appApi, intlApi, pubTime); if (_outSubPath.Contains('/')) @@ -574,42 +581,38 @@ private static async Task DoWorkAsync(MyOption myOption) } _outSubPath = _outSubPath[.._outSubPath.LastIndexOf('.')] + $".{s.lan}.srt"; File.Move(s.path, _outSubPath, true); + if (onlyDownloadOneItem) + { + if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0) Directory.Delete(p.aid, true); + continue; + } } } } - - if (subOnly) - { - if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0) Directory.Delete(p.aid, true); - continue; - } } //调用解析 (webJsonStr, videoTracks, audioTracks, clips, dfns, backgroundAudioTracks, roleAudioList, points) = await ExtractTracksAsync(aidOri, p.aid, p.cid, p.epid, tvApi, intlApi, appApi, firstEncoding); if (!p.points.Any()) p.points = points; - if (Config.DEBUG_LOG) - File.WriteAllText($"debug.json", webJsonStr); - - var savePath = ""; + Logger.WriteDebugFile(webJsonStr); //此处代码简直灾难, 后续优化吧 if ((videoTracks.Count != 0 || audioTracks.Count != 0) && clips.Count == 0) //dash { if (webJsonStr.Contains("\"video\":[") && videoTracks.Count == 0) { - LogError("没有找到符合要求的视频流"); - if (!audioOnly) continue; + LogWarn("没有找到符合要求的视频流"); + if (downloadVideo) continue; } if (webJsonStr.Contains("\"audio\":[") && audioTracks.Count == 0) { - LogError("没有找到符合要求的音频流"); - if (!videoOnly) continue; + LogWarn("没有找到符合要求的音频流"); + if (downloadAudio) continue; } - if (audioOnly) videoTracks.Clear(); - if (videoOnly) + if (!downloadVideo) videoTracks.Clear(); + if (!downloadAudio) { audioTracks.Clear(); backgroundAudioTracks.Clear(); @@ -676,6 +679,7 @@ private static async Task DoWorkAsync(MyOption myOption) if (infoMode) continue; // 为什么选择轨道要放在下载后面 + // 没有吧前面不是获取轨道嘛 if (interactMode && !selected) { if (videoTracks.Any()) @@ -698,7 +702,7 @@ private static async Task DoWorkAsync(MyOption myOption) } LogDebug("Format Before: " + savePathFormat); - savePath = FormatSavePath(savePathFormat, title, videoTracks.ElementAtOrDefault(vIndex), audioTracks.ElementAtOrDefault(aIndex), p, pagesCount, tvApi, appApi, intlApi, pubTime); + var savePath = FormatSavePath(savePathFormat, title, videoTracks.ElementAtOrDefault(vIndex), audioTracks.ElementAtOrDefault(aIndex), p, pagesCount, tvApi, appApi, intlApi, pubTime); LogDebug("Format After: " + savePath); if (downloadDanmaku) @@ -719,32 +723,28 @@ private static async Task DoWorkAsync(MyOption myOption) Log("弹幕Xml解析失败, 删除Xml..."); File.Delete(danmakuXmlPath); } - if (danmakuOnly) - { - if (Directory.Exists(p.aid)) - { - Directory.Delete(p.aid); - } + if (downloadDanmaku && onlyDownloadOneItem) continue; - } } - if (coverOnly) + // 前面不是下载过了吗?! + if (downloadCover && onlyDownloadOneItem) { var newCoverPath = savePath[..savePath.LastIndexOf('.')] + Path.GetExtension(pic); - await DownloadFile((pic == "" ? p.cover : pic), newCoverPath, useAria2c, aria2cArgs); - if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0) Directory.Delete(p.aid, true); + File.Move(coverPath, newCoverPath); + if (Directory.Exists(p.aid) && Directory.GetFiles(p.aid).Length == 0) + Directory.Delete(p.aid, true); continue; } Log($"已选择的流:"); if (videoTracks.Any()) { - var size = videoTracks[vIndex].size > 0 ? videoTracks[vIndex].size : videoTracks[vIndex].dur * videoTracks[vIndex].bandwith * 1024 / 8; + var size = CalculateSize(videoTracks[vIndex]); LogColor($"[视频] [{videoTracks[vIndex].dfn}] [{videoTracks[vIndex].res}] [{videoTracks[vIndex].codecs}] [{videoTracks[vIndex].fps}] [{videoTracks[vIndex].bandwith} kbps] [~{FormatFileSize(size)}]".Replace("[] ", ""), false); } if (audioTracks.Any()) - LogColor($"[音频] [{audioTracks[aIndex].codecs}] [{audioTracks[aIndex].bandwith} kbps] [~{FormatFileSize(audioTracks[aIndex].dur * audioTracks[aIndex].bandwith * 1024 / 8)}]", false); + LogColor($"[音频] [{audioTracks[aIndex].codecs}] [{audioTracks[aIndex].bandwith} kbps] [~{FormatFileSize(CalculateSize(audioTracks[aIndex]))}]", false); //用户开启了强制替换 if (myOption.ForceReplaceHost) @@ -797,7 +797,7 @@ private static async Task DoWorkAsync(MyOption myOption) if (videoTracks.Any()) { - if (!infoMode && File.Exists(savePath) && new FileInfo(savePath).Length != 0) + if (File.Exists(savePath) && new FileInfo(savePath).Length != 0) { Log($"{savePath}已存在, 跳过下载..."); File.Delete(coverPath); @@ -900,22 +900,24 @@ private static async Task DoWorkAsync(MyOption myOption) if (audioTracks.Count == 0) audioPath = ""; if (skipMux) continue; Log($"开始合并音视频{(subtitleInfo.Any() ? "和字幕" : "")}..."); - if (audioOnly) - savePath = savePath[..^4] + ".m4a"; - int code = MuxAV(useMp4box, videoPath, audioPath, audioMaterial, savePath, + int code = MuxAV(useMp4box, + downloadVideo ? videoPath : null, + downloadAudio ? audioPath : null, + audioMaterial, + savePath, desc, title, p.ownerName ?? "", (pagesCount > 1 || (bangumi && !vInfo.IsBangumiEnd)) ? p.title : "", - File.Exists(coverPath) ? coverPath : "", + downloadCover ? coverPath : null, lang, - subtitleInfo, audioOnly, videoOnly, p.points, p.pubTime); + subtitleInfo, p.points, p.pubTime); if (code != 0 || !File.Exists(savePath) || new FileInfo(savePath).Length == 0) { LogError("合并失败"); continue; } Log("清理临时文件..."); - Thread.Sleep(200); + await Task.Delay(200); if (videoTracks.Any()) File.Delete(videoPath); if (audioTracks.Any()) File.Delete(audioPath); if (p.points.Any()) File.Delete(Path.Combine(Path.GetDirectoryName(string.IsNullOrEmpty(videoPath) ? audioPath : videoPath)!, "chapters")); @@ -962,7 +964,7 @@ private static async Task DoWorkAsync(MyOption myOption) } } if (infoMode) continue; - savePath = FormatSavePath(savePathFormat, title, videoTracks.ElementAtOrDefault(vIndex), null, p, pagesCount, tvApi, appApi, intlApi, pubTime); + var savePath = FormatSavePath(savePathFormat, title, videoTracks.ElementAtOrDefault(vIndex), null, p, pagesCount, tvApi, appApi, intlApi, pubTime); if (File.Exists(savePath) && new FileInfo(savePath).Length != 0) { Log($"{savePath}已存在, 跳过下载..."); @@ -1012,16 +1014,18 @@ private static async Task DoWorkAsync(MyOption myOption) MergeFLV(files, videoPath); if (skipMux) continue; Log($"开始混流视频{(subtitleInfo.Any() ? "和字幕" : "")}..."); - if (audioOnly) - savePath = savePath[..^4] + ".m4a"; - int code = MuxAV(false, videoPath, "", audioMaterial, savePath, + int code = MuxAV(false, + downloadVideo ? videoPath : null, + null, + audioMaterial, + savePath, desc, title, p.ownerName ?? "", (pagesCount > 1 || (bangumi && !vInfo.IsBangumiEnd)) ? p.title : "", File.Exists(coverPath) ? coverPath : "", lang, - subtitleInfo, audioOnly, videoOnly, p.points, p.pubTime); + subtitleInfo, p.points, p.pubTime); if (code != 0 || !File.Exists(savePath) || new FileInfo(savePath).Length == 0) { LogError("合并失败"); continue; @@ -1131,7 +1135,7 @@ private static string FormatSavePath(string savePathFormat, string title, Video? }; result = result.Replace(m.Value, v); } - if (!result.EndsWith(".mp4")) { result += ".mp4"; } + // if (!result.EndsWith(".mp4")) { result += ".mp4"; } return result; }