From 47df7cb838ec3f9d8f024391770dad1d78df5712 Mon Sep 17 00:00:00 2001 From: nilaoda Date: Sat, 23 Jul 2022 03:25:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`--urlprocessor-args`?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=B0=86=E5=8F=82=E6=95=B0=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=E5=88=B0URL=E5=A4=84=E7=90=86=E5=99=A8=E4=B8=AD;=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0CENC=E5=8A=A0=E5=AF=86=E6=96=B9=E5=BC=8F=E8=AF=86?= =?UTF-8?q?=E5=88=AB;=E5=A2=9E=E5=8A=A0`nowehoryzonty.pl`=E7=BD=91?= =?UTF-8?q?=E7=AB=99=E5=8F=82=E6=95=B0=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/N_m3u8DL-RE.Common/Enum/EncryptMethod.cs | 1 + .../Resource/ResString.Designer.cs | 9 + .../Resource/ResString.resx | 3 + .../Resource/ResString.zh-Hans.resx | 3 + .../Resource/ResString.zh-Hant.resx | 3 + src/N_m3u8DL-RE.Parser/Config/ParserConfig.cs | 5 + .../Extractor/DASHExtractor2.cs | 45 +++- src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs | 85 ++++--- src/N_m3u8DL-RE.Parser/Util/ParserUtil.cs | 2 +- src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs | 4 +- src/N_m3u8DL-RE/CommandLine/MyOption.cs | 4 + .../DownloadManager/SimpleDownloadManager.cs | 8 +- src/N_m3u8DL-RE/N_m3u8DL-RE.csproj | 1 + .../Processor/NowehoryzontyUrlProcessor.cs | 224 ++++++++++++++++++ src/N_m3u8DL-RE/Program.cs | 5 +- src/N_m3u8DL-RE/rd.xml | 1 + 16 files changed, 346 insertions(+), 57 deletions(-) create mode 100644 src/N_m3u8DL-RE/Processor/NowehoryzontyUrlProcessor.cs diff --git a/src/N_m3u8DL-RE.Common/Enum/EncryptMethod.cs b/src/N_m3u8DL-RE.Common/Enum/EncryptMethod.cs index 9dc0789..319a466 100644 --- a/src/N_m3u8DL-RE.Common/Enum/EncryptMethod.cs +++ b/src/N_m3u8DL-RE.Common/Enum/EncryptMethod.cs @@ -13,6 +13,7 @@ namespace N_m3u8DL_RE.Common.Enum AES_128_ECB, SAMPLE_AES, SAMPLE_AES_CTR, + CENC, CHACHA20, UNKNOWN } diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs b/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs index 033d504..87aa6af 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.Designer.cs @@ -269,6 +269,15 @@ namespace N_m3u8DL_RE.Common.Resource { } } + /// + /// 查找类似 Give these arguments to the URL Processors. 的本地化字符串。 + /// + public static string cmd_urlProcessorArgs { + get { + return ResourceManager.GetString("cmd_urlProcessorArgs", resourceCulture); + } + } + /// /// 查找类似 Write meta json after parsed 的本地化字符串。 /// diff --git a/src/N_m3u8DL-RE.Common/Resource/ResString.resx b/src/N_m3u8DL-RE.Common/Resource/ResString.resx index 3706635..757f282 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.resx @@ -234,4 +234,7 @@ Pass decryption key(s) to mp4decrypt. format: --key KID1:KEY1 --key KID2:KEY2 + + Give these arguments to the URL Processors. + \ 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 651e5c2..67bac30 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hans.resx @@ -254,4 +254,7 @@ 设置解密密钥, 程序调用mp4decrpyt进行解密. 格式: --key KID1:KEY1 --key KID2:KEY2 + + 此字符串将直接传递给URL Processor + \ 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 a38ffbe..c1a51ce 100644 --- a/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx +++ b/src/N_m3u8DL-RE.Common/Resource/ResString.zh-Hant.resx @@ -231,4 +231,7 @@ 設置解密密鑰, 程序調用mp4decrpyt進行解密. 格式: --key KID1:KEY1 --key KID2:KEY2 + + 此字符串將直接傳遞給URL Processor + \ No newline at end of file diff --git a/src/N_m3u8DL-RE.Parser/Config/ParserConfig.cs b/src/N_m3u8DL-RE.Parser/Config/ParserConfig.cs index d087d4a..fb5f8c6 100644 --- a/src/N_m3u8DL-RE.Parser/Config/ParserConfig.cs +++ b/src/N_m3u8DL-RE.Parser/Config/ParserConfig.cs @@ -55,5 +55,10 @@ namespace N_m3u8DL_RE.Parser.Config /// 如果 AppendUrlParams=true,得 http://xxx.com/clip_01.ts?hmac=xxx&token=xxx /// public bool AppendUrlParams { get; set; } = false; + + /// + /// 此参数将会传递给URL Processor中 + /// + public string? UrlProcessorArgs { get; set; } } } diff --git a/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs b/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs index 93e96a7..a481378 100644 --- a/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs +++ b/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs @@ -16,6 +16,8 @@ namespace N_m3u8DL_RE.Parser.Extractor //https://blog.csdn.net/leek5533/article/details/117750191 internal class DASHExtractor2 : IExtractor { + private static EncryptMethod DEFAULT_METHOD = EncryptMethod.CENC; + public ExtractorType ExtractorType => ExtractorType.MPEG_DASH; private string MpdUrl = string.Empty; @@ -202,7 +204,7 @@ namespace N_m3u8DL_RE.Parser.Extractor new MediaSegment() { Index = 0, - Url = PreProcessUrl(segBaseUrl), + Url = segBaseUrl, Duration = XmlConvert.ToTimeSpan(periodDuration ?? mediaPresentationDuration ?? "PT0S").TotalSeconds } ); @@ -212,7 +214,7 @@ namespace N_m3u8DL_RE.Parser.Extractor var initUrl = ParserUtil.CombineURL(segBaseUrl, initialization.Attribute("sourceURL")?.Value!); var initRange = initialization.Attribute("range")?.Value; streamSpec.Playlist.MediaInit = new MediaSegment(); - streamSpec.Playlist.MediaInit.Url = PreProcessUrl(initUrl); + streamSpec.Playlist.MediaInit.Url = initUrl; if (initRange != null) { var (start, expect) = ParserUtil.ParseRange(initRange); @@ -235,7 +237,7 @@ namespace N_m3u8DL_RE.Parser.Extractor var initUrl = ParserUtil.CombineURL(segBaseUrl, initialization.Attribute("sourceURL")?.Value!); var initRange = initialization.Attribute("range")?.Value; streamSpec.Playlist.MediaInit = new MediaSegment(); - streamSpec.Playlist.MediaInit.Url = PreProcessUrl(initUrl); + streamSpec.Playlist.MediaInit.Url = initUrl; if (initRange != null) { var (start, expect) = ParserUtil.ParseRange(initRange); @@ -252,7 +254,7 @@ namespace N_m3u8DL_RE.Parser.Extractor var mediaRange = segmentURL.Attribute("mediaRange")?.Value; MediaSegment mediaSegment = new(); mediaSegment.Duration = Convert.ToDouble(duration); - mediaSegment.Url = PreProcessUrl(mediaUrl); + mediaSegment.Url = mediaUrl; mediaSegment.Index = segmentIndex; if (mediaRange != null) { @@ -289,7 +291,7 @@ namespace N_m3u8DL_RE.Parser.Extractor { var initUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, initialization), varDic); streamSpec.Playlist.MediaInit = new MediaSegment(); - streamSpec.Playlist.MediaInit.Url = PreProcessUrl(initUrl); + streamSpec.Playlist.MediaInit.Url = initUrl; } //处理分片 var media = segmentTemplate.Attribute("media")?.Value ?? segmentTemplateOuter.Attribute("media")?.Value; @@ -316,7 +318,7 @@ namespace N_m3u8DL_RE.Parser.Extractor varDic[DASHTags.TemplateNumber] = segNumber++; var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); MediaSegment mediaSegment = new(); - mediaSegment.Url = PreProcessUrl(mediaUrl); + mediaSegment.Url = mediaUrl; mediaSegment.Duration = _duration / (double)timescale; mediaSegment.Index = segIndex++; streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment); @@ -332,7 +334,7 @@ namespace N_m3u8DL_RE.Parser.Extractor varDic[DASHTags.TemplateTime] = currentTime; varDic[DASHTags.TemplateNumber] = segNumber++; var _mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); - _mediaSegment.Url = PreProcessUrl(_mediaUrl); + _mediaSegment.Url = _mediaUrl; _mediaSegment.Index = segIndex++; _mediaSegment.Duration = _duration / (double)timescale; streamSpec.Playlist.MediaParts[0].MediaSegments.Add(_mediaSegment); @@ -363,7 +365,7 @@ namespace N_m3u8DL_RE.Parser.Extractor varDic[DASHTags.TemplateNumber] = index; var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); MediaSegment mediaSegment = new(); - mediaSegment.Url = PreProcessUrl(mediaUrl); + mediaSegment.Url = mediaUrl; mediaSegment.Index = isLive ? index : segIndex; //直播直接用startNumber mediaSegment.Duration = duration / (double)timescale; streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment); @@ -379,7 +381,7 @@ namespace N_m3u8DL_RE.Parser.Extractor new MediaSegment() { Index = 0, - Url = PreProcessUrl(segBaseUrl), + Url = segBaseUrl, Duration = XmlConvert.ToTimeSpan(periodDuration ?? mediaPresentationDuration ?? "PT0S").TotalSeconds } ); @@ -390,11 +392,11 @@ namespace N_m3u8DL_RE.Parser.Extractor { if (streamSpec.Playlist.MediaInit != null) { - streamSpec.Playlist.MediaInit.EncryptInfo.Method = EncryptMethod.UNKNOWN; + streamSpec.Playlist.MediaInit.EncryptInfo.Method = DEFAULT_METHOD; } foreach (var item in streamSpec.Playlist.MediaParts[0].MediaSegments) { - item.EncryptInfo.Method = EncryptMethod.UNKNOWN; + item.EncryptInfo.Method = DEFAULT_METHOD; } } @@ -467,7 +469,26 @@ namespace N_m3u8DL_RE.Parser.Extractor public async Task FetchPlayListAsync(List streamSpecs) { - return; + //这里才调用URL预处理器,节省开销 + for (int i = 0; i < streamSpecs.Count; i++) + { + var playlist = streamSpecs[i].Playlist; + if (playlist != null) + { + if (playlist.MediaInit != null) + { + playlist.MediaInit!.Url = PreProcessUrl(playlist.MediaInit!.Url); + } + for (int ii = 0; ii < playlist!.MediaParts.Count; ii++) + { + var part = playlist.MediaParts[ii]; + for (int iii = 0; iii < part.MediaSegments.Count; iii++) + { + part.MediaSegments[iii].Url = PreProcessUrl(part.MediaSegments[iii].Url); + } + } + } + } } public string PreProcessUrl(string url) diff --git a/src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs b/src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs index 5d6fb46..e8dd1d3 100644 --- a/src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs +++ b/src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs @@ -1,36 +1,25 @@ using N_m3u8DL_RE.Common.Util; +using System.Security.Cryptography; namespace Mp4SubtitleParser { + public class ParsedMP4Info + { + public string? PSSH; + public string? KID; + public string? Scheme; + } + public class MP4InitUtil { private static readonly byte[] SYSTEM_ID_WIDEVINE = { 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; private static readonly byte[] SYSTEM_ID_PLAYREADY = { 0x9A, 0x04, 0xF0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xAB, 0x92, 0xE6, 0x5B, 0xE0, 0x88, 0x5F, 0x95 }; - public static string? ReadWVPssh(byte[] data) + public static ParsedMP4Info ReadInit(byte[] data) { - string? pssh = null; - //parse init - new MP4Parser() - .Box("moov", MP4Parser.Children) - .FullBox("pssh", (box) => - { - if (!(box.Version == 0 || box.Version == 1)) - throw new Exception("PSSH version can only be 0 or 1"); - var systemId = box.Reader.ReadBytes(16); - if (SYSTEM_ID_WIDEVINE.SequenceEqual(systemId)) - { - var dataSize = box.Reader.ReadUInt32(); - pssh = Convert.ToBase64String(box.Reader.ReadBytes((int)dataSize)); - } - }) - .Parse(data); - return pssh; - } + var info = new ParsedMP4Info(); + - public static string? ReadWVKid(byte[] data) - { - string? kid = null; //parse init new MP4Parser() .Box("moov", MP4Parser.Children) @@ -39,24 +28,44 @@ namespace Mp4SubtitleParser .Box("minf", MP4Parser.Children) .Box("stbl", MP4Parser.Children) .FullBox("stsd", MP4Parser.SampleDescription) - .FullBox("encv", MP4Parser.AllData((data) => + .FullBox("pssh", (box) => { - kid = HexUtil.BytesToHex(data[^16..]).ToLower(); - })) - .FullBox("enca", MP4Parser.AllData((data) => - { - kid = HexUtil.BytesToHex(data[^16..]).ToLower(); - })) - .FullBox("enct", MP4Parser.AllData((data) => - { - kid = HexUtil.BytesToHex(data[^16..]).ToLower(); - })) - .FullBox("encs", MP4Parser.AllData((data) => - { - kid = HexUtil.BytesToHex(data[^16..]).ToLower(); - })) + if (!(box.Version == 0 || box.Version == 1)) + throw new Exception("PSSH version can only be 0 or 1"); + var systemId = box.Reader.ReadBytes(16); + if (SYSTEM_ID_WIDEVINE.SequenceEqual(systemId)) + { + var dataSize = box.Reader.ReadUInt32(); + info.PSSH = Convert.ToBase64String(box.Reader.ReadBytes((int)dataSize)); + } + }) + .FullBox("encv", MP4Parser.AllData(data => ReadBox(data, info))) + .FullBox("enca", MP4Parser.AllData(data => ReadBox(data, info))) + .FullBox("enct", MP4Parser.AllData(data => ReadBox(data, info))) + .FullBox("encs", MP4Parser.AllData(data => ReadBox(data, info))) .Parse(data); - return kid; + + return info; + } + + private static void ReadBox(byte[] data, ParsedMP4Info info) + { + info.KID = HexUtil.BytesToHex(data[^16..]).ToLower(); + //find schm + var schmBytes = new byte[4] { 0x73, 0x63, 0x68, 0x6d }; + var schmIndex = 0; + for (int i = 0; i < data.Length - 4; i++) + { + if (new byte[4] { data[i], data[i + 1], data[i + 2], data[i + 3] }.SequenceEqual(schmBytes)) + { + schmIndex = i; + break; + } + } + if (schmIndex + 8 < data.Length) + { + info.Scheme = System.Text.Encoding.UTF8.GetString(data[schmIndex..][8..12]); + } } } } diff --git a/src/N_m3u8DL-RE.Parser/Util/ParserUtil.cs b/src/N_m3u8DL-RE.Parser/Util/ParserUtil.cs index 6fb4993..9757209 100644 --- a/src/N_m3u8DL-RE.Parser/Util/ParserUtil.cs +++ b/src/N_m3u8DL-RE.Parser/Util/ParserUtil.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace N_m3u8DL_RE.Parser.Util { - internal partial class ParserUtil + public partial class ParserUtil { [RegexGenerator("\\$Number%([^$]+)d\\$")] private static partial Regex VarsNumberRegex(); diff --git a/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs b/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs index f59b5a3..03e33d8 100644 --- a/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs +++ b/src/N_m3u8DL-RE/CommandLine/CommandInvoker.cs @@ -16,6 +16,7 @@ namespace N_m3u8DL_RE.CommandLine private readonly static Option SaveName = new(new string[] { "--save-name", "-O" }, description: ResString.cmd_saveName); private readonly static Option SavePattern = new(new string[] { "--save-pattern" }, description: ResString.cmd_savePattern, getDefaultValue: () => "____"); 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 Headers = new(new string[] { "--header", "-H" }, 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); @@ -59,6 +60,7 @@ namespace N_m3u8DL_RE.CommandLine AppendUrlParams = bindingContext.ParseResult.GetValueForOption(AppendUrlParams), SavePattern = bindingContext.ParseResult.GetValueForOption(SavePattern), Keys = bindingContext.ParseResult.GetValueForOption(Keys), + UrlProcessorArgs = bindingContext.ParseResult.GetValueForOption(UrlProcessorArgs), }; //在这里设置语言 @@ -87,7 +89,7 @@ namespace N_m3u8DL_RE.CommandLine { Input, TmpDir, SaveDir, SaveName, ThreadCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount, BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Keys, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix, - LogLevel, UILanguage + LogLevel, UILanguage, UrlProcessorArgs }; 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 1f6b248..194624f 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? UrlProcessorArgs { get; set; } + /// /// See: . /// public LogLevel LogLevel { get; set; } diff --git a/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs b/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs index 2153837..7ce30b2 100644 --- a/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs +++ b/src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs @@ -85,10 +85,10 @@ namespace N_m3u8DL_RE.DownloadManager if (result != null && result.Success) { var data = File.ReadAllBytes(result.ActualFilePath); - var pssh = MP4InitUtil.ReadWVPssh(data); - var kid = MP4InitUtil.ReadWVKid(data); - if (pssh != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {pssh}[/]"); - if (kid != null) Logger.WarnMarkUp($"[grey]KID: {kid}[/]"); + var info = MP4InitUtil.ReadInit(data); + 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}[/]"); } } diff --git a/src/N_m3u8DL-RE/N_m3u8DL-RE.csproj b/src/N_m3u8DL-RE/N_m3u8DL-RE.csproj index 924f5c5..c7fe853 100644 --- a/src/N_m3u8DL-RE/N_m3u8DL-RE.csproj +++ b/src/N_m3u8DL-RE/N_m3u8DL-RE.csproj @@ -15,6 +15,7 @@ + diff --git a/src/N_m3u8DL-RE/Processor/NowehoryzontyUrlProcessor.cs b/src/N_m3u8DL-RE/Processor/NowehoryzontyUrlProcessor.cs new file mode 100644 index 0000000..b83440c --- /dev/null +++ b/src/N_m3u8DL-RE/Processor/NowehoryzontyUrlProcessor.cs @@ -0,0 +1,224 @@ +using N_m3u8DL_RE.Common.Enum; +using N_m3u8DL_RE.Common.Log; +using N_m3u8DL_RE.Parser.Config; +using N_m3u8DL_RE.Parser.Processor; +using N_m3u8DL_RE.Parser.Util; +using NiL.JS.BaseLibrary; +using NiL.JS.Core; +using NiL.JS.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace N_m3u8DL_RE.Processor +{ + //"https://1429754964.rsc.cdn77.org/r/nh22/2022/VNUS_DE_NYKE/19_07_22_2302_skt/h264.mpd?secure=mSvVfvuciJt9wufUyzuBnA==,1658505709774" --urlprocessor-args "nowehoryzonty:timeDifference=-2274;filminfo.secureToken=vx54axqjal4f0yy2" + internal class NowehoryzontyUrlProcessor : UrlProcessor + { + private static string START = "nowehoryzonty:"; + private static string? TimeDifferenceStr = null; + private static int? TimeDifference = null; + private static string? SecureToken = null; + private static bool LOG = false; + private static Function? Function = null; + public override bool CanProcess(ExtractorType extractorType, string oriUrl, ParserConfig parserConfig) + { + if (extractorType == ExtractorType.MPEG_DASH && parserConfig.UrlProcessorArgs != null && parserConfig.UrlProcessorArgs.StartsWith(START)) + { + if (!LOG) + { + Logger.WarnMarkUp($"[white on green]www.nowehoryzonty.pl[/] matched! waiting for calc..."); + LOG = true; + } + var context = new Context(); + context.Eval(JS); + Function = context.GetVariable("md5").As(); + var argLine = parserConfig.UrlProcessorArgs![START.Length..]; + TimeDifferenceStr = ParserUtil.GetAttribute(argLine, "timeDifference"); + SecureToken = ParserUtil.GetAttribute(argLine, "filminfo.secureToken"); + if (TimeDifferenceStr != null && SecureToken != null) + { + TimeDifference = Convert.ToInt32(TimeDifferenceStr); + } + return true; + } + return false; + } + + public override string Process(string oriUrl, ParserConfig parserConfig) + { + var a = new Uri(oriUrl).AbsolutePath; + var n = oriUrl + "?secure=" + Calc(a); + return n; + } + + private static string Calc(string a) + { + string returnStr = Function!.Call(new Arguments { a, SecureToken, TimeDifference }).ToString(); + return returnStr; + } + + ////https://www.nowehoryzonty.pl/packed/videonho.js?v=1114377281:formatted + private static readonly string JS = """ + var p = function(f, e) { + var d = f[0] + , a = f[1] + , b = f[2] + , c = f[3]; + d = h(d, a, b, c, e[0], 7, -680876936); + c = h(c, d, a, b, e[1], 12, -389564586); + b = h(b, c, d, a, e[2], 17, 606105819); + a = h(a, b, c, d, e[3], 22, -1044525330); + d = h(d, a, b, c, e[4], 7, -176418897); + c = h(c, d, a, b, e[5], 12, 1200080426); + b = h(b, c, d, a, e[6], 17, -1473231341); + a = h(a, b, c, d, e[7], 22, -45705983); + d = h(d, a, b, c, e[8], 7, 1770035416); + c = h(c, d, a, b, e[9], 12, -1958414417); + b = h(b, c, d, a, e[10], 17, -42063); + a = h(a, b, c, d, e[11], 22, -1990404162); + d = h(d, a, b, c, e[12], 7, 1804603682); + c = h(c, d, a, b, e[13], 12, -40341101); + b = h(b, c, d, a, e[14], 17, -1502002290); + a = h(a, b, c, d, e[15], 22, 1236535329); + d = k(d, a, b, c, e[1], 5, -165796510); + c = k(c, d, a, b, e[6], 9, -1069501632); + b = k(b, c, d, a, e[11], 14, 643717713); + a = k(a, b, c, d, e[0], 20, -373897302); + d = k(d, a, b, c, e[5], 5, -701558691); + c = k(c, d, a, b, e[10], 9, 38016083); + b = k(b, c, d, a, e[15], 14, -660478335); + a = k(a, b, c, d, e[4], 20, -405537848); + d = k(d, a, b, c, e[9], 5, 568446438); + c = k(c, d, a, b, e[14], 9, -1019803690); + b = k(b, c, d, a, e[3], 14, -187363961); + a = k(a, b, c, d, e[8], 20, 1163531501); + d = k(d, a, b, c, e[13], 5, -1444681467); + c = k(c, d, a, b, e[2], 9, -51403784); + b = k(b, c, d, a, e[7], 14, 1735328473); + a = k(a, b, c, d, e[12], 20, -1926607734); + d = g(a ^ b ^ c, d, a, e[5], 4, -378558); + c = g(d ^ a ^ b, c, d, e[8], 11, -2022574463); + b = g(c ^ d ^ a, b, c, e[11], 16, 1839030562); + a = g(b ^ c ^ d, a, b, e[14], 23, -35309556); + d = g(a ^ b ^ c, d, a, e[1], 4, -1530992060); + c = g(d ^ a ^ b, c, d, e[4], 11, 1272893353); + b = g(c ^ d ^ a, b, c, e[7], 16, -155497632); + a = g(b ^ c ^ d, a, b, e[10], 23, -1094730640); + d = g(a ^ b ^ c, d, a, e[13], 4, 681279174); + c = g(d ^ a ^ b, c, d, e[0], 11, -358537222); + b = g(c ^ d ^ a, b, c, e[3], 16, -722521979); + a = g(b ^ c ^ d, a, b, e[6], 23, 76029189); + d = g(a ^ b ^ c, d, a, e[9], 4, -640364487); + c = g(d ^ a ^ b, c, d, e[12], 11, -421815835); + b = g(c ^ d ^ a, b, c, e[15], 16, 530742520); + a = g(b ^ c ^ d, a, b, e[2], 23, -995338651); + d = l(d, a, b, c, e[0], 6, -198630844); + c = l(c, d, a, b, e[7], 10, 1126891415); + b = l(b, c, d, a, e[14], 15, -1416354905); + a = l(a, b, c, d, e[5], 21, -57434055); + d = l(d, a, b, c, e[12], 6, 1700485571); + c = l(c, d, a, b, e[3], 10, -1894986606); + b = l(b, c, d, a, e[10], 15, -1051523); + a = l(a, b, c, d, e[1], 21, -2054922799); + d = l(d, a, b, c, e[8], 6, 1873313359); + c = l(c, d, a, b, e[15], 10, -30611744); + b = l(b, c, d, a, e[6], 15, -1560198380); + a = l(a, b, c, d, e[13], 21, 1309151649); + d = l(d, a, b, c, e[4], 6, -145523070); + c = l(c, d, a, b, e[11], 10, -1120210379); + b = l(b, c, d, a, e[2], 15, 718787259); + a = l(a, b, c, d, e[9], 21, -343485551); + f[0] = m(d, f[0]); + f[1] = m(a, f[1]); + f[2] = m(b, f[2]); + f[3] = m(c, f[3]) + }, g = function(f, e, d, a, b, c) { + e = m(m(e, f), m(a, c)); + return m(e << b | e >>> 32 - b, d) + } + , h = function(f, e, d, a, b, c, n) { + return g(e & d | ~e & a, f, e, b, c, n) + } + , k = function(f, e, d, a, b, c, n) { + return g(e & a | d & ~a, f, e, b, c, n) + } + , l = function(f, e, d, a, b, c, n) { + return g(d ^ (e | ~a), f, e, b, c, n) + }, r = "0123456789abcdef".split(""); + + var m = function(f, e) { + return f + e & 4294967295 + }; + + var q = function(f) { + var e = f.length, d = [1732584193, -271733879, -1732584194, 271733878], a; + for (a = 64; a <= f.length; a += 64) { + var b, c = f.substring(a - 64, a), g = []; + for (b = 0; 64 > b; b += 4) + g[b >> 2] = c.charCodeAt(b) + (c.charCodeAt(b + 1) << 8) + (c.charCodeAt(b + 2) << 16) + (c.charCodeAt(b + 3) << 24); + p(d, g) + } + f = f.substring(a - 64); + b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (a = 0; a < f.length; a++) + b[a >> 2] |= f.charCodeAt(a) << (a % 4 << 3); + b[a >> 2] |= 128 << (a % 4 << 3); + if (55 < a) + for (p(d, b), + a = 0; 16 > a; a++) + b[a] = 0; + b[14] = 8 * e; + p(d, b); + return d + }; + + var md5 = function(f, e, timeDifference) { + var d = Date.now() + 6E4 + timeDifference; + e = q(d + f + e); + f = []; + for (var a = 0; a < e.length; a++) { + var b = e[a]; + var c = [] + , g = 4; + do + c[--g] = b & 255, + b >>= 8; + while (g); + b = c; + for (c = b.length - 1; 0 <= c; c--) + f.push(b[c]) + } + g = void 0; + c = ""; + for (e = a = b = 0; e < 4 * f.length / 3; g = b >> 2 * (++e & 3) & 63, + c += String.fromCharCode(g + 71 - (26 > g ? 6 : 52 > g ? 0 : 62 > g ? 75 : g ^ 63 ? 90 : 87)) + (75 == (e - 1) % 76 ? "\r\n" : "")) + e & 3 ^ 3 && (b = b << 8 ^ f[a++]); + for (; e++ & 3; ) + c += "\x3d"; + return c.replace(/\+/g, "-").replace(/\//g, "_") + "," + d + }; + + "5d41402abc4b2a76b9719d911017c592" != function(f) { + for (var e = 0; e < f.length; e++) { + for (var d = e, a = f[e], b = "", c = 0; 4 > c; c++) + b += r[a >> 8 * c + 4 & 15] + r[a >> 8 * c & 15]; + f[d] = b + } + return f.join("") + }(q("hello")) && (m = function(f, e) { + var d = (f & 65535) + (e & 65535); + return (f >> 16) + (e >> 16) + (d >> 16) << 16 | d & 65535 + } + ) + + //console.log(md5('/r/nh22/2022/VNUS_DE_NYKE/19_07_22_2302_skt/h264.mpd','vx54axqjal4f0yy2',-2274)); + //console.log(md5('/r/nh22/2022/VNUS_DE_NYKE/19_07_22_2302_skt/subtitle_pl/34.m4s','vx54axqjal4f0yy2',-2274)); + + """; + } +} diff --git a/src/N_m3u8DL-RE/Program.cs b/src/N_m3u8DL-RE/Program.cs index 9cb2c51..32bc4bd 100644 --- a/src/N_m3u8DL-RE/Program.cs +++ b/src/N_m3u8DL-RE/Program.cs @@ -40,7 +40,8 @@ namespace N_m3u8DL_RE { var parserConfig = new ParserConfig() { - AppendUrlParams = option.AppendUrlParams + AppendUrlParams = option.AppendUrlParams, + UrlProcessorArgs = option.UrlProcessorArgs, }; //设置Headers @@ -53,6 +54,8 @@ namespace N_m3u8DL_RE parserConfig.ContentProcessors.Insert(0, new DemoProcessor()); //demo2 parserConfig.KeyProcessors.Insert(0, new DemoProcessor2()); + //for www.nowehoryzonty.pl + parserConfig.UrlProcessors.Insert(0, new NowehoryzontyUrlProcessor()); var url = string.Empty; //url = "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd"; //直播 diff --git a/src/N_m3u8DL-RE/rd.xml b/src/N_m3u8DL-RE/rd.xml index a9352dc..c48a404 100644 --- a/src/N_m3u8DL-RE/rd.xml +++ b/src/N_m3u8DL-RE/rd.xml @@ -3,5 +3,6 @@ + \ No newline at end of file