允许实时调用mp4decrpyt解密
This commit is contained in:
parent
306eff7079
commit
495d8508f5
|
@ -170,6 +170,15 @@ namespace N_m3u8DL_RE.Common.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Decrypt MP4 segments in real time 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string cmd_MP4RealTimeDecryption {
|
||||
get {
|
||||
return ResourceManager.GetString("cmd_MP4RealTimeDecryption", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Set output directory 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
@ -237,4 +237,7 @@
|
|||
<data name="cmd_urlProcessorArgs" xml:space="preserve">
|
||||
<value>Give these arguments to the URL Processors.</value>
|
||||
</data>
|
||||
<data name="cmd_MP4RealTimeDecryption" xml:space="preserve">
|
||||
<value>Decrypt MP4 segments in real time</value>
|
||||
</data>
|
||||
</root>
|
|
@ -257,4 +257,7 @@
|
|||
<data name="cmd_urlProcessorArgs" xml:space="preserve">
|
||||
<value>此字符串将直接传递给URL Processor</value>
|
||||
</data>
|
||||
<data name="cmd_MP4RealTimeDecryption" xml:space="preserve">
|
||||
<value>实时解密MP4分片</value>
|
||||
</data>
|
||||
</root>
|
|
@ -234,4 +234,7 @@
|
|||
<data name="cmd_urlProcessorArgs" xml:space="preserve">
|
||||
<value>此字符串將直接傳遞給URL Processor</value>
|
||||
</data>
|
||||
<data name="cmd_MP4RealTimeDecryption" xml:space="preserve">
|
||||
<value>實時解密MP4分片</value>
|
||||
</data>
|
||||
</root>
|
|
@ -12,8 +12,8 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
{
|
||||
private readonly static Argument<string> Input = new(name: "input", description: ResString.cmd_Input);
|
||||
private readonly static Option<string?> TmpDir = new(new string[] { "--tmp-dir" }, description: ResString.cmd_tmpDir);
|
||||
private readonly static Option<string?> SaveDir = new(new string[] { "--save-dir", "-o" }, description: ResString.cmd_saveDir);
|
||||
private readonly static Option<string?> SaveName = new(new string[] { "--save-name", "-O" }, description: ResString.cmd_saveName);
|
||||
private readonly static Option<string?> SaveDir = new(new string[] { "--save-dir" }, description: ResString.cmd_saveDir);
|
||||
private readonly static Option<string?> SaveName = new(new string[] { "--save-name" }, description: ResString.cmd_saveName);
|
||||
private readonly static Option<string?> SavePattern = new(new string[] { "--save-pattern" }, description: ResString.cmd_savePattern, getDefaultValue: () => "<SaveName>_<Id>_<Codecs>_<Language>_<Ext>");
|
||||
private readonly static Option<string?> UILanguage = new(new string[] { "--ui-language" }, description: ResString.cmd_uiLanguage);
|
||||
private readonly static Option<string?> UrlProcessorArgs = new(new string[] { "--urlprocessor-args" }, description: ResString.cmd_urlProcessorArgs);
|
||||
|
@ -32,6 +32,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
private readonly static Option<bool> CheckSegmentsCount = new(new string[] { "--check-segments-count" }, description: ResString.cmd_checkSegmentsCount, getDefaultValue: () => true);
|
||||
private readonly static Option<bool> WriteMetaJson = new(new string[] { "--write-meta-json" }, description: ResString.cmd_writeMetaJson, getDefaultValue: () => true);
|
||||
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
||||
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
||||
|
||||
class MyOptionBinder : BinderBase<MyOption>
|
||||
{
|
||||
|
@ -61,6 +62,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
SavePattern = bindingContext.ParseResult.GetValueForOption(SavePattern),
|
||||
Keys = bindingContext.ParseResult.GetValueForOption(Keys),
|
||||
UrlProcessorArgs = bindingContext.ParseResult.GetValueForOption(UrlProcessorArgs),
|
||||
MP4RealTimeDecryption = bindingContext.ParseResult.GetValueForOption(MP4RealTimeDecryption),
|
||||
};
|
||||
|
||||
//在这里设置语言
|
||||
|
@ -85,11 +87,11 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
|
||||
public static async Task<int> InvokeArgs(string[] args, Func<MyOption, Task> action)
|
||||
{
|
||||
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220721")
|
||||
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220723")
|
||||
{
|
||||
Input, TmpDir, SaveDir, SaveName, ThreadCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
||||
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Keys, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
||||
LogLevel, UILanguage, UrlProcessorArgs
|
||||
LogLevel, UILanguage, UrlProcessorArgs, MP4RealTimeDecryption
|
||||
};
|
||||
rootCommand.TreatUnmatchedTokensAsErrors = true;
|
||||
rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder());
|
||||
|
|
|
@ -70,6 +70,10 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
/// </summary>
|
||||
public bool AppendUrlParams { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.MP4RealTimeDecryption"/>.
|
||||
/// </summary>
|
||||
public bool MP4RealTimeDecryption { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.SubtitleFormat"/>.
|
||||
/// </summary>
|
||||
public SubtitleFormat SubtitleFormat { get; set; }
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace N_m3u8DL_RE.Config
|
|||
ThreadCount = option.ThreadCount;
|
||||
SavePattern = option.SavePattern;
|
||||
Keys = option.Keys;
|
||||
MP4RealTimeDecryption = option.MP4RealTimeDecryption;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -74,6 +75,10 @@ namespace N_m3u8DL_RE.Config
|
|||
/// </summary>
|
||||
public bool AutoSubtitleFix { get; set; } = true;
|
||||
/// <summary>
|
||||
/// MP4实时解密
|
||||
/// </summary>
|
||||
public bool MP4RealTimeDecryption { get; set; } = true;
|
||||
/// <summary>
|
||||
/// 字幕格式
|
||||
/// </summary>
|
||||
public SubtitleFormat SubtitleFormat { get; set; } = SubtitleFormat.VTT;
|
||||
|
|
|
@ -51,6 +51,15 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
var headers = DownloaderConfig.Headers;
|
||||
var output = Path.Combine(saveDir, saveName + $".{streamSpec.Extension ?? "ts"}");
|
||||
|
||||
//mp4decrypt
|
||||
var APP_DIR = Path.GetDirectoryName(Environment.ProcessPath)!;
|
||||
var fileName = "mp4decrypt";
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
fileName += ".exe";
|
||||
var mp4decrypt = Path.Combine(APP_DIR, fileName);
|
||||
if (!File.Exists(mp4decrypt)) mp4decrypt = fileName;
|
||||
var mp4InitFile = "";
|
||||
|
||||
Logger.Debug($"dirName: {dirName}; tmpDir: {tmpDir}; saveDir: {saveDir}; saveName: {saveName}; output: {output}");
|
||||
|
||||
//创建文件夹
|
||||
|
@ -76,12 +85,20 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
var path = Path.Combine(tmpDir, "_init.mp4.tmp");
|
||||
var result = await Downloader.DownloadSegmentAsync(streamSpec.Playlist.MediaInit, path, headers);
|
||||
FileDic[streamSpec.Playlist.MediaInit] = result;
|
||||
if (result == null)
|
||||
{
|
||||
throw new Exception("Download init file failed!");
|
||||
}
|
||||
mp4InitFile = result.ActualFilePath;
|
||||
task.Increment(1);
|
||||
|
||||
//修改输出后缀
|
||||
if (streamSpec.MediaType == Common.Enum.MediaType.AUDIO)
|
||||
output = Path.ChangeExtension(output, ".m4a");
|
||||
else
|
||||
output = Path.ChangeExtension(output, ".mp4");
|
||||
|
||||
//读取mp4信息
|
||||
if (result != null && result.Success)
|
||||
{
|
||||
var data = File.ReadAllBytes(result.ActualFilePath);
|
||||
|
@ -89,6 +106,17 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
if (info.Scheme != null) Logger.WarnMarkUp($"[grey]Type: {info.Scheme}[/]");
|
||||
if (info.PSSH != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {info.PSSH}[/]");
|
||||
if (info.KID != null) Logger.WarnMarkUp($"[grey]KID: {info.KID}[/]");
|
||||
//实时解密
|
||||
if (DownloaderConfig.MP4RealTimeDecryption && streamSpec.Playlist.MediaInit.EncryptInfo.Method != Common.Enum.EncryptMethod.NONE)
|
||||
{
|
||||
var enc = result.ActualFilePath;
|
||||
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
|
||||
var dResult = await MP4DecryptUtil.DecryptAsync(mp4decrypt, DownloaderConfig.Keys, enc, dec);
|
||||
if (dResult)
|
||||
{
|
||||
result.ActualFilePath = dec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,8 +133,25 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
var result = await Downloader.DownloadSegmentAsync(seg, path, headers);
|
||||
FileDic[seg] = result;
|
||||
task.Increment(1);
|
||||
//实时解密
|
||||
if (DownloaderConfig.MP4RealTimeDecryption && seg.EncryptInfo.Method != Common.Enum.EncryptMethod.NONE && result != null)
|
||||
{
|
||||
var enc = result.ActualFilePath;
|
||||
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
|
||||
var dResult = await MP4DecryptUtil.DecryptAsync(mp4decrypt, DownloaderConfig.Keys, enc, dec, mp4InitFile);
|
||||
if (dResult)
|
||||
{
|
||||
File.Delete(enc);
|
||||
result.ActualFilePath = dec;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (DownloaderConfig.MP4RealTimeDecryption && mp4InitFile != "")
|
||||
{
|
||||
File.Delete(mp4InitFile);
|
||||
}
|
||||
|
||||
//校验分片数量
|
||||
if (DownloaderConfig.CheckSegmentsCount && FileDic.Values.Any(s => s == null))
|
||||
{
|
||||
|
@ -313,30 +358,16 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
}
|
||||
}
|
||||
|
||||
if (DownloaderConfig.Keys != null && DownloaderConfig.Keys.Length > 0)
|
||||
//调用mp4decrypt解密
|
||||
if (!DownloaderConfig.MP4RealTimeDecryption && DownloaderConfig.Keys != null && DownloaderConfig.Keys.Length > 0)
|
||||
{
|
||||
var APP_DIR = Path.GetDirectoryName(Environment.ProcessPath)!;
|
||||
var fileName = "mp4decrypt";
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
fileName += ".exe";
|
||||
var mp4decrypt = Path.Combine(APP_DIR, fileName);
|
||||
if (!File.Exists(mp4decrypt)) mp4decrypt = fileName;
|
||||
if (streamSpec.Playlist!.MediaParts.First().MediaSegments.First().EncryptInfo != null
|
||||
&& streamSpec.Playlist!.MediaParts.First().MediaSegments.First().EncryptInfo.Method != Common.Enum.EncryptMethod.NONE)
|
||||
if (totalCount > 1 && streamSpec.Playlist!.MediaParts.First().MediaSegments.First().EncryptInfo.Method != Common.Enum.EncryptMethod.NONE)
|
||||
{
|
||||
var enc = output;
|
||||
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
|
||||
var cmd = string.Join(" ", DownloaderConfig.Keys.Select(k => $"--key {k}")) + $" \"{enc}\" \"{dec}\"";
|
||||
Logger.InfoMarkUp($"[grey]Decrypting...[/]");
|
||||
await Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = mp4decrypt,
|
||||
Arguments = cmd,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
})!.WaitForExitAsync();
|
||||
if (File.Exists(dec) && new FileInfo(dec).Length > 0)
|
||||
var result = await MP4DecryptUtil.DecryptAsync(mp4decrypt, DownloaderConfig.Keys, enc, dec);
|
||||
if (result)
|
||||
{
|
||||
File.Delete(enc);
|
||||
output = dec;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using N_m3u8DL_RE.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace N_m3u8DL_RE.Util
|
||||
{
|
||||
internal class MP4DecryptUtil
|
||||
{
|
||||
public static async Task<bool> DecryptAsync(string bin, string[]? keys, string source, string dest, string init = "")
|
||||
{
|
||||
if (keys == null || keys.Length == 0) return false;
|
||||
|
||||
var cmd = string.Join(" ", keys.Select(k => $"--key {k}"));
|
||||
if (init != "")
|
||||
{
|
||||
cmd += $" --fragments-info \"{init}\" ";
|
||||
}
|
||||
cmd += $" \"{source}\" \"{dest}\"";
|
||||
|
||||
await Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = bin,
|
||||
Arguments = cmd,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
})!.WaitForExitAsync();
|
||||
|
||||
if (File.Exists(dest) && new FileInfo(dest).Length > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue