增加`--urlprocessor-args`用于将参数传输到URL处理器中;增加CENC加密方式识别;增加`nowehoryzonty.pl`网站参数计算逻辑

This commit is contained in:
nilaoda 2022-07-23 03:25:45 +08:00
parent d6b01d83bd
commit 47df7cb838
16 changed files with 346 additions and 57 deletions

View File

@ -13,6 +13,7 @@ namespace N_m3u8DL_RE.Common.Enum
AES_128_ECB, AES_128_ECB,
SAMPLE_AES, SAMPLE_AES,
SAMPLE_AES_CTR, SAMPLE_AES_CTR,
CENC,
CHACHA20, CHACHA20,
UNKNOWN UNKNOWN
} }

View File

@ -269,6 +269,15 @@ namespace N_m3u8DL_RE.Common.Resource {
} }
} }
/// <summary>
/// 查找类似 Give these arguments to the URL Processors. 的本地化字符串。
/// </summary>
public static string cmd_urlProcessorArgs {
get {
return ResourceManager.GetString("cmd_urlProcessorArgs", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Write meta json after parsed 的本地化字符串。 /// 查找类似 Write meta json after parsed 的本地化字符串。
/// </summary> /// </summary>

View File

@ -234,4 +234,7 @@
<value>Pass decryption key(s) to mp4decrypt. format: <value>Pass decryption key(s) to mp4decrypt. format:
--key KID1:KEY1 --key KID2:KEY2</value> --key KID1:KEY1 --key KID2:KEY2</value>
</data> </data>
<data name="cmd_urlProcessorArgs" xml:space="preserve">
<value>Give these arguments to the URL Processors.</value>
</data>
</root> </root>

View File

@ -254,4 +254,7 @@
<value>设置解密密钥, 程序调用mp4decrpyt进行解密. 格式: <value>设置解密密钥, 程序调用mp4decrpyt进行解密. 格式:
--key KID1:KEY1 --key KID2:KEY2</value> --key KID1:KEY1 --key KID2:KEY2</value>
</data> </data>
<data name="cmd_urlProcessorArgs" xml:space="preserve">
<value>此字符串将直接传递给URL Processor</value>
</data>
</root> </root>

View File

@ -231,4 +231,7 @@
<value>設置解密密鑰, 程序調用mp4decrpyt進行解密. 格式: <value>設置解密密鑰, 程序調用mp4decrpyt進行解密. 格式:
--key KID1:KEY1 --key KID2:KEY2</value> --key KID1:KEY1 --key KID2:KEY2</value>
</data> </data>
<data name="cmd_urlProcessorArgs" xml:space="preserve">
<value>此字符串將直接傳遞給URL Processor</value>
</data>
</root> </root>

View File

@ -55,5 +55,10 @@ namespace N_m3u8DL_RE.Parser.Config
/// 如果 AppendUrlParams=true得 http://xxx.com/clip_01.ts?hmac=xxx&token=xxx /// 如果 AppendUrlParams=true得 http://xxx.com/clip_01.ts?hmac=xxx&token=xxx
/// </summary> /// </summary>
public bool AppendUrlParams { get; set; } = false; public bool AppendUrlParams { get; set; } = false;
/// <summary>
/// 此参数将会传递给URL Processor中
/// </summary>
public string? UrlProcessorArgs { get; set; }
} }
} }

View File

@ -16,6 +16,8 @@ namespace N_m3u8DL_RE.Parser.Extractor
//https://blog.csdn.net/leek5533/article/details/117750191 //https://blog.csdn.net/leek5533/article/details/117750191
internal class DASHExtractor2 : IExtractor internal class DASHExtractor2 : IExtractor
{ {
private static EncryptMethod DEFAULT_METHOD = EncryptMethod.CENC;
public ExtractorType ExtractorType => ExtractorType.MPEG_DASH; public ExtractorType ExtractorType => ExtractorType.MPEG_DASH;
private string MpdUrl = string.Empty; private string MpdUrl = string.Empty;
@ -202,7 +204,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
new MediaSegment() new MediaSegment()
{ {
Index = 0, Index = 0,
Url = PreProcessUrl(segBaseUrl), Url = segBaseUrl,
Duration = XmlConvert.ToTimeSpan(periodDuration ?? mediaPresentationDuration ?? "PT0S").TotalSeconds 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 initUrl = ParserUtil.CombineURL(segBaseUrl, initialization.Attribute("sourceURL")?.Value!);
var initRange = initialization.Attribute("range")?.Value; var initRange = initialization.Attribute("range")?.Value;
streamSpec.Playlist.MediaInit = new MediaSegment(); streamSpec.Playlist.MediaInit = new MediaSegment();
streamSpec.Playlist.MediaInit.Url = PreProcessUrl(initUrl); streamSpec.Playlist.MediaInit.Url = initUrl;
if (initRange != null) if (initRange != null)
{ {
var (start, expect) = ParserUtil.ParseRange(initRange); 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 initUrl = ParserUtil.CombineURL(segBaseUrl, initialization.Attribute("sourceURL")?.Value!);
var initRange = initialization.Attribute("range")?.Value; var initRange = initialization.Attribute("range")?.Value;
streamSpec.Playlist.MediaInit = new MediaSegment(); streamSpec.Playlist.MediaInit = new MediaSegment();
streamSpec.Playlist.MediaInit.Url = PreProcessUrl(initUrl); streamSpec.Playlist.MediaInit.Url = initUrl;
if (initRange != null) if (initRange != null)
{ {
var (start, expect) = ParserUtil.ParseRange(initRange); var (start, expect) = ParserUtil.ParseRange(initRange);
@ -252,7 +254,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
var mediaRange = segmentURL.Attribute("mediaRange")?.Value; var mediaRange = segmentURL.Attribute("mediaRange")?.Value;
MediaSegment mediaSegment = new(); MediaSegment mediaSegment = new();
mediaSegment.Duration = Convert.ToDouble(duration); mediaSegment.Duration = Convert.ToDouble(duration);
mediaSegment.Url = PreProcessUrl(mediaUrl); mediaSegment.Url = mediaUrl;
mediaSegment.Index = segmentIndex; mediaSegment.Index = segmentIndex;
if (mediaRange != null) if (mediaRange != null)
{ {
@ -289,7 +291,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
{ {
var initUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, initialization), varDic); var initUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, initialization), varDic);
streamSpec.Playlist.MediaInit = new MediaSegment(); 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; var media = segmentTemplate.Attribute("media")?.Value ?? segmentTemplateOuter.Attribute("media")?.Value;
@ -316,7 +318,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
varDic[DASHTags.TemplateNumber] = segNumber++; varDic[DASHTags.TemplateNumber] = segNumber++;
var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic);
MediaSegment mediaSegment = new(); MediaSegment mediaSegment = new();
mediaSegment.Url = PreProcessUrl(mediaUrl); mediaSegment.Url = mediaUrl;
mediaSegment.Duration = _duration / (double)timescale; mediaSegment.Duration = _duration / (double)timescale;
mediaSegment.Index = segIndex++; mediaSegment.Index = segIndex++;
streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment); streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment);
@ -332,7 +334,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
varDic[DASHTags.TemplateTime] = currentTime; varDic[DASHTags.TemplateTime] = currentTime;
varDic[DASHTags.TemplateNumber] = segNumber++; varDic[DASHTags.TemplateNumber] = segNumber++;
var _mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); var _mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic);
_mediaSegment.Url = PreProcessUrl(_mediaUrl); _mediaSegment.Url = _mediaUrl;
_mediaSegment.Index = segIndex++; _mediaSegment.Index = segIndex++;
_mediaSegment.Duration = _duration / (double)timescale; _mediaSegment.Duration = _duration / (double)timescale;
streamSpec.Playlist.MediaParts[0].MediaSegments.Add(_mediaSegment); streamSpec.Playlist.MediaParts[0].MediaSegments.Add(_mediaSegment);
@ -363,7 +365,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
varDic[DASHTags.TemplateNumber] = index; varDic[DASHTags.TemplateNumber] = index;
var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic); var mediaUrl = ParserUtil.ReplaceVars(ParserUtil.CombineURL(segBaseUrl, media!), varDic);
MediaSegment mediaSegment = new(); MediaSegment mediaSegment = new();
mediaSegment.Url = PreProcessUrl(mediaUrl); mediaSegment.Url = mediaUrl;
mediaSegment.Index = isLive ? index : segIndex; //直播直接用startNumber mediaSegment.Index = isLive ? index : segIndex; //直播直接用startNumber
mediaSegment.Duration = duration / (double)timescale; mediaSegment.Duration = duration / (double)timescale;
streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment); streamSpec.Playlist.MediaParts[0].MediaSegments.Add(mediaSegment);
@ -379,7 +381,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
new MediaSegment() new MediaSegment()
{ {
Index = 0, Index = 0,
Url = PreProcessUrl(segBaseUrl), Url = segBaseUrl,
Duration = XmlConvert.ToTimeSpan(periodDuration ?? mediaPresentationDuration ?? "PT0S").TotalSeconds Duration = XmlConvert.ToTimeSpan(periodDuration ?? mediaPresentationDuration ?? "PT0S").TotalSeconds
} }
); );
@ -390,11 +392,11 @@ namespace N_m3u8DL_RE.Parser.Extractor
{ {
if (streamSpec.Playlist.MediaInit != null) 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) 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<StreamSpec> streamSpecs) public async Task FetchPlayListAsync(List<StreamSpec> 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) public string PreProcessUrl(string url)

View File

@ -1,36 +1,25 @@
using N_m3u8DL_RE.Common.Util; using N_m3u8DL_RE.Common.Util;
using System.Security.Cryptography;
namespace Mp4SubtitleParser namespace Mp4SubtitleParser
{ {
public class ParsedMP4Info
{
public string? PSSH;
public string? KID;
public string? Scheme;
}
public class MP4InitUtil 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_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 }; 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; var info = new ParsedMP4Info();
//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;
}
public static string? ReadWVKid(byte[] data)
{
string? kid = null;
//parse init //parse init
new MP4Parser() new MP4Parser()
.Box("moov", MP4Parser.Children) .Box("moov", MP4Parser.Children)
@ -39,24 +28,44 @@ namespace Mp4SubtitleParser
.Box("minf", MP4Parser.Children) .Box("minf", MP4Parser.Children)
.Box("stbl", MP4Parser.Children) .Box("stbl", MP4Parser.Children)
.FullBox("stsd", MP4Parser.SampleDescription) .FullBox("stsd", MP4Parser.SampleDescription)
.FullBox("encv", MP4Parser.AllData((data) => .FullBox("pssh", (box) =>
{ {
kid = HexUtil.BytesToHex(data[^16..]).ToLower(); if (!(box.Version == 0 || box.Version == 1))
})) throw new Exception("PSSH version can only be 0 or 1");
.FullBox("enca", MP4Parser.AllData((data) => var systemId = box.Reader.ReadBytes(16);
if (SYSTEM_ID_WIDEVINE.SequenceEqual(systemId))
{ {
kid = HexUtil.BytesToHex(data[^16..]).ToLower(); var dataSize = box.Reader.ReadUInt32();
})) info.PSSH = Convert.ToBase64String(box.Reader.ReadBytes((int)dataSize));
.FullBox("enct", MP4Parser.AllData((data) => }
{ })
kid = HexUtil.BytesToHex(data[^16..]).ToLower(); .FullBox("encv", MP4Parser.AllData(data => ReadBox(data, info)))
})) .FullBox("enca", MP4Parser.AllData(data => ReadBox(data, info)))
.FullBox("encs", MP4Parser.AllData((data) => .FullBox("enct", MP4Parser.AllData(data => ReadBox(data, info)))
{ .FullBox("encs", MP4Parser.AllData(data => ReadBox(data, info)))
kid = HexUtil.BytesToHex(data[^16..]).ToLower();
}))
.Parse(data); .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]);
}
} }
} }
} }

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace N_m3u8DL_RE.Parser.Util namespace N_m3u8DL_RE.Parser.Util
{ {
internal partial class ParserUtil public partial class ParserUtil
{ {
[RegexGenerator("\\$Number%([^$]+)d\\$")] [RegexGenerator("\\$Number%([^$]+)d\\$")]
private static partial Regex VarsNumberRegex(); private static partial Regex VarsNumberRegex();

View File

@ -16,6 +16,7 @@ namespace N_m3u8DL_RE.CommandLine
private readonly static Option<string?> SaveName = new(new string[] { "--save-name", "-O" }, description: ResString.cmd_saveName); private readonly static Option<string?> SaveName = new(new string[] { "--save-name", "-O" }, 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?> 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?> 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);
private readonly static Option<string[]?> Keys = new(new string[] { "--key" }, description: ResString.cmd_keys) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false }; private readonly static Option<string[]?> Keys = new(new string[] { "--key" }, description: ResString.cmd_keys) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false };
private readonly static Option<string[]?> Headers = new(new string[] { "--header", "-H" }, description: ResString.cmd_header) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false }; private readonly static Option<string[]?> Headers = new(new string[] { "--header", "-H" }, description: ResString.cmd_header) { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = false };
private readonly static Option<LogLevel> LogLevel = new(name: "--log-level", description: ResString.cmd_logLevel, getDefaultValue: () => Common.Log.LogLevel.INFO); private readonly static Option<LogLevel> 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), AppendUrlParams = bindingContext.ParseResult.GetValueForOption(AppendUrlParams),
SavePattern = bindingContext.ParseResult.GetValueForOption(SavePattern), SavePattern = bindingContext.ParseResult.GetValueForOption(SavePattern),
Keys = bindingContext.ParseResult.GetValueForOption(Keys), 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, Input, TmpDir, SaveDir, SaveName, ThreadCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Keys, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix, BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Keys, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
LogLevel, UILanguage LogLevel, UILanguage, UrlProcessorArgs
}; };
rootCommand.TreatUnmatchedTokensAsErrors = true; rootCommand.TreatUnmatchedTokensAsErrors = true;
rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder()); rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder());

View File

@ -18,6 +18,10 @@ namespace N_m3u8DL_RE.CommandLine
/// </summary> /// </summary>
public string[]? Keys { get; set; } public string[]? Keys { get; set; }
/// <summary> /// <summary>
/// See: <see cref="CommandInvoker.UrlProcessorArgs"/>.
/// </summary>
public string? UrlProcessorArgs { get; set; }
/// <summary>
/// See: <see cref="CommandInvoker.LogLevel"/>. /// See: <see cref="CommandInvoker.LogLevel"/>.
/// </summary> /// </summary>
public LogLevel LogLevel { get; set; } public LogLevel LogLevel { get; set; }

View File

@ -85,10 +85,10 @@ namespace N_m3u8DL_RE.DownloadManager
if (result != null && result.Success) if (result != null && result.Success)
{ {
var data = File.ReadAllBytes(result.ActualFilePath); var data = File.ReadAllBytes(result.ActualFilePath);
var pssh = MP4InitUtil.ReadWVPssh(data); var info = MP4InitUtil.ReadInit(data);
var kid = MP4InitUtil.ReadWVKid(data); if (info.Scheme != null) Logger.WarnMarkUp($"[grey]Type: {info.Scheme}[/]");
if (pssh != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {pssh}[/]"); if (info.PSSH != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {info.PSSH}[/]");
if (kid != null) Logger.WarnMarkUp($"[grey]KID: {kid}[/]"); if (info.KID != null) Logger.WarnMarkUp($"[grey]KID: {info.KID}[/]");
} }
} }

View File

@ -15,6 +15,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NiL.JS" Version="2.5.1560" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" /> <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup> </ItemGroup>

View File

@ -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<Function>();
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));
""";
}
}

View File

@ -40,7 +40,8 @@ namespace N_m3u8DL_RE
{ {
var parserConfig = new ParserConfig() var parserConfig = new ParserConfig()
{ {
AppendUrlParams = option.AppendUrlParams AppendUrlParams = option.AppendUrlParams,
UrlProcessorArgs = option.UrlProcessorArgs,
}; };
//设置Headers //设置Headers
@ -53,6 +54,8 @@ namespace N_m3u8DL_RE
parserConfig.ContentProcessors.Insert(0, new DemoProcessor()); parserConfig.ContentProcessors.Insert(0, new DemoProcessor());
//demo2 //demo2
parserConfig.KeyProcessors.Insert(0, new DemoProcessor2()); parserConfig.KeyProcessors.Insert(0, new DemoProcessor2());
//for www.nowehoryzonty.pl
parserConfig.UrlProcessors.Insert(0, new NowehoryzontyUrlProcessor());
var url = string.Empty; var url = string.Empty;
//url = "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd"; //直播 //url = "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd"; //直播

View File

@ -3,5 +3,6 @@
<!--<Assembly Name="N_m3u8DL-RE" Dynamic="Required All"/> <!--<Assembly Name="N_m3u8DL-RE" Dynamic="Required All"/>
<Assembly Name="N_m3u8DL-RE.Common" Dynamic="Required All"/> <Assembly Name="N_m3u8DL-RE.Common" Dynamic="Required All"/>
<Assembly Name="N_m3u8DL-RE.Parser" Dynamic="Required All"/>--> <Assembly Name="N_m3u8DL-RE.Parser" Dynamic="Required All"/>-->
<Assembly Name="NiL.JS" Dynamic="Required All"/>
</Application> </Application>
</Directives> </Directives>