diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs b/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs index aed0669..64017c1 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs @@ -188,6 +188,15 @@ namespace N_m3u8DL_RE.Common.Resource { } } + /// + /// 查找类似 Set the kid-key file, the program will search the KEY with KID from the file.(Very large file are not recommended) 的本地化字符串。 + /// + public static string cmd_keyText { + get { + return ResourceManager.GetString("cmd_keyText", resourceCulture); + } + } + /// /// 查找类似 Failed to get KEY, ignore. 的本地化字符串。 /// @@ -494,6 +503,15 @@ namespace N_m3u8DL_RE.Common.Resource { } } + /// + /// 查找类似 Trying to search for KEY from text file... 的本地化字符串。 + /// + public static string searchKey { + get { + return ResourceManager.GetString("searchKey", resourceCulture); + } + } + /// /// 查找类似 Segment count check not pass, total: {}, downloaded: {}. 的本地化字符串。 /// diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.resx b/src/N_m3u8DL-RE.Common/Resource/ResString.resx index 2e06829..59b6000 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.resx @@ -258,4 +258,10 @@ ffmpeg merging... + + Set the kid-key file, the program will search the KEY with KID from the file.(Very large file are not recommended) + + + Trying to search for KEY from text file... + \ No newline at end of file diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx index f86d071..aad8e88 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx @@ -278,4 +278,10 @@ 调用ffmpeg合并中... + + 设置密钥文件,程序将从文件中按KID搜寻KEY以解密.(不建议使用特大文件) + + + 正在尝试从文本文件搜索KEY... + \ No newline at end of file diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx index adbd381..57d407f 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx @@ -255,4 +255,10 @@ 調用ffmpeg合併中... + + 設置密鑰文件,程序將從文件中按KID搜尋KEY以解密.(不建議使用特大文件) + + + 正在嘗試從文本文件搜尋KEY... + \ No newline at end of file diff --git a/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs b/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs index 2510f47..e651b05 100644 --- a/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs +++ b/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs @@ -18,6 +18,7 @@ namespace N_m3u8DL_RE.CommandLine private readonly static Option UILanguage = new(new string[] { "--ui-language" }, description: ResString.cmd_uiLanguage); private readonly static Option UrlProcessorArgs = new(new string[] { "--urlprocessor-args" }, description: ResString.cmd_urlProcessorArgs); private readonly static Option Keys = new(new string[] { "--key" }, description: ResString.cmd_keys) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false }; + private readonly static Option KeyTextFile = new(new string[] { "--key-text-file" }, description: ResString.cmd_keyText); private readonly static Option Headers = new(new string[] { "-H", "--header" }, description: ResString.cmd_header) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false }; private readonly static Option LogLevel = new(name: "--log-level", description: ResString.cmd_logLevel, getDefaultValue: () => Common.Log.LogLevel.INFO); private readonly static Option SubtitleFormat = new(name: "--sub-format", description: ResString.cmd_subFormat, getDefaultValue: () => Enum.SubtitleFormat.VTT); @@ -69,6 +70,7 @@ namespace N_m3u8DL_RE.CommandLine UseShakaPackager = bindingContext.ParseResult.GetValueForOption(UseShakaPackager), DecryptionBinaryPath = bindingContext.ParseResult.GetValueForOption(DecryptionBinaryPath), FFmpegBinaryPath = bindingContext.ParseResult.GetValueForOption(FFmpegBinaryPath), + KeyTextFile = bindingContext.ParseResult.GetValueForOption(KeyTextFile), }; //在这里设置语言 @@ -93,12 +95,12 @@ namespace N_m3u8DL_RE.CommandLine public static async Task InvokeArgs(string[] args, Func action) { - var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220808") + var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220811") { Input, TmpDir, SaveDir, SaveName, ThreadCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount, BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix, FFmpegBinaryPath, - LogLevel, UILanguage, UrlProcessorArgs, Keys, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption + LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption }; rootCommand.TreatUnmatchedTokensAsErrors = true; rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder()); diff --git a/src/N_m3u8DL-RE/CommandLine/MyOption.cs b/src/N_m3u8DL-RE/CommandLine/MyOption.cs index 9e37bae..93a6685 100644 --- a/src/N_m3u8DL-RE/CommandLine/MyOption.cs +++ b/src/N_m3u8DL-RE/CommandLine/MyOption.cs @@ -18,6 +18,10 @@ namespace N_m3u8DL_RE.CommandLine /// public string[]? Keys { get; set; } /// + /// See: . + /// + public string? KeyTextFile { get; set; } + /// /// See: . /// public string? UrlProcessorArgs { get; set; } diff --git a/src/N_m3u8DL-RE/Config/DownloaderConfig.cs b/src/N_m3u8DL-RE/Config/DownloaderConfig.cs index 290f9de..fba4eb4 100644 --- a/src/N_m3u8DL-RE/Config/DownloaderConfig.cs +++ b/src/N_m3u8DL-RE/Config/DownloaderConfig.cs @@ -31,6 +31,7 @@ namespace N_m3u8DL_RE.Config UseShakaPackager = option.UseShakaPackager; DecryptionBinaryPath = option.DecryptionBinaryPath; FFmpegBinaryPath = option.FFmpegBinaryPath; + KeyTextFile = option.KeyTextFile; } /// @@ -105,6 +106,10 @@ namespace N_m3u8DL_RE.Config /// public string[]? Keys { get; set; } /// + /// KID-KEY文件 + /// + public string? KeyTextFile { get; set; } + /// /// ffmpeg路径 /// public string? FFmpegBinaryPath { get; set; } diff --git a/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs b/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs index 0306248..a1797d9 100644 --- a/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs +++ b/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs @@ -105,6 +105,15 @@ namespace N_m3u8DL_RE.DownloadManager { var data = File.ReadAllBytes(result.ActualFilePath); currentKID = ReadInit(data); + //从文件读取KEY + var _key = await MP4DecryptUtil.SearchKeyFromFile(DownloaderConfig.KeyTextFile, currentKID); + if (_key != null) + { + if (DownloaderConfig.Keys == null) + DownloaderConfig.Keys = new string[] { _key }; + else + DownloaderConfig.Keys = DownloaderConfig.Keys.Concat(new string[] { _key }).ToArray(); + } //实时解密 if (DownloaderConfig.MP4RealTimeDecryption && streamSpec.Playlist.MediaInit.EncryptInfo.Method != Common.Enum.EncryptMethod.NONE) { @@ -387,6 +396,15 @@ namespace N_m3u8DL_RE.DownloadManager var header = new byte[4096]; //4KB fs.Read(header); currentKID = ReadInit(header); + //从文件读取KEY + var _key = await MP4DecryptUtil.SearchKeyFromFile(DownloaderConfig.KeyTextFile, currentKID); + if (_key != null) + { + if (DownloaderConfig.Keys == null) + DownloaderConfig.Keys = new string[] { _key }; + else + DownloaderConfig.Keys = DownloaderConfig.Keys.Concat(new string[] { _key }).ToArray(); + } } } var enc = output; diff --git a/src/N_m3u8DL-RE/Program.cs b/src/N_m3u8DL-RE/Program.cs index de8ff25..bfe87dc 100644 --- a/src/N_m3u8DL-RE/Program.cs +++ b/src/N_m3u8DL-RE/Program.cs @@ -49,7 +49,7 @@ namespace N_m3u8DL_RE } //预先检查 - if (option.Keys != null && option.Keys.Length > 0) + if ((option.Keys != null && option.Keys.Length > 0) || option.KeyTextFile != null) { if (string.IsNullOrEmpty(option.DecryptionBinaryPath)) { diff --git a/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs b/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs index 1676acc..218f7ad 100644 --- a/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs +++ b/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs @@ -1,4 +1,7 @@ -using System.Diagnostics; +using N_m3u8DL_RE.Common.Log; +using N_m3u8DL_RE.Common.Resource; +using N_m3u8DL_RE.Config; +using System.Diagnostics; namespace N_m3u8DL_RE.Util { @@ -60,6 +63,8 @@ namespace N_m3u8DL_RE.Util private static async Task RunCommandAsync(string name, string arg) { + Logger.DebugMarkUp($"FileName: {name}"); + Logger.DebugMarkUp($"Arguments: {arg}"); await Process.Start(new ProcessStartInfo() { FileName = name, @@ -69,5 +74,32 @@ namespace N_m3u8DL_RE.Util UseShellExecute = false })!.WaitForExitAsync(); } + + public static async Task SearchKeyFromFile(string? file, string? kid) + { + try + { + if (string.IsNullOrEmpty(file) || !File.Exists(file) || string.IsNullOrEmpty(kid)) + return null; + + Logger.InfoMarkUp(ResString.searchKey); + using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var reader = new StreamReader(stream); + var line = ""; + while (!string.IsNullOrEmpty(line = await reader.ReadLineAsync())) + { + if (line.Trim().StartsWith(kid)) + { + Logger.InfoMarkUp($"[green]OK[/] [grey]{line.Trim()}[/]"); + return line.Trim(); + } + } + } + catch (Exception ex) + { + Logger.ErrorMarkUp(ex.Message); + } + return null; + } } }