支持通过分片数量选择流; 支持过滤不需要的流
This commit is contained in:
parent
9cd8cec5cd
commit
66daf00b5a
|
@ -54,6 +54,14 @@ namespace N_m3u8DL_RE.Common.Entity
|
|||
|
||||
public Playlist? Playlist { get; set; }
|
||||
|
||||
public int SegmentsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return Playlist != null ? Playlist.MediaParts.Sum(x => x.MediaSegments.Count) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public string ToShortString()
|
||||
{
|
||||
var prefixStr = "";
|
||||
|
@ -93,8 +101,7 @@ namespace N_m3u8DL_RE.Common.Entity
|
|||
var prefixStr = "";
|
||||
var returnStr = "";
|
||||
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)))
|
||||
|
|
|
@ -32,10 +32,13 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
public static string cmd_muxImport { get => GetText("cmd_muxImport"); }
|
||||
public static string cmd_muxImport_more { get => GetText("cmd_muxImport_more"); }
|
||||
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_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_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_customHLSMethod { get => GetText("cmd_customHLSMethod"); }
|
||||
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }
|
||||
|
|
|
@ -334,11 +334,17 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
zhTW: "通過正則表達式選擇符合要求的影片軌. 輸入 \"--morehelp select-video\" 以查看詳細訊息",
|
||||
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
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的视频流. 你能够以:分隔形式指定如下参数:\r\n\r\n" +
|
||||
"id=REGEX:lang=REGEX:name=REGEX:codec=REGEX:res=REGEX\r\n" +
|
||||
"frame=REGEX:ch=REGEX:range=REGEX:url=REGEX:for=FOR\r\n\r\n" +
|
||||
"id=REGEX:lang=REGEX:name=REGEX:codec=REGEX:res=REGEX:frame=REGEX\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" +
|
||||
"例如: \r\n" +
|
||||
"# 选择最佳视频\r\n" +
|
||||
|
@ -370,6 +376,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
zhTW: "通過正則表達式選擇符合要求的音軌. 輸入 \"--morehelp select-audio\" 以查看詳細訊息",
|
||||
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
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的音频流. 参考 --select-video\r\n\r\n" +
|
||||
|
@ -403,6 +415,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
zhTW: "通過正則表達式選擇符合要求的字幕流. 輸入 \"--morehelp select-subtitle\" 以查看詳細訊息",
|
||||
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
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的字幕流. 参考 --select-video\r\n\r\n" +
|
||||
|
|
|
@ -83,6 +83,10 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
private readonly static Option<StreamFilter?> VideoFilter = new(new string[] { "-sv", "--select-video" }, description: ResString.cmd_selectVideo, 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?> 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>
|
||||
/// 解析用户代理
|
||||
|
@ -236,6 +240,14 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
if (!string.IsNullOrEmpty(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;
|
||||
}
|
||||
|
||||
|
@ -373,6 +385,9 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
VideoFilter = bindingContext.ParseResult.GetValueForOption(VideoFilter),
|
||||
AudioFilter = bindingContext.ParseResult.GetValueForOption(AudioFilter),
|
||||
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),
|
||||
LiveKeepSegments = bindingContext.ParseResult.GetValueForOption(LiveKeepSegments),
|
||||
LiveRecordLimit = bindingContext.ParseResult.GetValueForOption(LiveRecordLimit),
|
||||
|
@ -447,7 +462,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
MuxAfterDone,
|
||||
CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy, CustomProxy,
|
||||
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LiveRecordLimit, LiveWaitTime,
|
||||
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, MoreHelp
|
||||
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, DropVideoFilter, DropAudioFilter, DropSubtitleFilter, MoreHelp
|
||||
};
|
||||
|
||||
rootCommand.TreatUnmatchedTokensAsErrors = true;
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace N_m3u8DL_RE.Entity
|
|||
public Regex? ChannelsReg { get; set; }
|
||||
public Regex? VideoRangeReg { get; set; }
|
||||
public Regex? UrlReg { get; set; }
|
||||
public long? SegmentsMinCount { get; set; }
|
||||
public long? SegmentsMaxCount { get; set; }
|
||||
|
||||
public string For { get; set; } = "best";
|
||||
}
|
||||
|
|
|
@ -198,6 +198,14 @@ namespace N_m3u8DL_RE
|
|||
}
|
||||
|
||||
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 (basicStreams.Any())
|
||||
|
@ -215,9 +223,9 @@ namespace N_m3u8DL_RE
|
|||
}
|
||||
else if (option.VideoFilter != null || option.AudioFilter != null || option.SubtitleFilter != null)
|
||||
{
|
||||
basicStreams = FilterUtil.DoFilter(basicStreams, option.VideoFilter);
|
||||
audios = FilterUtil.DoFilter(audios, option.AudioFilter);
|
||||
subs = FilterUtil.DoFilter(subs, option.SubtitleFilter);
|
||||
basicStreams = FilterUtil.DoFilterKeep(basicStreams, option.VideoFilter);
|
||||
audios = FilterUtil.DoFilterKeep(audios, option.AudioFilter);
|
||||
subs = FilterUtil.DoFilterKeep(subs, option.SubtitleFilter);
|
||||
selectedStreams = basicStreams.Concat(audios).Concat(subs).ToList();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace N_m3u8DL_RE.Util
|
|||
{
|
||||
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>();
|
||||
|
||||
|
@ -36,6 +36,10 @@ namespace N_m3u8DL_RE.Util
|
|||
inputs = inputs.Where(i => i.VideoRange != null && filter.VideoRangeReg.IsMatch(i.VideoRange));
|
||||
if (filter.UrlReg != null)
|
||||
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 worstNumberStr = filter.For.Replace("worst", "");
|
||||
|
@ -52,6 +56,18 @@ namespace N_m3u8DL_RE.Util
|
|||
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)
|
||||
{
|
||||
if (lists.Count() == 1)
|
||||
|
|
Loading…
Reference in New Issue