支持通过分片数量选择流; 支持过滤不需要的流

This commit is contained in:
nilaoda 2022-12-02 15:52:16 +08:00
parent 9cd8cec5cd
commit 66daf00b5a
7 changed files with 78 additions and 9 deletions

View File

@ -54,6 +54,14 @@ namespace N_m3u8DL_RE.Common.Entity
public Playlist? Playlist { get; set; } public Playlist? Playlist { get; set; }
public int SegmentsCount
{
get
{
return Playlist != null ? Playlist.MediaParts.Sum(x => x.MediaSegments.Count) : 0;
}
}
public string ToShortString() public string ToShortString()
{ {
var prefixStr = ""; var prefixStr = "";
@ -93,8 +101,7 @@ namespace N_m3u8DL_RE.Common.Entity
var prefixStr = ""; var prefixStr = "";
var returnStr = ""; var returnStr = "";
var encStr = string.Empty; var encStr = string.Empty;
var segmentsCount = Playlist != null ? Playlist.MediaParts.Sum(x => x.MediaSegments.Count) : 0; var segmentsCountStr = SegmentsCount == 0 ? "" : (SegmentsCount > 1 ? $"{SegmentsCount} Segments" : $"{SegmentsCount} Segment");
var segmentsCountStr = segmentsCount == 0 ? "" : (segmentsCount > 1 ? $"{segmentsCount} Segments" : $"{segmentsCount} Segment");
//增加加密标志 //增加加密标志
if (Playlist != null && Playlist.MediaParts.Any(m => m.MediaSegments.Any(s => s.EncryptInfo.Method != EncryptMethod.NONE))) if (Playlist != null && Playlist.MediaParts.Any(m => m.MediaSegments.Any(s => s.EncryptInfo.Method != EncryptMethod.NONE)))

View File

@ -32,10 +32,13 @@ namespace N_m3u8DL_RE.Common.Resource
public static string cmd_muxImport { get => GetText("cmd_muxImport"); } public static string cmd_muxImport { get => GetText("cmd_muxImport"); }
public static string cmd_muxImport_more { get => GetText("cmd_muxImport_more"); } public static string cmd_muxImport_more { get => GetText("cmd_muxImport_more"); }
public static string cmd_selectVideo { get => GetText("cmd_selectVideo"); } public static string cmd_selectVideo { get => GetText("cmd_selectVideo"); }
public static string cmd_dropVideo { get => GetText("cmd_dropVideo"); }
public static string cmd_selectVideo_more { get => GetText("cmd_selectVideo_more"); } public static string cmd_selectVideo_more { get => GetText("cmd_selectVideo_more"); }
public static string cmd_selectAudio { get => GetText("cmd_selectAudio"); } public static string cmd_selectAudio { get => GetText("cmd_selectAudio"); }
public static string cmd_dropAudio { get => GetText("cmd_dropAudio"); }
public static string cmd_selectAudio_more { get => GetText("cmd_selectAudio_more"); } public static string cmd_selectAudio_more { get => GetText("cmd_selectAudio_more"); }
public static string cmd_selectSubtitle { get => GetText("cmd_selectSubtitle"); } public static string cmd_selectSubtitle { get => GetText("cmd_selectSubtitle"); }
public static string cmd_dropSubtitle { get => GetText("cmd_dropSubtitle"); }
public static string cmd_selectSubtitle_more { get => GetText("cmd_selectSubtitle_more"); } public static string cmd_selectSubtitle_more { get => GetText("cmd_selectSubtitle_more"); }
public static string cmd_customHLSMethod { get => GetText("cmd_customHLSMethod"); } public static string cmd_customHLSMethod { get => GetText("cmd_customHLSMethod"); }
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); } public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }

View File

@ -334,11 +334,17 @@ namespace N_m3u8DL_RE.Common.Resource
zhTW: "通過正則表達式選擇符合要求的影片軌. 輸入 \"--morehelp select-video\" 以查看詳細訊息", zhTW: "通過正則表達式選擇符合要求的影片軌. 輸入 \"--morehelp select-video\" 以查看詳細訊息",
enUS: "Select video streams by regular expressions. Use \"--morehelp select-video\" for more details" enUS: "Select video streams by regular expressions. Use \"--morehelp select-video\" for more details"
), ),
["cmd_dropVideo"] = new TextContainer
(
zhCN: "通过正则表达式去除符合要求的视频流.",
zhTW: "通過正則表達式去除符合要求的影片串流.",
enUS: "Drop video streams by regular expressions."
),
["cmd_selectVideo_more"] = new TextContainer ["cmd_selectVideo_more"] = new TextContainer
( (
zhCN: "通过正则表达式选择符合要求的视频流. 你能够以:分隔形式指定如下参数:\r\n\r\n" + zhCN: "通过正则表达式选择符合要求的视频流. 你能够以:分隔形式指定如下参数:\r\n\r\n" +
"id=REGEX:lang=REGEX:name=REGEX:codec=REGEX:res=REGEX\r\n" + "id=REGEX:lang=REGEX:name=REGEX:codec=REGEX:res=REGEX:frame=REGEX\r\n" +
"frame=REGEX:ch=REGEX:range=REGEX:url=REGEX:for=FOR\r\n\r\n" + "segsMin=number:segsMax=number:ch=REGEX:range=REGEX:url=REGEX:for=FOR\r\n\r\n" +
"* for=FOR: 选择方式. best[number], worst[number], all (默认: best)\r\n\r\n" + "* for=FOR: 选择方式. best[number], worst[number], all (默认: best)\r\n\r\n" +
"例如: \r\n" + "例如: \r\n" +
"# 选择最佳视频\r\n" + "# 选择最佳视频\r\n" +
@ -370,6 +376,12 @@ namespace N_m3u8DL_RE.Common.Resource
zhTW: "通過正則表達式選擇符合要求的音軌. 輸入 \"--morehelp select-audio\" 以查看詳細訊息", zhTW: "通過正則表達式選擇符合要求的音軌. 輸入 \"--morehelp select-audio\" 以查看詳細訊息",
enUS: "Select audio streams by regular expressions. Use \"--morehelp select-audio\" for more details" enUS: "Select audio streams by regular expressions. Use \"--morehelp select-audio\" for more details"
), ),
["cmd_dropAudio"] = new TextContainer
(
zhCN: "通过正则表达式去除符合要求的音频流.",
zhTW: "通過正則表達式去除符合要求的音軌.",
enUS: "Drop audio streams by regular expressions."
),
["cmd_selectAudio_more"] = new TextContainer ["cmd_selectAudio_more"] = new TextContainer
( (
zhCN: "通过正则表达式选择符合要求的音频流. 参考 --select-video\r\n\r\n" + zhCN: "通过正则表达式选择符合要求的音频流. 参考 --select-video\r\n\r\n" +
@ -403,6 +415,12 @@ namespace N_m3u8DL_RE.Common.Resource
zhTW: "通過正則表達式選擇符合要求的字幕流. 輸入 \"--morehelp select-subtitle\" 以查看詳細訊息", zhTW: "通過正則表達式選擇符合要求的字幕流. 輸入 \"--morehelp select-subtitle\" 以查看詳細訊息",
enUS: "Select subtitle streams by regular expressions. Use \"--morehelp select-subtitle\" for more details" enUS: "Select subtitle streams by regular expressions. Use \"--morehelp select-subtitle\" for more details"
), ),
["cmd_dropSubtitle"] = new TextContainer
(
zhCN: "通过正则表达式去除符合要求的字幕流.",
zhTW: "通過正則表達式去除符合要求的字幕流.",
enUS: "Drop subtitle streams by regular expressions."
),
["cmd_selectSubtitle_more"] = new TextContainer ["cmd_selectSubtitle_more"] = new TextContainer
( (
zhCN: "通过正则表达式选择符合要求的字幕流. 参考 --select-video\r\n\r\n" + zhCN: "通过正则表达式选择符合要求的字幕流. 参考 --select-video\r\n\r\n" +

View File

@ -84,6 +84,10 @@ namespace N_m3u8DL_RE.CommandLine
private readonly static Option<StreamFilter?> AudioFilter = new(new string[] { "-sa", "--select-audio" }, description: ResString.cmd_selectAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" }; private readonly static Option<StreamFilter?> AudioFilter = new(new string[] { "-sa", "--select-audio" }, description: ResString.cmd_selectAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
private readonly static Option<StreamFilter?> SubtitleFilter = new(new string[] { "-ss", "--select-subtitle" }, description: ResString.cmd_selectSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" }; private readonly static Option<StreamFilter?> SubtitleFilter = new(new string[] { "-ss", "--select-subtitle" }, description: ResString.cmd_selectSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
private readonly static Option<StreamFilter?> DropVideoFilter = new(new string[] { "-dv", "--drop-video" }, description: ResString.cmd_dropVideo, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
private readonly static Option<StreamFilter?> DropAudioFilter = new(new string[] { "-da", "--drop-audio" }, description: ResString.cmd_dropAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
private readonly static Option<StreamFilter?> DropSubtitleFilter = new(new string[] { "-ds", "--drop-subtitle" }, description: ResString.cmd_dropSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
/// <summary> /// <summary>
/// 解析用户代理 /// 解析用户代理
/// </summary> /// </summary>
@ -236,6 +240,14 @@ namespace N_m3u8DL_RE.CommandLine
if (!string.IsNullOrEmpty(url)) if (!string.IsNullOrEmpty(url))
streamFilter.UrlReg = new Regex(url); streamFilter.UrlReg = new Regex(url);
var segsMin = p.GetValue("segsMin");
if (!string.IsNullOrEmpty(segsMin))
streamFilter.SegmentsMinCount = long.Parse(segsMin);
var segsMax = p.GetValue("segsMax");
if (!string.IsNullOrEmpty(segsMax))
streamFilter.SegmentsMaxCount = long.Parse(segsMax);
return streamFilter; return streamFilter;
} }
@ -373,6 +385,9 @@ namespace N_m3u8DL_RE.CommandLine
VideoFilter = bindingContext.ParseResult.GetValueForOption(VideoFilter), VideoFilter = bindingContext.ParseResult.GetValueForOption(VideoFilter),
AudioFilter = bindingContext.ParseResult.GetValueForOption(AudioFilter), AudioFilter = bindingContext.ParseResult.GetValueForOption(AudioFilter),
SubtitleFilter = bindingContext.ParseResult.GetValueForOption(SubtitleFilter), SubtitleFilter = bindingContext.ParseResult.GetValueForOption(SubtitleFilter),
DropVideoFilter = bindingContext.ParseResult.GetValueForOption(DropVideoFilter),
DropAudioFilter = bindingContext.ParseResult.GetValueForOption(DropAudioFilter),
DropSubtitleFilter = bindingContext.ParseResult.GetValueForOption(DropSubtitleFilter),
LiveRealTimeMerge = bindingContext.ParseResult.GetValueForOption(LiveRealTimeMerge), LiveRealTimeMerge = bindingContext.ParseResult.GetValueForOption(LiveRealTimeMerge),
LiveKeepSegments = bindingContext.ParseResult.GetValueForOption(LiveKeepSegments), LiveKeepSegments = bindingContext.ParseResult.GetValueForOption(LiveKeepSegments),
LiveRecordLimit = bindingContext.ParseResult.GetValueForOption(LiveRecordLimit), LiveRecordLimit = bindingContext.ParseResult.GetValueForOption(LiveRecordLimit),
@ -447,7 +462,7 @@ namespace N_m3u8DL_RE.CommandLine
MuxAfterDone, MuxAfterDone,
CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy, CustomProxy, CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy, CustomProxy,
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LiveRecordLimit, LiveWaitTime, LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LiveRecordLimit, LiveWaitTime,
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, MoreHelp MuxImports, VideoFilter, AudioFilter, SubtitleFilter, DropVideoFilter, DropAudioFilter, DropSubtitleFilter, MoreHelp
}; };
rootCommand.TreatUnmatchedTokensAsErrors = true; rootCommand.TreatUnmatchedTokensAsErrors = true;

View File

@ -19,6 +19,8 @@ namespace N_m3u8DL_RE.Entity
public Regex? ChannelsReg { get; set; } public Regex? ChannelsReg { get; set; }
public Regex? VideoRangeReg { get; set; } public Regex? VideoRangeReg { get; set; }
public Regex? UrlReg { get; set; } public Regex? UrlReg { get; set; }
public long? SegmentsMinCount { get; set; }
public long? SegmentsMaxCount { get; set; }
public string For { get; set; } = "best"; public string For { get; set; } = "best";
} }

View File

@ -198,6 +198,14 @@ namespace N_m3u8DL_RE
} }
var selectedStreams = new List<StreamSpec>(); var selectedStreams = new List<StreamSpec>();
if (option.DropVideoFilter != null || option.DropAudioFilter != null || option.DropSubtitleFilter != null)
{
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);
}
if (option.AutoSelect) if (option.AutoSelect)
{ {
if (basicStreams.Any()) if (basicStreams.Any())
@ -215,9 +223,9 @@ namespace N_m3u8DL_RE
} }
else if (option.VideoFilter != null || option.AudioFilter != null || option.SubtitleFilter != null) else if (option.VideoFilter != null || option.AudioFilter != null || option.SubtitleFilter != null)
{ {
basicStreams = FilterUtil.DoFilter(basicStreams, option.VideoFilter); basicStreams = FilterUtil.DoFilterKeep(basicStreams, option.VideoFilter);
audios = FilterUtil.DoFilter(audios, option.AudioFilter); audios = FilterUtil.DoFilterKeep(audios, option.AudioFilter);
subs = FilterUtil.DoFilter(subs, option.SubtitleFilter); subs = FilterUtil.DoFilterKeep(subs, option.SubtitleFilter);
selectedStreams = basicStreams.Concat(audios).Concat(subs).ToList(); selectedStreams = basicStreams.Concat(audios).Concat(subs).ToList();
} }
else else

View File

@ -13,7 +13,7 @@ namespace N_m3u8DL_RE.Util
{ {
public class FilterUtil public class FilterUtil
{ {
public static List<StreamSpec> DoFilter(IEnumerable<StreamSpec> lists, StreamFilter? filter) public static List<StreamSpec> DoFilterKeep(IEnumerable<StreamSpec> lists, StreamFilter? filter)
{ {
if (filter == null) return new List<StreamSpec>(); if (filter == null) return new List<StreamSpec>();
@ -36,6 +36,10 @@ namespace N_m3u8DL_RE.Util
inputs = inputs.Where(i => i.VideoRange != null && filter.VideoRangeReg.IsMatch(i.VideoRange)); inputs = inputs.Where(i => i.VideoRange != null && filter.VideoRangeReg.IsMatch(i.VideoRange));
if (filter.UrlReg != null) if (filter.UrlReg != null)
inputs = inputs.Where(i => i.Url != null && filter.UrlReg.IsMatch(i.Url)); inputs = inputs.Where(i => i.Url != null && filter.UrlReg.IsMatch(i.Url));
if (filter.SegmentsMaxCount != null && inputs.All(i => i.SegmentsCount > 0))
inputs = inputs.Where(i => i.SegmentsCount < filter.SegmentsMaxCount);
if (filter.SegmentsMinCount != null && inputs.All(i => i.SegmentsCount > 0))
inputs = inputs.Where(i => i.SegmentsCount > filter.SegmentsMinCount);
var bestNumberStr = filter.For.Replace("best", ""); var bestNumberStr = filter.For.Replace("best", "");
var worstNumberStr = filter.For.Replace("worst", ""); var worstNumberStr = filter.For.Replace("worst", "");
@ -52,6 +56,18 @@ namespace N_m3u8DL_RE.Util
return inputs.ToList(); return inputs.ToList();
} }
public static List<StreamSpec> DoFilterDrop(IEnumerable<StreamSpec> lists, StreamFilter? filter)
{
if (filter == null) return new List<StreamSpec>();
var inputs = lists.Where(_ => true);
var selected = DoFilterKeep(lists, filter);
inputs = inputs.SkipWhile(i => selected.Any(s => s.ToString() == i.ToString()));
return inputs.ToList();
}
public static List<StreamSpec> SelectStreams(IEnumerable<StreamSpec> lists) public static List<StreamSpec> SelectStreams(IEnumerable<StreamSpec> lists)
{ {
if (lists.Count() == 1) if (lists.Count() == 1)