新增`--allow-hls-multi-ext-map` (#503)

This commit is contained in:
nilaoda 2024-11-23 19:32:25 +08:00 committed by GitHub
parent 0c73b730bb
commit e8e92b6337
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 53 additions and 19 deletions

View File

@ -65,6 +65,7 @@ public class ResString
public static string cmd_skipDownload => GetText("cmd_skipDownload");
public static string cmd_noDateInfo => GetText("cmd_noDateInfo");
public static string cmd_noLog => GetText("cmd_noLog");
public static string cmd_allowHlsMultiExtMap => GetText("cmd_allowHlsMultiExtMap");
public static string cmd_skipMerge => GetText("cmd_skipMerge");
public static string cmd_subFormat => GetText("cmd_subFormat");
public static string cmd_subOnly => GetText("cmd_subOnly");
@ -111,6 +112,7 @@ public class ResString
public static string liveFound => GetText("liveFound");
public static string loadingUrl => GetText("loadingUrl");
public static string masterM3u8Found => GetText("masterM3u8Found");
public static string allowHlsMultiExtMap => GetText("allowHlsMultiExtMap");
public static string matchDASH => GetText("matchDASH");
public static string matchMSS => GetText("matchMSS");
public static string matchTS => GetText("matchTS");

View File

@ -172,6 +172,12 @@ internal class StaticText
zhTW: "關閉日誌文件輸出",
enUS: "Disable log file output"
),
["cmd_allowHlsMultiExtMap"] = new TextContainer
(
zhCN: "允许HLS中的多个#EXT-X-MAP(实验性)",
zhTW: "允許HLS中的多個#EXT-X-MAP(實驗性)",
enUS: "Allow multiple #EXT-X-MAP in HLS (experimental)"
),
["cmd_appendUrlParams"] = new TextContainer
(
zhCN: "将输入Url的Params添加至分片, 对某些网站很有用, 例如 kakao.com",
@ -820,6 +826,12 @@ internal class StaticText
zhTW: "檢測到Master列表開始解析全部流訊息",
enUS: "Master List detected, try parse all streams"
),
["allowHlsMultiExtMap"] = new TextContainer
(
zhCN: "已经允许识别多个#EXT-X-MAP标签, 本软件可能无法正确处理, 请手动确认内容完整性",
zhTW: "已經允許識別多個#EXT-X-MAP標籤, 本軟件可能無法正確處理, 請手動確認內容完整性",
enUS: "Multiple #EXT-X-MAP tags are now allowed for detection. However, this software may not handle them correctly. Please manually verify the content's integrity"
),
["matchTS"] = new TextContainer
(
zhCN: "内容匹配: [white on green3]HTTP Live MPEG2-TS[/]",

View File

@ -13,7 +13,9 @@ public class ParserConfig
public string BaseUrl { get; set; }
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> CustomParserArgs { get; } = new();
public Dictionary<string, string> Headers { get; init; } = new();
/// <summary>
/// 内容前置处理器. 调用顺序与列表顺序相同

View File

@ -221,6 +221,12 @@ internal class HLSExtractor : IExtractor
{
// 标记是否已清除广告分片
bool hasAd = false;
;
bool allowHlsMultiExtMap = ParserConfig.CustomParserArgs.TryGetValue("AllowHlsMultiExtMap", out var allMultiExtMap) && allMultiExtMap == "true";
if (allowHlsMultiExtMap)
{
Logger.WarnMarkUp($"[darkorange3_1]{ResString.allowHlsMultiExtMap}[/]");
}
using StringReader sr = new StringReader(M3u8Content);
string? line;
@ -395,10 +401,13 @@ internal class HLSExtractor : IExtractor
});
}
segments = new();
if (!allowHlsMultiExtMap)
{
isEndlist = true;
break;
}
}
}
// 评论行不解析
else if (line.StartsWith("#")) continue;
// 空白行不解析

View File

@ -17,7 +17,7 @@ namespace N_m3u8DL_RE.CommandLine;
internal partial class CommandInvoker
{
public const string VERSION_INFO = "N_m3u8DL-RE (Beta version) 20241117";
public const string VERSION_INFO = "N_m3u8DL-RE (Beta version) 20241123";
[GeneratedRegex("((best|worst)\\d*|all)")]
private static partial Regex ForStrRegex();
@ -61,6 +61,7 @@ internal partial class CommandInvoker
private static readonly Option<string?> BaseUrl = new(["--base-url"], description: ResString.cmd_baseUrl);
private static readonly Option<bool> ConcurrentDownload = new(["-mt", "--concurrent-download"], description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
private static readonly Option<bool> NoLog = new(["--no-log"], description: ResString.cmd_noLog, getDefaultValue: () => false);
private static readonly Option<bool> AllowHlsMultiExtMap = new(["--allow-hls-multi-ext-map"], description: ResString.cmd_allowHlsMultiExtMap, getDefaultValue: () => false);
private static readonly Option<string[]?> AdKeywords = new(["--ad-keyword"], description: ResString.cmd_adKeyword) { ArgumentHelpName = "REG" };
private static readonly Option<long?> MaxSpeed = new(["-R", "--max-speed"], description: ResString.cmd_maxSpeed, parseArgument: ParseSpeedLimit) { ArgumentHelpName = "SPEED" };
@ -550,6 +551,7 @@ internal partial class CommandInvoker
LiveTakeCount = bindingContext.ParseResult.GetValueForOption(LiveTakeCount),
NoDateInfo = bindingContext.ParseResult.GetValueForOption(NoDateInfo),
NoLog = bindingContext.ParseResult.GetValueForOption(NoLog),
AllowHlsMultiExtMap = bindingContext.ParseResult.GetValueForOption(AllowHlsMultiExtMap),
AdKeywords = bindingContext.ParseResult.GetValueForOption(AdKeywords),
MaxSpeed = bindingContext.ParseResult.GetValueForOption(MaxSpeed),
};
@ -618,7 +620,7 @@ internal partial class CommandInvoker
MuxAfterDone,
CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy, CustomProxy, CustomRange, TaskStartAt,
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LivePipeMux, LiveFixVttByAudio, LiveRecordLimit, LiveWaitTime, LiveTakeCount,
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, DropVideoFilter, DropAudioFilter, DropSubtitleFilter, AdKeywords, DisableUpdateCheck, MoreHelp
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, DropVideoFilter, DropAudioFilter, DropSubtitleFilter, AdKeywords, DisableUpdateCheck, AllowHlsMultiExtMap, MoreHelp
};
rootCommand.TreatUnmatchedTokensAsErrors = true;

View File

@ -53,6 +53,10 @@ internal class MyOption
/// </summary>
public bool NoLog { get; set; }
/// <summary>
/// See: <see cref="CommandInvoker.AllowHlsMultiExtMap"/>.
/// </summary>
public bool AllowHlsMultiExtMap { get; set; }
/// <summary>
/// See: <see cref="CommandInvoker.AutoSelect"/>.
/// </summary>
public bool AutoSelect { get; set; }

View File

@ -106,21 +106,20 @@ internal class Program
// 检查互斥的选项
if (!option.MuxAfterDone && option.MuxImports != null && option.MuxImports.Count > 0)
if (option is { MuxAfterDone: false, MuxImports.Count: > 0 })
{
throw new ArgumentException("MuxAfterDone disabled, MuxImports not allowed!");
}
// LivePipeMux开启时 LiveRealTimeMerge必须开启
if (option.LivePipeMux && !option.LiveRealTimeMerge)
if (option is { LivePipeMux: true, LiveRealTimeMerge: false })
{
Logger.WarnMarkUp("LivePipeMux detected, forced enable LiveRealTimeMerge");
option.LiveRealTimeMerge = true;
}
// 预先检查ffmpeg
if (option.FFmpegBinaryPath == null)
option.FFmpegBinaryPath = GlobalUtil.FindExecutable("ffmpeg");
option.FFmpegBinaryPath ??= GlobalUtil.FindExecutable("ffmpeg");
if (string.IsNullOrEmpty(option.FFmpegBinaryPath) || !File.Exists(option.FFmpegBinaryPath))
{
@ -132,8 +131,7 @@ internal class Program
// 预先检查mkvmerge
if (option.MuxOptions != null && option.MuxOptions.UseMkvmerge && option.MuxAfterDone)
{
if (option.MkvmergeBinaryPath == null)
option.MkvmergeBinaryPath = GlobalUtil.FindExecutable("mkvmerge");
option.MkvmergeBinaryPath ??= GlobalUtil.FindExecutable("mkvmerge");
if (string.IsNullOrEmpty(option.MkvmergeBinaryPath) || !File.Exists(option.MkvmergeBinaryPath))
{
throw new FileNotFoundException("mkvmerge not found");
@ -142,7 +140,7 @@ internal class Program
}
// 预先检查
if ((option.Keys != null && option.Keys.Length > 0) || option.KeyTextFile != null)
if (option.Keys is { Length: > 0 } || option.KeyTextFile != null)
{
if (string.IsNullOrEmpty(option.DecryptionBinaryPath))
{
@ -193,6 +191,11 @@ internal class Program
CustomeIV = option.CustomHLSIv,
};
if (option.AllowHlsMultiExtMap)
{
parserConfig.CustomParserArgs.Add("AllowHlsMultiExtMap", "true");
}
// demo1
parserConfig.ContentProcessors.Insert(0, new DemoProcessor());
// demo2
@ -225,13 +228,13 @@ internal class Program
// 全部媒体
var lists = streams.OrderBy(p => p.MediaType).ThenByDescending(p => p.Bandwidth).ThenByDescending(GetOrder);
var lists = streams.OrderBy(p => p.MediaType).ThenByDescending(p => p.Bandwidth).ThenByDescending(GetOrder).ToList();
// 基本流
var basicStreams = lists.Where(x => x.MediaType == null || x.MediaType == MediaType.VIDEO);
var basicStreams = lists.Where(x => x.MediaType is null or MediaType.VIDEO).ToList();
// 可选音频轨道
var audios = lists.Where(x => x.MediaType == MediaType.AUDIO);
var audios = lists.Where(x => x.MediaType == MediaType.AUDIO).ToList();
// 可选字幕轨道
var subs = lists.Where(x => x.MediaType == MediaType.SUBTITLES);
var subs = lists.Where(x => x.MediaType == MediaType.SUBTITLES).ToList();
// 尝试从URL或文件读取文件名
if (string.IsNullOrEmpty(option.SaveName))
@ -246,7 +249,7 @@ internal class Program
// 写出文件
await WriteRawFilesAsync(option, extractor, tmpDir);
Logger.Info(ResString.streamsInfo, lists.Count(), basicStreams.Count(), audios.Count(), subs.Count());
Logger.Info(ResString.streamsInfo, lists.Count, basicStreams.Count, audios.Count, subs.Count);
foreach (var item in lists)
{
@ -259,7 +262,7 @@ internal class Program
basicStreams = FilterUtil.DoFilterDrop(basicStreams, option.DropVideoFilter);
audios = FilterUtil.DoFilterDrop(audios, option.DropAudioFilter);
subs = FilterUtil.DoFilterDrop(subs, option.DropSubtitleFilter);
lists = basicStreams.Concat(audios).Concat(subs).OrderBy(x => true);
lists = basicStreams.Concat(audios).Concat(subs).ToList();
}
if (option.DropVideoFilter != null) Logger.Extra($"DropVideoFilter => {option.DropVideoFilter}");