支持命令行选择视频、音频和字幕
This commit is contained in:
parent
983599b61f
commit
9bf57058cf
|
@ -28,6 +28,9 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string cmd_baseUrl { get => GetText("cmd_baseUrl"); }
|
public static string cmd_baseUrl { get => GetText("cmd_baseUrl"); }
|
||||||
public static string cmd_header { get => GetText("cmd_header"); }
|
public static string cmd_header { get => GetText("cmd_header"); }
|
||||||
public static string cmd_muxImport { get => GetText("cmd_muxImport"); }
|
public static string cmd_muxImport { get => GetText("cmd_muxImport"); }
|
||||||
|
public static string cmd_selectVideo { get => GetText("cmd_selectVideo"); }
|
||||||
|
public static string cmd_selectAudio { get => GetText("cmd_selectAudio"); }
|
||||||
|
public static string cmd_selectSubtitle { get => GetText("cmd_selectSubtitle"); }
|
||||||
public static string cmd_Input { get => GetText("cmd_Input"); }
|
public static string cmd_Input { get => GetText("cmd_Input"); }
|
||||||
public static string cmd_keys { get => GetText("cmd_keys"); }
|
public static string cmd_keys { get => GetText("cmd_keys"); }
|
||||||
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
||||||
|
@ -49,9 +52,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
||||||
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
||||||
public static string cmd_concurrentDownload { get => GetText("cmd_concurrentDownload"); }
|
public static string cmd_concurrentDownload { get => GetText("cmd_concurrentDownload"); }
|
||||||
public static string cmd_useMkvmerge { get => GetText("cmd_useMkvmerge"); }
|
|
||||||
public static string cmd_muxAfterDone { get => GetText("cmd_muxAfterDone"); }
|
public static string cmd_muxAfterDone { get => GetText("cmd_muxAfterDone"); }
|
||||||
public static string cmd_muxToMp4 { get => GetText("cmd_muxToMp4"); }
|
|
||||||
public static string cmd_writeMetaJson { get => GetText("cmd_writeMetaJson"); }
|
public static string cmd_writeMetaJson { get => GetText("cmd_writeMetaJson"); }
|
||||||
public static string fetch { get => GetText("fetch"); }
|
public static string fetch { get => GetText("fetch"); }
|
||||||
public static string ffmpegMerge { get => GetText("ffmpegMerge"); }
|
public static string ffmpegMerge { get => GetText("ffmpegMerge"); }
|
||||||
|
@ -78,6 +79,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string startDownloading { get => GetText("startDownloading"); }
|
public static string startDownloading { get => GetText("startDownloading"); }
|
||||||
public static string streamsInfo { get => GetText("streamsInfo"); }
|
public static string streamsInfo { get => GetText("streamsInfo"); }
|
||||||
public static string writeJson { get => GetText("writeJson"); }
|
public static string writeJson { get => GetText("writeJson"); }
|
||||||
|
public static string noStreamsToDownload { get => GetText("noStreamsToDownload"); }
|
||||||
|
|
||||||
private static string GetText(string key)
|
private static string GetText(string key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -238,18 +238,90 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
zhTW: "解密时使用shaka-packager替代mp4decrypt",
|
zhTW: "解密时使用shaka-packager替代mp4decrypt",
|
||||||
enUS: "Use shaka-packager instead of mp4decrypt to decrypt"
|
enUS: "Use shaka-packager instead of mp4decrypt to decrypt"
|
||||||
),
|
),
|
||||||
["cmd_useMkvmerge"] = new TextContainer
|
|
||||||
(
|
|
||||||
zhCN: "混流时使用mkvmerge替代ffmpeg",
|
|
||||||
zhTW: "混流时使用mkvmerge替代ffmpeg",
|
|
||||||
enUS: "Use mkvmerge instead of ffmpeg to mux"
|
|
||||||
),
|
|
||||||
["cmd_concurrentDownload"] = new TextContainer
|
["cmd_concurrentDownload"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "并发下载已选择的音频、视频和字幕",
|
zhCN: "并发下载已选择的音频、视频和字幕",
|
||||||
zhTW: "並發下載已選擇的音訊、影片和字幕",
|
zhTW: "並發下載已選擇的音訊、影片和字幕",
|
||||||
enUS: "Concurrently download the selected audio, video and subtitles"
|
enUS: "Concurrently download the selected audio, video and subtitles"
|
||||||
),
|
),
|
||||||
|
["cmd_selectVideo"] = 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" +
|
||||||
|
"* for=FOR: 选择方式. best[number], worst[number], all (默认: best)\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 选择最佳视频\r\n" +
|
||||||
|
"-sv best\r\n" +
|
||||||
|
"# 选择4K+HEVC视频\r\n" +
|
||||||
|
"-sv res=\"3840*\":codec=hvc1:for=best\r\n",
|
||||||
|
zhTW: "通過正則表達式選擇符合要求的影片軌. 你能夠以:分隔形式指定如下參數:\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" +
|
||||||
|
"* for=FOR: 選擇方式. best[number], worst[number], all (默認: best)\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 選擇最佳影片\r\n" +
|
||||||
|
"-sv best\r\n" +
|
||||||
|
"# 選擇4K+HEVC影片\r\n" +
|
||||||
|
"-sv res=\"3840*\":codec=hvc1:for=best\r\n",
|
||||||
|
enUS: "Select video streams by regular expressions. OPTIONS is a colon separated list of:\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" +
|
||||||
|
"* for=FOR: Select type. best[number], worst[number], all (Default: best)\r\n\r\n" +
|
||||||
|
"Examples: \r\n" +
|
||||||
|
"# select best video\r\n" +
|
||||||
|
"-sv best\r\n" +
|
||||||
|
"# select 4K+HEVC video\r\n" +
|
||||||
|
"-sv res=\"3840*\":codec=hvc1:for=best\r\n"
|
||||||
|
),
|
||||||
|
["cmd_selectAudio"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "通过正则表达式选择符合要求的音频流. 参考 --select-video\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 选择所有音频\r\n" +
|
||||||
|
"-sa all\r\n" +
|
||||||
|
"# 选择最佳英语音轨\r\n" +
|
||||||
|
"-sa lang=en:for=best\r\n" +
|
||||||
|
"# 选择最佳的2条英语(或日语)音轨\r\n" +
|
||||||
|
"-sa lang=\"ja|en\":for=best2\r\n",
|
||||||
|
zhTW: "通過正則表達式選擇符合要求的音軌. 參考 --select-video\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 選擇所有音訊\r\n" +
|
||||||
|
"-sa all\r\n" +
|
||||||
|
"# 選擇最佳英語音軌\r\n" +
|
||||||
|
"-sa lang=en:for=best\r\n" +
|
||||||
|
"# 選擇最佳的2條英語(或日語)音軌\r\n" +
|
||||||
|
"-sa lang=\"ja|en\":for=best2\r\n",
|
||||||
|
enUS: "Select audio streams by regular expressions. ref --select-video\r\n\r\n" +
|
||||||
|
"Examples: \r\n" +
|
||||||
|
"# select all\r\n" +
|
||||||
|
"-sa all\r\n" +
|
||||||
|
"# select best eng audio\r\n" +
|
||||||
|
"-sa lang=en:for=best\r\n" +
|
||||||
|
"# select best 2, and language is ja or en\r\n" +
|
||||||
|
"-sa lang=\"ja|en\":for=best2\r\n"
|
||||||
|
),
|
||||||
|
["cmd_selectSubtitle"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "通过正则表达式选择符合要求的字幕流. 参考 --select-video\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 选择所有字幕\r\n" +
|
||||||
|
"-ss all\r\n" +
|
||||||
|
"# 选择所有带有\"中文\"的字幕\r\n" +
|
||||||
|
"-ss name=\"中文\":for=all\r\n",
|
||||||
|
zhTW: "通過正則表達式選擇符合要求的字幕流. 參考 --select-video\r\n\r\n" +
|
||||||
|
"例如: \r\n" +
|
||||||
|
"# 選擇所有字幕\r\n" +
|
||||||
|
"-ss all\r\n" +
|
||||||
|
"# 選擇所有帶有\"中文\"的字幕\r\n" +
|
||||||
|
"-ss name=\"中文\":for=all\r\n",
|
||||||
|
enUS: "Select subtitle streams by regular expressions. ref --select-video\r\n\r\n" +
|
||||||
|
"Examples: \r\n" +
|
||||||
|
"# select all subs\r\n" +
|
||||||
|
"-ss all\r\n" +
|
||||||
|
"# select all subs containing \"English\"\r\n" +
|
||||||
|
"-ss name=\"English\":for=all\r\n"
|
||||||
|
),
|
||||||
["cmd_muxAfterDone"] = new TextContainer
|
["cmd_muxAfterDone"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "所有工作完成时尝试混流分离的音视频. 你能够以:分隔形式指定如下参数:\r\n\r\n" +
|
zhCN: "所有工作完成时尝试混流分离的音视频. 你能够以:分隔形式指定如下参数:\r\n\r\n" +
|
||||||
|
@ -258,11 +330,11 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
"* bin_path=PATH: 指定程序路径 (默认: 自动寻找)\r\n" +
|
"* bin_path=PATH: 指定程序路径 (默认: 自动寻找)\r\n" +
|
||||||
"* keep=BOOL: 混流完成是否删除文件 true, false (默认: true)\r\n\r\n" +
|
"* keep=BOOL: 混流完成是否删除文件 true, false (默认: true)\r\n\r\n" +
|
||||||
"例如: \r\n" +
|
"例如: \r\n" +
|
||||||
"\r\n#混流为mp4容器\r\n" +
|
"# 混流为mp4容器\r\n" +
|
||||||
"-M format=mp4\r\n" +
|
"-M format=mp4\r\n" +
|
||||||
"\r\n#使用mkvmerge, 自动寻找程序\r\n" +
|
"# 使用mkvmerge, 自动寻找程序\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge\r\n" +
|
"-M format=mkv:muxer=mkvmerge\r\n" +
|
||||||
"\r\n#使用mkvmerge, 自定义程序路径\r\n" +
|
"# 使用mkvmerge, 自定义程序路径\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n",
|
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n",
|
||||||
zhTW: "所有工作完成時嘗試混流分離的影音. 你能夠以:分隔形式指定如下參數:\r\n\r\n" +
|
zhTW: "所有工作完成時嘗試混流分離的影音. 你能夠以:分隔形式指定如下參數:\r\n\r\n" +
|
||||||
"* format=FORMAT: 指定混流容器 mkv, mp4\r\n" +
|
"* format=FORMAT: 指定混流容器 mkv, mp4\r\n" +
|
||||||
|
@ -270,11 +342,11 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
"* bin_path=PATH: 指定程序路徑 (默認: 自動尋找)\r\n" +
|
"* bin_path=PATH: 指定程序路徑 (默認: 自動尋找)\r\n" +
|
||||||
"* keep=BOOL: 混流完成是否刪除文件 true, false (默認: true)\r\n\r\n" +
|
"* keep=BOOL: 混流完成是否刪除文件 true, false (默認: true)\r\n\r\n" +
|
||||||
"例如: \r\n" +
|
"例如: \r\n" +
|
||||||
"\r\n#混流為mp4容器\r\n" +
|
"# 混流為mp4容器\r\n" +
|
||||||
"-M format=mp4\r\n" +
|
"-M format=mp4\r\n" +
|
||||||
"\r\n#使用mkvmerge, 自動尋找程序\r\n" +
|
"# 使用mkvmerge, 自動尋找程序\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge\r\n" +
|
"-M format=mkv:muxer=mkvmerge\r\n" +
|
||||||
"\r\n#使用mkvmerge, 自訂程序路徑\r\n" +
|
"# 使用mkvmerge, 自訂程序路徑\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n",
|
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n",
|
||||||
enUS: "When all works is done, try to mux the downloaded streams. OPTIONS is a colon separated list of:\r\n\r\n" +
|
enUS: "When all works is done, try to mux the downloaded streams. OPTIONS is a colon separated list of:\r\n\r\n" +
|
||||||
"* format=FORMAT: set container. mkv, mp4\r\n" +
|
"* format=FORMAT: set container. mkv, mp4\r\n" +
|
||||||
|
@ -282,11 +354,11 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
"* bin_path=PATH: set binary file path. (Default: auto)\r\n" +
|
"* bin_path=PATH: set binary file path. (Default: auto)\r\n" +
|
||||||
"* keep=BOOL: set whether or not delete files. true, false (Default: true)\r\n\r\n" +
|
"* keep=BOOL: set whether or not delete files. true, false (Default: true)\r\n\r\n" +
|
||||||
"Examples: \r\n" +
|
"Examples: \r\n" +
|
||||||
"\r\n#mux to mp4\r\n" +
|
"# mux to mp4\r\n" +
|
||||||
"-M format=mp4\r\n" +
|
"-M format=mp4\r\n" +
|
||||||
"\r\n#use mkvmerge, auto detect bin path\r\n" +
|
"# use mkvmerge, auto detect bin path\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge\r\n" +
|
"-M format=mkv:muxer=mkvmerge\r\n" +
|
||||||
"\r\n#use mkvmerge, set bin path\r\n" +
|
"# use mkvmerge, set bin path\r\n" +
|
||||||
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n"
|
"-M format=mkv:muxer=mkvmerge:bin_path=\"C\\:\\Program Files\\MKVToolNix\\mkvmerge.exe\"\r\n"
|
||||||
),
|
),
|
||||||
["cmd_muxImport"] = new TextContainer
|
["cmd_muxImport"] = new TextContainer
|
||||||
|
@ -296,35 +368,29 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
"* lang=CODE: 指定媒体文件语言代码 (非必须)\r\n" +
|
"* lang=CODE: 指定媒体文件语言代码 (非必须)\r\n" +
|
||||||
"* name=NAME: 指定媒体文件描述信息 (非必须)\r\n\r\n" +
|
"* name=NAME: 指定媒体文件描述信息 (非必须)\r\n\r\n" +
|
||||||
"例如: \r\n" +
|
"例如: \r\n" +
|
||||||
"\r\n#引入外部字幕\r\n" +
|
"# 引入外部字幕\r\n" +
|
||||||
"--mux-import path=zh-Hans.srt:lang=chi:name=\"中文 (简体)\"\r\n" +
|
"--mux-import path=zh-Hans.srt:lang=chi:name=\"中文 (简体)\"\r\n" +
|
||||||
"\r\n#引入外部音轨+字幕\r\n" +
|
"# 引入外部音轨+字幕\r\n" +
|
||||||
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\"",
|
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\"",
|
||||||
zhTW: "混流時引入外部媒體檔案. 你能夠以:分隔形式指定如下參數:\r\n\r\n" +
|
zhTW: "混流時引入外部媒體檔案. 你能夠以:分隔形式指定如下參數:\r\n\r\n" +
|
||||||
"* path=PATH: 指定媒體檔案路徑\r\n" +
|
"* path=PATH: 指定媒體檔案路徑\r\n" +
|
||||||
"* lang=CODE: 指定媒體檔案語言代碼 (非必須)\r\n" +
|
"* lang=CODE: 指定媒體檔案語言代碼 (非必須)\r\n" +
|
||||||
"* name=NAME: 指定媒體檔案描述訊息 (非必須)\r\n\r\n" +
|
"* name=NAME: 指定媒體檔案描述訊息 (非必須)\r\n\r\n" +
|
||||||
"例如: \r\n" +
|
"例如: \r\n" +
|
||||||
"\r\n#引入外部字幕\r\n" +
|
"# 引入外部字幕\r\n" +
|
||||||
"--mux-import path=zh-Hant.srt:lang=chi:name=\"中文 (繁體)\"\r\n" +
|
"--mux-import path=zh-Hant.srt:lang=chi:name=\"中文 (繁體)\"\r\n" +
|
||||||
"\r\n#引入外部音軌+字幕\r\n" +
|
"# 引入外部音軌+字幕\r\n" +
|
||||||
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\"",
|
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\"",
|
||||||
enUS: "When MuxAfterDone enabled, allow to import local media files. OPTIONS is a colon separated list of:\r\n\r\n" +
|
enUS: "When MuxAfterDone enabled, allow to import local media files. OPTIONS is a colon separated list of:\r\n\r\n" +
|
||||||
"* path=PATH: set file path\r\n" +
|
"* path=PATH: set file path\r\n" +
|
||||||
"* lang=CODE: set media language code (not required)\r\n" +
|
"* lang=CODE: set media language code (not required)\r\n" +
|
||||||
"* name=NAME: set description (not required)\r\n\r\n" +
|
"* name=NAME: set description (not required)\r\n\r\n" +
|
||||||
"Examples: \r\n" +
|
"Examples: \r\n" +
|
||||||
"\r\n#import subtitle\r\n" +
|
"# import subtitle\r\n" +
|
||||||
"--mux-import path=en-US.srt:lang=eng:name=\"English (Original)\"\r\n" +
|
"--mux-import path=en-US.srt:lang=eng:name=\"English (Original)\"\r\n" +
|
||||||
"\r\n#import audio and subtitle\r\n" +
|
"# import audio and subtitle\r\n" +
|
||||||
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\""
|
"--mux-import path=\"D\\:\\media\\atmos.m4a\":lang=eng:name=\"English Description Audio\" --mux-import path=\"D\\:\\media\\eng.vtt\":lang=eng:name=\"English (Description)\""
|
||||||
),
|
),
|
||||||
["cmd_muxToMp4"] = new TextContainer
|
|
||||||
(
|
|
||||||
zhCN: "混流时使用mp4容器而非mkv",
|
|
||||||
zhTW: "混流時使用mp4容器而非mkv",
|
|
||||||
enUS: "Use mp4 container instead of mkv when muxing"
|
|
||||||
),
|
|
||||||
["cmd_writeMetaJson"] = new TextContainer
|
["cmd_writeMetaJson"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "解析后的信息是否输出json文件",
|
zhCN: "解析后的信息是否输出json文件",
|
||||||
|
@ -481,6 +547,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
zhTW: "寫出meta json",
|
zhTW: "寫出meta json",
|
||||||
enUS: "Writing meta json"
|
enUS: "Writing meta json"
|
||||||
),
|
),
|
||||||
|
["noStreamsToDownload"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "没有找到需要下载的流",
|
||||||
|
zhTW: "沒有找到需要下載的流",
|
||||||
|
enUS: "No stream found to download"
|
||||||
|
),
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,15 @@ using System.CommandLine;
|
||||||
using System.CommandLine.Binding;
|
using System.CommandLine.Binding;
|
||||||
using System.CommandLine.Parsing;
|
using System.CommandLine.Parsing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.CommandLine
|
namespace N_m3u8DL_RE.CommandLine
|
||||||
{
|
{
|
||||||
internal class CommandInvoker
|
internal partial class CommandInvoker
|
||||||
{
|
{
|
||||||
|
[RegexGenerator("((best|worst)\\d*|all)")]
|
||||||
|
private static partial Regex ForStrRegex();
|
||||||
|
|
||||||
private readonly static Argument<string> Input = new(name: "input", description: ResString.cmd_Input);
|
private readonly static Argument<string> Input = new(name: "input", description: ResString.cmd_Input);
|
||||||
private readonly static Option<string?> TmpDir = new(new string[] { "--tmp-dir" }, description: ResString.cmd_tmpDir);
|
private readonly static Option<string?> TmpDir = new(new string[] { "--tmp-dir" }, description: ResString.cmd_tmpDir);
|
||||||
private readonly static Option<string?> SaveDir = new(new string[] { "--save-dir" }, description: ResString.cmd_saveDir);
|
private readonly static Option<string?> SaveDir = new(new string[] { "--save-dir" }, description: ResString.cmd_saveDir);
|
||||||
|
@ -27,8 +30,8 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
private readonly static Option<SubtitleFormat> SubtitleFormat = new(name: "--sub-format", description: ResString.cmd_subFormat, getDefaultValue: () => Enum.SubtitleFormat.VTT);
|
private readonly static Option<SubtitleFormat> SubtitleFormat = new(name: "--sub-format", description: ResString.cmd_subFormat, getDefaultValue: () => Enum.SubtitleFormat.VTT);
|
||||||
private readonly static Option<bool> AutoSelect = new(new string[] { "--auto-select" }, description: ResString.cmd_autoSelect, getDefaultValue: () => false);
|
private readonly static Option<bool> AutoSelect = new(new string[] { "--auto-select" }, description: ResString.cmd_autoSelect, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> SubOnly = new(new string[] { "--sub-only" }, description: ResString.cmd_subOnly, getDefaultValue: () => false);
|
private readonly static Option<bool> SubOnly = new(new string[] { "--sub-only" }, description: ResString.cmd_subOnly, getDefaultValue: () => false);
|
||||||
private readonly static Option<int> ThreadCount = new(new string[] { "--thread-count" }, description: ResString.cmd_threadCount, getDefaultValue: () => 8);
|
private readonly static Option<int> ThreadCount = new(new string[] { "--thread-count" }, description: ResString.cmd_threadCount, getDefaultValue: () => 8) { ArgumentHelpName = "number" };
|
||||||
private readonly static Option<int> DownloadRetryCount = new(new string[] { "--download-retry-count" }, description: ResString.cmd_downloadRetryCount, getDefaultValue: () => 3);
|
private readonly static Option<int> DownloadRetryCount = new(new string[] { "--download-retry-count" }, description: ResString.cmd_downloadRetryCount, getDefaultValue: () => 3) { ArgumentHelpName = "number" };
|
||||||
private readonly static Option<bool> SkipMerge = new(new string[] { "--skip-merge" }, description: ResString.cmd_skipMerge, getDefaultValue: () => false);
|
private readonly static Option<bool> SkipMerge = new(new string[] { "--skip-merge" }, description: ResString.cmd_skipMerge, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> SkipDownload = new(new string[] { "--skip-download" }, description: ResString.cmd_skipDownload, getDefaultValue: () => false);
|
private readonly static Option<bool> SkipDownload = new(new string[] { "--skip-download" }, description: ResString.cmd_skipDownload, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> BinaryMerge = new(new string[] { "--binary-merge" }, description: ResString.cmd_binaryMerge, getDefaultValue: () => false);
|
private readonly static Option<bool> BinaryMerge = new(new string[] { "--binary-merge" }, description: ResString.cmd_binaryMerge, getDefaultValue: () => false);
|
||||||
|
@ -39,15 +42,85 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
||||||
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath);
|
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath);
|
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
||||||
private readonly static Option<bool> ConcurrentDownload = new(new string[] { "--concurrent-download" }, description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
|
private readonly static Option<bool> ConcurrentDownload = new(new string[] { "-mt", "--concurrent-download" }, description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
|
||||||
|
|
||||||
//复杂命令行如下
|
//复杂命令行如下
|
||||||
private readonly static Option<MuxOptions?> MuxAfterDone = new(new string[] { "-M", "--mux-after-done" }, description: ResString.cmd_muxAfterDone, parseArgument: ParseMuxAfterDone) { ArgumentHelpName = "OPTIONS" };
|
private readonly static Option<MuxOptions?> MuxAfterDone = new(new string[] { "-M", "--mux-after-done" }, description: ResString.cmd_muxAfterDone, parseArgument: ParseMuxAfterDone) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<List<OutputFile>> MuxImports = new("--mux-import", description: ResString.cmd_muxImport, parseArgument: ParseImports) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "OPTIONS" };
|
private readonly static Option<List<OutputFile>> MuxImports = new("--mux-import", description: ResString.cmd_muxImport, parseArgument: ParseImports) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "OPTIONS" };
|
||||||
|
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" };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 流过滤器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static StreamFilter? ParseStreamFilter(ArgumentResult result)
|
||||||
|
{
|
||||||
|
var streamFilter = new StreamFilter();
|
||||||
|
var input = result.Tokens.First().Value;
|
||||||
|
var p = new ComplexParamParser(input);
|
||||||
|
|
||||||
|
|
||||||
|
//目标范围
|
||||||
|
var forStr = "";
|
||||||
|
if (input == ForStrRegex().Match(input).Value)
|
||||||
|
{
|
||||||
|
forStr = input;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forStr = p.GetValue("for") ?? "best";
|
||||||
|
if (forStr != ForStrRegex().Match(input).Value)
|
||||||
|
{
|
||||||
|
result.ErrorMessage = $"for={forStr} not valid";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streamFilter.For = forStr;
|
||||||
|
|
||||||
|
var id = p.GetValue("id");
|
||||||
|
if (!string.IsNullOrEmpty(id))
|
||||||
|
streamFilter.GroupIdReg = new Regex(id);
|
||||||
|
|
||||||
|
var lang = p.GetValue("lang");
|
||||||
|
if (!string.IsNullOrEmpty(lang))
|
||||||
|
streamFilter.LanguageReg = new Regex(lang);
|
||||||
|
|
||||||
|
var name = p.GetValue("name");
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
streamFilter.NameReg = new Regex(name);
|
||||||
|
|
||||||
|
var codecs = p.GetValue("codecs");
|
||||||
|
if (!string.IsNullOrEmpty(codecs))
|
||||||
|
streamFilter.CodecsReg = new Regex(codecs);
|
||||||
|
|
||||||
|
var res = p.GetValue("res");
|
||||||
|
if (!string.IsNullOrEmpty(res))
|
||||||
|
streamFilter.ResolutionReg = new Regex(res);
|
||||||
|
|
||||||
|
var frame = p.GetValue("frame");
|
||||||
|
if (!string.IsNullOrEmpty(frame))
|
||||||
|
streamFilter.FrameRateReg = new Regex(frame);
|
||||||
|
|
||||||
|
var channel = p.GetValue("channel");
|
||||||
|
if (!string.IsNullOrEmpty(channel))
|
||||||
|
streamFilter.ChannelsReg = new Regex(channel);
|
||||||
|
|
||||||
|
var range = p.GetValue("range");
|
||||||
|
if (!string.IsNullOrEmpty(range))
|
||||||
|
streamFilter.VideoRangeReg = new Regex(range);
|
||||||
|
|
||||||
|
var url = p.GetValue("url");
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
streamFilter.UrlReg = new Regex(url);
|
||||||
|
|
||||||
|
return streamFilter;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分割Header
|
/// 分割Header
|
||||||
|
@ -180,6 +253,9 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
BaseUrl = bindingContext.ParseResult.GetValueForOption(BaseUrl),
|
BaseUrl = bindingContext.ParseResult.GetValueForOption(BaseUrl),
|
||||||
MuxImports = bindingContext.ParseResult.GetValueForOption(MuxImports),
|
MuxImports = bindingContext.ParseResult.GetValueForOption(MuxImports),
|
||||||
ConcurrentDownload = bindingContext.ParseResult.GetValueForOption(ConcurrentDownload),
|
ConcurrentDownload = bindingContext.ParseResult.GetValueForOption(ConcurrentDownload),
|
||||||
|
VideoFilter = bindingContext.ParseResult.GetValueForOption(VideoFilter),
|
||||||
|
AudioFilter = bindingContext.ParseResult.GetValueForOption(AudioFilter),
|
||||||
|
SubtitleFilter = bindingContext.ParseResult.GetValueForOption(SubtitleFilter),
|
||||||
};
|
};
|
||||||
|
|
||||||
var parsedHeaders = bindingContext.ParseResult.GetValueForOption(Headers);
|
var parsedHeaders = bindingContext.ParseResult.GetValueForOption(Headers);
|
||||||
|
@ -215,13 +291,13 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
|
|
||||||
public static async Task<int> InvokeArgs(string[] args, Func<MyOption, Task> action)
|
public static async Task<int> InvokeArgs(string[] args, Func<MyOption, Task> action)
|
||||||
{
|
{
|
||||||
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220826")
|
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220827")
|
||||||
{
|
{
|
||||||
Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
||||||
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
||||||
FFmpegBinaryPath,
|
FFmpegBinaryPath,
|
||||||
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
||||||
MuxAfterDone, MuxImports
|
MuxAfterDone, MuxImports, VideoFilter, AudioFilter, SubtitleFilter
|
||||||
};
|
};
|
||||||
rootCommand.TreatUnmatchedTokensAsErrors = true;
|
rootCommand.TreatUnmatchedTokensAsErrors = true;
|
||||||
rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder());
|
rootCommand.SetHandler(async (myOption) => await action(myOption), new MyOptionBinder());
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var index = _arg.IndexOf(key + "=");
|
var index = _arg.IndexOf(key + "=");
|
||||||
if (index == -1) return _arg.IndexOf(key) != -1 ? "true" : null;
|
if (index == -1) return (_arg.Contains(key) && _arg.EndsWith(key)) ? "true" : null;
|
||||||
|
|
||||||
var chars = _arg[(index + key.Length + 1)..].ToCharArray();
|
var chars = _arg[(index + key.Length + 1)..].ToCharArray();
|
||||||
var result = new StringBuilder();
|
var result = new StringBuilder();
|
||||||
|
|
|
@ -146,6 +146,18 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
/// See: <see cref="CommandInvoker.MuxImports"/>.
|
/// See: <see cref="CommandInvoker.MuxImports"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<OutputFile>? MuxImports { get; set; }
|
public List<OutputFile>? MuxImports { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.VideoFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StreamFilter? VideoFilter { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.AudioFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StreamFilter? AudioFilter { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.SubtitleFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StreamFilter? SubtitleFilter { get; set; }
|
||||||
public bool MuxKeepFiles { get; set; }
|
public bool MuxKeepFiles { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace N_m3u8DL_RE.Entity
|
||||||
|
{
|
||||||
|
public class StreamFilter
|
||||||
|
{
|
||||||
|
public Regex? GroupIdReg { get; set; }
|
||||||
|
public Regex? LanguageReg { get; set; }
|
||||||
|
public Regex? NameReg { get; set; }
|
||||||
|
public Regex? CodecsReg { get; set; }
|
||||||
|
public Regex? ResolutionReg { get; set; }
|
||||||
|
public Regex? FrameRateReg { get; set; }
|
||||||
|
public Regex? ChannelsReg { get; set; }
|
||||||
|
public Regex? VideoRangeReg { get; set; }
|
||||||
|
public Regex? UrlReg { get; set; }
|
||||||
|
|
||||||
|
public string For { get; set; } = "best";
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,16 @@ namespace N_m3u8DL_RE
|
||||||
await CommandInvoker.InvokeArgs(args, DoWorkAsync);
|
await CommandInvoker.InvokeArgs(args, DoWorkAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetOrder(StreamSpec streamSpec)
|
||||||
|
{
|
||||||
|
if (streamSpec.Channels == null) return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var str = streamSpec.Channels.Split('/')[0];
|
||||||
|
return int.TryParse(str, out var order) ? order : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async Task DoWorkAsync(MyOption option)
|
static async Task DoWorkAsync(MyOption option)
|
||||||
{
|
{
|
||||||
Logger.LogLevel = option.LogLevel;
|
Logger.LogLevel = option.LogLevel;
|
||||||
|
@ -182,7 +192,7 @@ namespace N_m3u8DL_RE
|
||||||
}
|
}
|
||||||
|
|
||||||
//全部媒体
|
//全部媒体
|
||||||
var lists = streams.OrderBy(p => p.MediaType).ThenByDescending(p => p.Bandwidth);
|
var lists = streams.OrderBy(p => p.MediaType).ThenByDescending(p => p.Bandwidth).ThenByDescending(GetOrder);
|
||||||
//基本流
|
//基本流
|
||||||
var basicStreams = lists.Where(x => x.MediaType == null || x.MediaType == MediaType.VIDEO);
|
var basicStreams = lists.Where(x => x.MediaType == null || x.MediaType == MediaType.VIDEO);
|
||||||
//可选音频轨道
|
//可选音频轨道
|
||||||
|
@ -203,8 +213,6 @@ namespace N_m3u8DL_RE
|
||||||
Logger.InfoMarkUp(item.ToString());
|
Logger.InfoMarkUp(item.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//展示交互式选择框
|
|
||||||
//var selectedStreams = PromptUtil.SelectStreams(lists);
|
|
||||||
var selectedStreams = new List<StreamSpec>();
|
var selectedStreams = new List<StreamSpec>();
|
||||||
if (option.AutoSelect)
|
if (option.AutoSelect)
|
||||||
{
|
{
|
||||||
|
@ -213,7 +221,7 @@ namespace N_m3u8DL_RE
|
||||||
var langs = audios.DistinctBy(a => a.Language).Select(a => a.Language);
|
var langs = audios.DistinctBy(a => a.Language).Select(a => a.Language);
|
||||||
foreach (var lang in langs)
|
foreach (var lang in langs)
|
||||||
{
|
{
|
||||||
selectedStreams.Add(audios.Where(a => a.Language == lang).OrderByDescending(a => a.Bandwidth).First());
|
selectedStreams.Add(audios.Where(a => a.Language == lang).OrderByDescending(a => a.Bandwidth).ThenByDescending(GetOrder).First());
|
||||||
}
|
}
|
||||||
selectedStreams.AddRange(subs);
|
selectedStreams.AddRange(subs);
|
||||||
}
|
}
|
||||||
|
@ -221,10 +229,22 @@ namespace N_m3u8DL_RE
|
||||||
{
|
{
|
||||||
selectedStreams.AddRange(subs);
|
selectedStreams.AddRange(subs);
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
selectedStreams = basicStreams.Concat(audios).Concat(subs).ToList();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selectedStreams = PromptUtil.SelectStreams(lists);
|
//展示交互式选择框
|
||||||
|
selectedStreams = FilterUtil.SelectStreams(lists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!selectedStreams.Any())
|
||||||
|
throw new Exception(ResString.noStreamsToDownload);
|
||||||
|
|
||||||
//一个以上的话,需要手动重新加载playlist
|
//一个以上的话,需要手动重新加载playlist
|
||||||
if (lists.Count() > 1)
|
if (lists.Count() > 1)
|
||||||
await extractor.FetchPlayListAsync(selectedStreams);
|
await extractor.FetchPlayListAsync(selectedStreams);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
|
using N_m3u8DL_RE.Entity;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -10,8 +11,47 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util
|
namespace N_m3u8DL_RE.Util
|
||||||
{
|
{
|
||||||
public class PromptUtil
|
public class FilterUtil
|
||||||
{
|
{
|
||||||
|
public static List<StreamSpec> DoFilter(IEnumerable<StreamSpec> lists, StreamFilter? filter)
|
||||||
|
{
|
||||||
|
if (filter == null) return new List<StreamSpec>();
|
||||||
|
|
||||||
|
var inputs = lists.Where(_ => true);
|
||||||
|
if (filter.GroupIdReg != null)
|
||||||
|
inputs = inputs.Where(i => i.GroupId != null && filter.GroupIdReg.IsMatch(i.GroupId));
|
||||||
|
if (filter.LanguageReg != null)
|
||||||
|
inputs = inputs.Where(i => i.Language != null && filter.LanguageReg.IsMatch(i.Language));
|
||||||
|
if (filter.NameReg != null)
|
||||||
|
inputs = inputs.Where(i => i.Name != null && filter.NameReg.IsMatch(i.Name));
|
||||||
|
if (filter.CodecsReg != null)
|
||||||
|
inputs = inputs.Where(i => i.Codecs != null && filter.CodecsReg.IsMatch(i.Codecs));
|
||||||
|
if (filter.ResolutionReg != null)
|
||||||
|
inputs = inputs.Where(i => i.Resolution != null && filter.ResolutionReg.IsMatch(i.Resolution));
|
||||||
|
if (filter.FrameRateReg != null)
|
||||||
|
inputs = inputs.Where(i => i.FrameRate != null && filter.FrameRateReg.IsMatch($"{i.FrameRate}"));
|
||||||
|
if (filter.ChannelsReg != null)
|
||||||
|
inputs = inputs.Where(i => i.Channels != null && filter.ChannelsReg.IsMatch(i.Channels));
|
||||||
|
if (filter.VideoRangeReg != null)
|
||||||
|
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));
|
||||||
|
|
||||||
|
var bestNumberStr = filter.For.Replace("best", "");
|
||||||
|
var worstNumberStr = filter.For.Replace("worst", "");
|
||||||
|
|
||||||
|
if (filter.For == "best" && inputs.Count() > 0)
|
||||||
|
inputs = inputs.Take(1).ToList();
|
||||||
|
else if (filter.For == "worst" && inputs.Count() > 0)
|
||||||
|
inputs = inputs.TakeLast(1).ToList();
|
||||||
|
else if (int.TryParse(bestNumberStr, out int bestNumber) && inputs.Count() > 0)
|
||||||
|
inputs = inputs.Take(bestNumber).ToList();
|
||||||
|
else if (int.TryParse(worstNumberStr, out int worstNumber) && inputs.Count() > 0)
|
||||||
|
inputs = inputs.TakeLast(worstNumber).ToList();
|
||||||
|
|
||||||
|
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)
|
Loading…
Reference in New Issue