static void Main(string[] args) { SetConsoleCtrlHandler(cancelHandler, true); ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; string loc = "zh-CN"; string currLoc = Thread.CurrentThread.CurrentUICulture.Name; if (currLoc == "zh-TW" || currLoc == "zh-HK" || currLoc == "zh-MO") { loc = "zh-TW"; } else if (loc == "zh-CN" || loc == "zh-SG") { loc = "zh-CN"; } else { loc = "en-US"; } //设置语言 CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(loc); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(loc); try { //goto httplitsen; //当前程序路径(末尾有\) string CURRENT_PATH = Directory.GetCurrentDirectory(); string fileName = ""; //寻找ffmpeg.exe if (!File.Exists("ffmpeg.exe") && !File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "ffmpeg.exe"))) { try { string[] EnvironmentPath = Environment.GetEnvironmentVariable("Path").Split(';'); foreach (var de in EnvironmentPath) { if (File.Exists(Path.Combine(de.Trim('\"').Trim(), "ffmpeg.exe"))) { goto HasFFmpeg; } } } catch (Exception) { ; } Console.BackgroundColor = ConsoleColor.Red; //设置背景色 Console.ForegroundColor = ConsoleColor.White; //设置前景色,即字体颜色 Console.WriteLine(strings.ffmpegLost); Console.ResetColor(); //将控制台的前景色和背景色设为默认值 Console.WriteLine(strings.ffmpegTip); Console.WriteLine(); Console.WriteLine("x86 https://ffmpeg.zeranoe.com/builds/win32/static/"); Console.WriteLine("x64 https://ffmpeg.zeranoe.com/builds/win64/static/"); Console.WriteLine(); Console.WriteLine(strings.pressAnyKeyExit); Console.ReadKey(); Environment.Exit(-1); } HasFFmpeg: Global.WriteInit(); if (!File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "NO_UPDATE"))) { Thread checkUpdate = new Thread(() => { Global.CheckUpdate(); }); checkUpdate.IsBackground = true; checkUpdate.Start(); } int maxThreads = Environment.ProcessorCount; int minThreads = 16; int retryCount = 15; int timeOut = 10; //默认10秒 string baseUrl = ""; string reqHeaders = ""; string keyFile = ""; string keyBase64 = ""; string keyIV = ""; string muxSetJson = "MUXSETS.json"; string workDir = CURRENT_PATH + "\\Downloads"; bool muxFastStart = false; bool delAfterDone = false; bool parseOnly = false; bool noMerge = false; /******************************************************/ ServicePointManager.DefaultConnectionLimit = 1024; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | (SecurityProtocolType)0x300 //Tls11 | (SecurityProtocolType)0xC00; //Tls12 /******************************************************/ if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt"))) { reqHeaders = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt")); } //分析命令行参数 parseArgs: var arguments = CommandLineArgumentParser.Parse(args); if (args.Length == 1 && args[0] == "--help") { Console.WriteLine(strings.helpInfo); return; } if (arguments.Has("--enableDelAfterDone")) { delAfterDone = true; } if (arguments.Has("--enableParseOnly")) { parseOnly = true; } if (arguments.Has("--enableBinaryMerge")) { DownloadManager.BinaryMerge = true; } if (arguments.Has("--disableDateInfo")) { FFmpeg.WriteDate = false; } if (arguments.Has("--noMerge")) { noMerge = true; } if (arguments.Has("--noProxy")) { Global.NoProxy = true; } if (arguments.Has("--headers")) { reqHeaders = arguments.Get("--headers").Next; } if (arguments.Has("--enableMuxFastStart")) { muxFastStart = true; } if (arguments.Has("--disableIntegrityCheck")) { DownloadManager.DisableIntegrityCheck = true; } if (arguments.Has("--enableAudioOnly")) { Global.VIDEO_TYPE = "IGNORE"; } if (arguments.Has("--muxSetJson")) { muxSetJson = arguments.Get("--muxSetJson").Next; } if (arguments.Has("--workDir")) { workDir = arguments.Get("--workDir").Next; DownloadManager.HasSetDir = true; } if (arguments.Has("--saveName")) { fileName = Global.GetValidFileName(arguments.Get("--saveName").Next); } if (arguments.Has("--useKeyFile")) { if (File.Exists(arguments.Get("--useKeyFile").Next)) { keyFile = arguments.Get("--useKeyFile").Next; } } if (arguments.Has("--useKeyBase64")) { keyBase64 = arguments.Get("--useKeyBase64").Next; } if (arguments.Has("--useKeyIV")) { keyIV = arguments.Get("--useKeyIV").Next; } if (arguments.Has("--stopSpeed")) { Global.STOP_SPEED = Convert.ToInt64(arguments.Get("--stopSpeed").Next); } if (arguments.Has("--maxSpeed")) { Global.MAX_SPEED = Convert.ToInt64(arguments.Get("--maxSpeed").Next); } if (arguments.Has("--baseUrl")) { baseUrl = arguments.Get("--baseUrl").Next; } if (arguments.Has("--maxThreads")) { maxThreads = Convert.ToInt32(arguments.Get("--maxThreads").Next); } if (arguments.Has("--minThreads")) { minThreads = Convert.ToInt32(arguments.Get("--minThreads").Next); } if (arguments.Has("--retryCount")) { retryCount = Convert.ToInt32(arguments.Get("--retryCount").Next); } if (arguments.Has("--timeOut")) { timeOut = Convert.ToInt32(arguments.Get("--timeOut").Next); } if (arguments.Has("--liveRecDur")) { //时间码 Regex reg2 = new Regex(@"(\d+):(\d+):(\d+)"); var t = arguments.Get("--liveRecDur").Next; if (reg2.IsMatch(t)) { int HH = Convert.ToInt32(reg2.Match(t).Groups[1].Value); int MM = Convert.ToInt32(reg2.Match(t).Groups[2].Value); int SS = Convert.ToInt32(reg2.Match(t).Groups[3].Value); HLSLiveDownloader.REC_DUR_LIMIT = SS + MM * 60 + HH * 60 * 60; } } if (arguments.Has("--downloadRange")) { string p = arguments.Get("--downloadRange").Next; if (p.Contains(":")) { //时间码 Regex reg2 = new Regex(@"((\d+):(\d+):(\d+))?-((\d+):(\d+):(\d+))?"); if (reg2.IsMatch(p)) { Parser.DurStart = reg2.Match(p).Groups[1].Value; Parser.DurEnd = reg2.Match(p).Groups[5].Value; Parser.DelAd = false; } } else { //数字 Regex reg = new Regex(@"(\d*)-(\d*)"); if (reg.IsMatch(p)) { if (!string.IsNullOrEmpty(reg.Match(p).Groups[1].Value)) { Parser.RangeStart = Convert.ToInt32(reg.Match(p).Groups[1].Value); Parser.DelAd = false; } if (!string.IsNullOrEmpty(reg.Match(p).Groups[2].Value)) { Parser.RangeEnd = Convert.ToInt32(reg.Match(p).Groups[2].Value); Parser.DelAd = false; } } } } //如果只有URL,没有附加参数,则尝试解析配置文件 if (args.Length == 1 || (args.Length == 3 && args[1].ToLower() == "--savename")) { if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))) { if (args.Length == 3) { args = Global.ParseArguments($"\"{args[0]}\" {args[1]} {args[2]} " + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))).ToArray(); //解析命令行 } else { args = Global.ParseArguments($"\"{args[0]}\" " + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))).ToArray(); //解析命令行 } goto parseArgs; } } //ReadLine字数上限 Stream steam = Console.OpenStandardInput(); Console.SetIn(new StreamReader(steam, Encoding.Default, false, 5000)); int inputRetryCount = 20; input: string testurl = ""; //重试太多次,退出 if (inputRetryCount == 0) { Environment.Exit(-1); } if (args.Length > 0) { testurl = args[0]; } else { Console.CursorVisible = true; Console.ForegroundColor = ConsoleColor.Cyan; Console.Write("N_m3u8DL-CLI"); Console.ResetColor(); Console.Write(" > "); args = Global.ParseArguments(Console.ReadLine()).ToArray(); //解析命令行 Global.WriteInit(); Console.CursorVisible = false; goto parseArgs; } if (fileName == "") { fileName = Global.GetUrlFileName(testurl) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"); } if (testurl.Contains("twitcasting") && testurl.Contains("/fmp4/")) { DownloadManager.BinaryMerge = true; } //优酷DRM设备更改 /*if (testurl.Contains("playlist/m3u8")) * { * string drm_type = Global.GetQueryString("drm_type", testurl); * string drm_device = Global.GetQueryString("drm_device", testurl); * if (drm_type != "1") * { * testurl = testurl.Replace("drm_type=" + drm_type, "drm_type=1"); * } * if (drm_device != "11") * { * testurl = testurl.Replace("drm_device=" + drm_device, "drm_device=11"); * } * }*/ string m3u8Content = string.Empty; bool isVOD = true; //开始解析 Console.CursorVisible = false; LOGGER.PrintLine($"{strings.fileName}{fileName}"); LOGGER.PrintLine($"{strings.savePath}{Path.GetDirectoryName(Path.Combine(workDir, fileName))}"); Parser parser = new Parser(); parser.DownName = fileName; parser.DownDir = Path.Combine(workDir, parser.DownName); parser.M3u8Url = testurl; parser.KeyBase64 = keyBase64; parser.KeyIV = keyIV; parser.KeyFile = keyFile; if (baseUrl != "") { parser.BaseUrl = baseUrl; } parser.Headers = reqHeaders; string exePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); LOGGER.LOGFILE = Path.Combine(exePath, "Logs", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log"); LOGGER.InitLog(); LOGGER.WriteLine(strings.startParsing + testurl); LOGGER.PrintLine(strings.startParsing, LOGGER.Warning); if (testurl.EndsWith(".json") && File.Exists(testurl)) //可直接跳过解析 { if (!Directory.Exists(Path.Combine(workDir, fileName))) //若文件夹不存在则新建文件夹 { Directory.CreateDirectory(Path.Combine(workDir, fileName)); //新建文件夹 } File.Copy(testurl, Path.Combine(Path.Combine(workDir, fileName), "meta.json"), true); } else { parser.Parse(); //开始解析 } //仅解析模式 if (parseOnly) { LOGGER.PrintLine(strings.parseExit); Environment.Exit(0); } if (File.Exists(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))) { JObject initJson = JObject.Parse(File.ReadAllText(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))); isVOD = Convert.ToBoolean(initJson["m3u8Info"]["vod"].ToString()); //传给Watcher总时长 Watcher.TotalDuration = initJson["m3u8Info"]["totalDuration"].Value <double>(); LOGGER.PrintLine($"{strings.fileDuration}{Global.FormatTime((int)Watcher.TotalDuration)}"); LOGGER.PrintLine(strings.segCount + initJson["m3u8Info"]["originalCount"].Value <int>() + $", {strings.selectedCount}" + initJson["m3u8Info"]["count"].Value <int>()); } else { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(workDir, fileName)); directoryInfo.Delete(true); LOGGER.PrintLine(strings.InvalidUri, LOGGER.Error); LOGGER.CursorIndex = 5; inputRetryCount--; goto input; } //点播 if (isVOD == true) { ServicePointManager.DefaultConnectionLimit = 10000; DownloadManager md = new DownloadManager(); md.DownDir = parser.DownDir; md.Headers = reqHeaders; md.Threads = Environment.ProcessorCount; if (md.Threads > maxThreads) { md.Threads = maxThreads; } if (md.Threads < minThreads) { md.Threads = minThreads; } if (File.Exists("minT.txt")) { int t = Convert.ToInt32(File.ReadAllText("minT.txt")); if (md.Threads <= t) { md.Threads = t; } } md.TimeOut = timeOut * 1000; md.NoMerge = noMerge; md.DownName = fileName; md.DelAfterDone = delAfterDone; md.MuxFormat = "mp4"; md.RetryCount = retryCount; md.MuxSetJson = muxSetJson; md.MuxFastStart = muxFastStart; md.DoDownload(); } //直播 if (isVOD == false) { LOGGER.WriteLine(strings.liveStreamFoundAndRecoding); LOGGER.PrintLine(strings.liveStreamFoundAndRecoding); //LOGGER.STOPLOG = true; //停止记录日志 //开辟文件流,且不关闭。(便于播放器不断读取文件) string LivePath = Path.Combine(Directory.GetParent(parser.DownDir).FullName , DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + "_" + fileName + ".ts"); FileStream outputStream = new FileStream(LivePath, FileMode.Append); HLSLiveDownloader live = new HLSLiveDownloader(); live.DownDir = parser.DownDir; live.Headers = reqHeaders; live.LiveStream = outputStream; live.LiveFile = LivePath; live.TimerStart(); //开始录制 Console.ReadKey(); } //监听测试 /*httplitsen: * HTTPListener.StartListening();*/ LOGGER.WriteLineError(strings.downloadFailed); LOGGER.PrintLine(strings.downloadFailed, LOGGER.Error); Console.CursorVisible = true; Thread.Sleep(3000); Environment.Exit(-1); //Console.Write("按任意键继续..."); Console.ReadKey(); return; } catch (Exception ex) { Console.CursorVisible = true; LOGGER.PrintLine(ex.Message, LOGGER.Error); } }
private static void DoWork(MyOptions o) { try { Global.WriteInit(); //当前程序路径(末尾有\) string CURRENT_PATH = Directory.GetCurrentDirectory(); string fileName = Global.GetValidFileName(o.SaveName); string reqHeaders = o.Headers; string muxSetJson = o.MuxSetJson ?? "MUXSETS.json"; string workDir = CURRENT_PATH + "\\Downloads"; string keyFile = ""; string keyBase64 = ""; string keyIV = ""; string baseUrl = ""; Global.STOP_SPEED = o.StopSpeed; Global.MAX_SPEED = o.MaxSpeed; if (!string.IsNullOrEmpty(o.UseKeyBase64)) { keyBase64 = o.UseKeyBase64; } if (!string.IsNullOrEmpty(o.UseKeyIV)) { keyIV = o.UseKeyIV; } if (!string.IsNullOrEmpty(o.BaseUrl)) { baseUrl = o.BaseUrl; } if (o.EnableBinaryMerge) { DownloadManager.BinaryMerge = true; } if (o.DisableDateInfo) { FFmpeg.WriteDate = false; } if (o.NoProxy) { Global.NoProxy = true; } if (o.DisableIntegrityCheck) { DownloadManager.DisableIntegrityCheck = true; } if (o.EnableAudioOnly) { Global.VIDEO_TYPE = "IGNORE"; } if (!string.IsNullOrEmpty(o.WorkDir)) { workDir = Environment.ExpandEnvironmentVariables(o.WorkDir); DownloadManager.HasSetDir = true; } //Proxy if (!string.IsNullOrEmpty(o.ProxyAddress)) { var proxy = o.ProxyAddress; if (proxy.StartsWith("http://")) { Global.UseProxyAddress = proxy; } if (proxy.StartsWith("socks5://")) { Global.UseProxyAddress = proxy; } } //Key if (!string.IsNullOrEmpty(o.UseKeyFile)) { if (File.Exists(o.UseKeyFile)) { keyFile = o.UseKeyFile; } } if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt"))) { reqHeaders = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt")); } if (!string.IsNullOrEmpty(o.LiveRecDur)) { //时间码 Regex reg2 = new Regex(@"(\d+):(\d+):(\d+)"); var t = o.LiveRecDur; if (reg2.IsMatch(t)) { int HH = Convert.ToInt32(reg2.Match(t).Groups[1].Value); int MM = Convert.ToInt32(reg2.Match(t).Groups[2].Value); int SS = Convert.ToInt32(reg2.Match(t).Groups[3].Value); HLSLiveDownloader.REC_DUR_LIMIT = SS + MM * 60 + HH * 60 * 60; } } if (!string.IsNullOrEmpty(o.DownloadRange)) { string p = o.DownloadRange; if (p.Contains(":")) { //时间码 Regex reg2 = new Regex(@"((\d+):(\d+):(\d+))?-((\d+):(\d+):(\d+))?"); if (reg2.IsMatch(p)) { Parser.DurStart = reg2.Match(p).Groups[1].Value; Parser.DurEnd = reg2.Match(p).Groups[5].Value; if (Parser.DurEnd == "00:00:00") { Parser.DurEnd = ""; } Parser.DelAd = false; } } else { //数字 Regex reg = new Regex(@"(\d*)-(\d*)"); if (reg.IsMatch(p)) { if (!string.IsNullOrEmpty(reg.Match(p).Groups[1].Value)) { Parser.RangeStart = Convert.ToInt32(reg.Match(p).Groups[1].Value); Parser.DelAd = false; } if (!string.IsNullOrEmpty(reg.Match(p).Groups[2].Value)) { Parser.RangeEnd = Convert.ToInt32(reg.Match(p).Groups[2].Value); Parser.DelAd = false; } } } } int inputRetryCount = 20; input: string testurl = o.Input; //重试太多次,退出 if (inputRetryCount == 0) { Environment.Exit(-1); } if (fileName == "") { fileName = Global.GetUrlFileName(testurl) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"); } if (testurl.Contains("twitcasting") && testurl.Contains("/fmp4/")) { DownloadManager.BinaryMerge = true; } string m3u8Content = string.Empty; bool isVOD = true; //避免文件路径过长 if (workDir.Length >= 200) { //目录不能随便改 直接抛出异常 throw new Exception("保存目录过长!"); } else if (workDir.Length + fileName.Length >= 200) { //尝试缩短文件名 while (workDir.Length + fileName.Length >= 200) { fileName = fileName.Substring(0, fileName.Length - 1); } } //开始解析 LOGGER.PrintLine($"{strings.fileName}{fileName}"); LOGGER.PrintLine($"{strings.savePath}{Path.GetDirectoryName(Path.Combine(workDir, fileName))}"); Parser parser = new Parser(); parser.DownName = fileName; parser.DownDir = Path.Combine(workDir, parser.DownName); parser.M3u8Url = testurl; parser.KeyBase64 = keyBase64; parser.KeyIV = keyIV; parser.KeyFile = keyFile; if (baseUrl != "") { parser.BaseUrl = baseUrl; } parser.Headers = reqHeaders; string exePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); LOGGER.LOGFILE = Path.Combine(exePath, "Logs", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff") + ".log"); LOGGER.InitLog(); LOGGER.WriteLine(strings.startParsing + testurl); LOGGER.PrintLine(strings.startParsing + " " + testurl, LOGGER.Warning); if (testurl.EndsWith(".json") && File.Exists(testurl)) //可直接跳过解析 { if (!Directory.Exists(Path.Combine(workDir, fileName))) //若文件夹不存在则新建文件夹 { Directory.CreateDirectory(Path.Combine(workDir, fileName)); //新建文件夹 } File.Copy(testurl, Path.Combine(Path.Combine(workDir, fileName), "meta.json"), true); } else { parser.Parse(); //开始解析 } //仅解析模式 if (o.EnableParseOnly) { LOGGER.PrintLine(strings.parseExit); Environment.Exit(0); } if (File.Exists(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))) { JObject initJson = JObject.Parse(File.ReadAllText(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))); isVOD = Convert.ToBoolean(initJson["m3u8Info"]["vod"].ToString()); //传给Watcher总时长 Watcher.TotalDuration = initJson["m3u8Info"]["totalDuration"].Value <double>(); LOGGER.PrintLine($"{strings.fileDuration}{Global.FormatTime((int)Watcher.TotalDuration)}"); LOGGER.PrintLine(strings.segCount + initJson["m3u8Info"]["originalCount"].Value <int>() + $", {strings.selectedCount}" + initJson["m3u8Info"]["count"].Value <int>()); } else { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(workDir, fileName)); directoryInfo.Delete(true); LOGGER.PrintLine(strings.InvalidUri, LOGGER.Error); inputRetryCount--; goto input; } //点播 if (isVOD == true) { ServicePointManager.DefaultConnectionLimit = 10000; DownloadManager md = new DownloadManager(); md.DownDir = parser.DownDir; md.Headers = reqHeaders; md.Threads = Environment.ProcessorCount; if (md.Threads > o.MaxThreads) { md.Threads = (int)o.MaxThreads; } if (md.Threads < o.MinThreads) { md.Threads = (int)o.MinThreads; } if (File.Exists("minT.txt")) { int t = Convert.ToInt32(File.ReadAllText("minT.txt")); if (md.Threads <= t) { md.Threads = t; } } md.TimeOut = (int)(o.TimeOut * 1000); md.NoMerge = o.NoMerge; md.DownName = fileName; md.DelAfterDone = o.EnableDelAfterDone; md.MuxFormat = "mp4"; md.RetryCount = (int)o.RetryCount; md.MuxSetJson = muxSetJson; md.MuxFastStart = o.EnableMuxFastStart; md.DoDownload(); } //直播 if (isVOD == false) { LOGGER.WriteLine(strings.liveStreamFoundAndRecoding); LOGGER.PrintLine(strings.liveStreamFoundAndRecoding); //LOGGER.STOPLOG = true; //停止记录日志 //开辟文件流,且不关闭。(便于播放器不断读取文件) string LivePath = Path.Combine(Directory.GetParent(parser.DownDir).FullName , DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + "_" + fileName + ".ts"); FileStream outputStream = new FileStream(LivePath, FileMode.Append); HLSLiveDownloader live = new HLSLiveDownloader(); live.DownDir = parser.DownDir; live.Headers = reqHeaders; live.LiveStream = outputStream; live.LiveFile = LivePath; live.TimerStart(); //开始录制 Console.ReadKey(); } LOGGER.WriteLineError(strings.downloadFailed); LOGGER.PrintLine(strings.downloadFailed, LOGGER.Error); Thread.Sleep(3000); Environment.Exit(-1); //Console.Write("按任意键继续..."); Console.ReadKey(); return; } catch (Exception ex) { LOGGER.PrintLine(ex.Message, LOGGER.Error); } }
static void Main(string[] args) { SetConsoleCtrlHandler(cancelHandler, true); ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; try { //goto httplitsen; //当前程序路径(末尾有\) string CURRENT_PATH = Directory.GetCurrentDirectory(); string fileName = ""; //寻找ffmpeg.exe if (!File.Exists("ffmpeg.exe")) { try { string[] EnvironmentPath = Environment.GetEnvironmentVariable("Path").Split(';'); foreach (var de in EnvironmentPath) { if (File.Exists(Path.Combine(de.Trim('\"').Trim(), "ffmpeg.exe"))) { goto HasFFmpeg; } } } catch (Exception) { ; } Console.BackgroundColor = ConsoleColor.Red; //设置背景色 Console.ForegroundColor = ConsoleColor.White; //设置前景色,即字体颜色 Console.WriteLine("在PATH和程序路径下找不到 ffmpeg.exe"); Console.ResetColor(); //将控制台的前景色和背景色设为默认值 Console.WriteLine("请下载ffmpeg.exe并把他放到程序同目录."); Console.WriteLine(); Console.WriteLine("x86 https://ffmpeg.zeranoe.com/builds/win32/static/"); Console.WriteLine("x64 https://ffmpeg.zeranoe.com/builds/win64/static/"); Console.WriteLine(); Console.WriteLine("按任意键退出."); Console.ReadKey(); Environment.Exit(-1); } HasFFmpeg: Global.WriteInit(); Thread checkUpdate = new Thread(() => { Global.CheckUpdate(); }); checkUpdate.IsBackground = true; checkUpdate.Start(); int maxThreads = Environment.ProcessorCount; int minThreads = 16; int retryCount = 15; int timeOut = 10; //默认10秒 string baseUrl = ""; string reqHeaders = ""; string keyFile = ""; string keyBase64 = ""; string muxSetJson = "MUXSETS.json"; string workDir = CURRENT_PATH + "\\Downloads"; bool muxFastStart = false; bool delAfterDone = false; bool parseOnly = false; bool noMerge = false; /******************************************************/ ServicePointManager.DefaultConnectionLimit = 1024; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | (SecurityProtocolType)0x300 //Tls11 | (SecurityProtocolType)0xC00; //Tls12 /******************************************************/ if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt"))) { reqHeaders = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "headers.txt")); } //分析命令行参数 parseArgs: var arguments = CommandLineArgumentParser.Parse(args); if (args.Length == 1 && args[0] == "--help") { Console.WriteLine(@"N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS] --workDir Directory 设定程序工作目录 --saveName Filename 设定存储文件名(不包括后缀) --baseUrl BaseUrl 设定Baseurl --headers headers 设定请求头,格式 key:value 使用|分割不同的key&value --maxThreads Thread 设定程序的最大线程数(默认为32) --minThreads Thread 设定程序的最小线程数(默认为16) --retryCount Count 设定程序的重试次数(默认为15) --timeOut Sec 设定程序网络请求的超时时间(单位为秒,默认为10秒) --muxSetJson File 使用外部json文件定义混流选项 --useKeyFile File 使用外部16字节文件定义AES-128解密KEY --useKeyBase64 Base64String 使用Base64字符串定义AES-128解密KEY --downloadRange Range 仅下载视频的一部分分片或长度 --liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件 --stopSpeed Number 当速度低于此值时,重试(单位为KB/s) --maxSpeed Number 设置下载速度上限(单位为KB/s) --enableYouKuAes 使用优酷AES-128解密方案 --enableDelAfterDone 开启下载后删除临时文件夹的功能 --enableMuxFastStart 开启混流mp4的FastStart特性 --enableBinaryMerge 开启二进制合并分片 --enableParseOnly 开启仅解析模式(程序只进行到meta.json) --enableAudioOnly 合并时仅封装音频轨道 --disableDateInfo 关闭混流中的日期写入 --noMerge 禁用自动合并 --noProxy 不自动使用系统代理 --disableIntegrityCheck 不检测分片数量是否完整"); return; } if (arguments.Has("--enableDelAfterDone")) { delAfterDone = true; } if (arguments.Has("--enableParseOnly")) { parseOnly = true; } if (arguments.Has("--enableBinaryMerge")) { DownloadManager.BinaryMerge = true; } if (arguments.Has("--disableDateInfo")) { FFmpeg.WriteDate = false; } if (arguments.Has("--noMerge")) { noMerge = true; } if (arguments.Has("--noProxy")) { Global.NoProxy = true; } if (arguments.Has("--headers")) { reqHeaders = arguments.Get("--headers").Next; } if (arguments.Has("--enableMuxFastStart")) { muxFastStart = true; } if (arguments.Has("--enableYouKuAes")) { Downloader.YouKuAES = true; } if (arguments.Has("--disableIntegrityCheck")) { DownloadManager.DisableIntegrityCheck = true; } if (arguments.Has("--enableAudioOnly")) { Global.VIDEO_TYPE = "IGNORE"; } if (arguments.Has("--muxSetJson")) { muxSetJson = arguments.Get("--muxSetJson").Next; } if (arguments.Has("--workDir")) { workDir = arguments.Get("--workDir").Next; DownloadManager.HasSetDir = true; } if (arguments.Has("--saveName")) { fileName = Global.GetValidFileName(arguments.Get("--saveName").Next); } if (arguments.Has("--useKeyFile")) { if (File.Exists(arguments.Get("--useKeyFile").Next)) { keyFile = arguments.Get("--useKeyFile").Next; } } if (arguments.Has("--useKeyBase64")) { keyBase64 = arguments.Get("--useKeyBase64").Next; } if (arguments.Has("--stopSpeed")) { Global.STOP_SPEED = Convert.ToInt64(arguments.Get("--stopSpeed").Next); } if (arguments.Has("--maxSpeed")) { Global.MAX_SPEED = Convert.ToInt64(arguments.Get("--maxSpeed").Next); } if (arguments.Has("--baseUrl")) { baseUrl = arguments.Get("--baseUrl").Next; } if (arguments.Has("--maxThreads")) { maxThreads = Convert.ToInt32(arguments.Get("--maxThreads").Next); } if (arguments.Has("--minThreads")) { minThreads = Convert.ToInt32(arguments.Get("--minThreads").Next); } if (arguments.Has("--retryCount")) { retryCount = Convert.ToInt32(arguments.Get("--retryCount").Next); } if (arguments.Has("--timeOut")) { timeOut = Convert.ToInt32(arguments.Get("--timeOut").Next); } if (arguments.Has("--liveRecDur")) { //时间码 Regex reg2 = new Regex(@"(\d+):(\d+):(\d+)"); var t = arguments.Get("--liveRecDur").Next; if (reg2.IsMatch(t)) { int HH = Convert.ToInt32(reg2.Match(t).Groups[1].Value); int MM = Convert.ToInt32(reg2.Match(t).Groups[2].Value); int SS = Convert.ToInt32(reg2.Match(t).Groups[3].Value); HLSLiveDownloader.REC_DUR_LIMIT = SS + MM * 60 + HH * 60 * 60; } } if (arguments.Has("--downloadRange")) { string p = arguments.Get("--downloadRange").Next; if (p.Contains(":")) { //时间码 Regex reg2 = new Regex(@"((\d+):(\d+):(\d+))?-((\d+):(\d+):(\d+))?"); if (reg2.IsMatch(p)) { Parser.DurStart = reg2.Match(p).Groups[1].Value; Parser.DurEnd = reg2.Match(p).Groups[5].Value; Parser.DelAd = false; } } else { //数字 Regex reg = new Regex(@"(\d*)-(\d*)"); if (reg.IsMatch(p)) { if (!string.IsNullOrEmpty(reg.Match(p).Groups[1].Value)) { Parser.RangeStart = Convert.ToInt32(reg.Match(p).Groups[1].Value); Parser.DelAd = false; } if (!string.IsNullOrEmpty(reg.Match(p).Groups[2].Value)) { Parser.RangeEnd = Convert.ToInt32(reg.Match(p).Groups[2].Value); Parser.DelAd = false; } } } } //如果只有URL,没有附加参数,则尝试解析配置文件 if (args.Length == 1) { if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))) { args = Global.ParseArguments($"\"{args[0]}\"" + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))).ToArray(); //解析命令行 goto parseArgs; } } //ReadLine字数上限 Stream steam = Console.OpenStandardInput(); Console.SetIn(new StreamReader(steam, Encoding.Default, false, 5000)); int inputRetryCount = 20; input: string testurl = ""; //重试太多次,退出 if (inputRetryCount == 0) { Environment.Exit(-1); } if (args.Length > 0) { testurl = args[0]; } else { Console.CursorVisible = true; Console.ForegroundColor = ConsoleColor.Cyan; Console.Write("N_m3u8DL-CLI"); Console.ResetColor(); Console.Write(" > "); args = Global.ParseArguments(Console.ReadLine()).ToArray(); //解析命令行 Global.WriteInit(); Console.CursorVisible = false; goto parseArgs; } if (fileName == "") { fileName = Global.GetUrlFileName(testurl) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"); } if (testurl.Contains("twitcasting") && testurl.Contains("/fmp4/")) { DownloadManager.BinaryMerge = true; } //优酷DRM设备更改 /*if (testurl.Contains("playlist/m3u8")) * { * string drm_type = Global.GetQueryString("drm_type", testurl); * string drm_device = Global.GetQueryString("drm_device", testurl); * if (drm_type != "1") * { * testurl = testurl.Replace("drm_type=" + drm_type, "drm_type=1"); * } * if (drm_device != "11") * { * testurl = testurl.Replace("drm_device=" + drm_device, "drm_device=11"); * } * }*/ string m3u8Content = string.Empty; bool isVOD = true; //开始解析 Console.CursorVisible = false; LOGGER.PrintLine($"文件名称:{fileName}"); LOGGER.PrintLine($"存储路径:{Path.GetDirectoryName(Path.Combine(workDir, fileName))}"); Parser parser = new Parser(); parser.DownName = fileName; parser.DownDir = Path.Combine(workDir, parser.DownName); parser.M3u8Url = testurl; parser.KeyBase64 = keyBase64; parser.KeyFile = keyFile; if (baseUrl != "") { parser.BaseUrl = baseUrl; } parser.Headers = reqHeaders; string exePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); LOGGER.LOGFILE = Path.Combine(exePath, "Logs", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log"); LOGGER.InitLog(); LOGGER.WriteLine("Start Parsing " + testurl); LOGGER.PrintLine("开始解析地址...", LOGGER.Warning); if (testurl.EndsWith(".json") && File.Exists(testurl)) //可直接跳过解析 { if (!Directory.Exists(Path.Combine(workDir, fileName))) //若文件夹不存在则新建文件夹 { Directory.CreateDirectory(Path.Combine(workDir, fileName)); //新建文件夹 } File.Copy(testurl, Path.Combine(Path.Combine(workDir, fileName), "meta.json"), true); } else { parser.Parse(); //开始解析 } //仅解析模式 if (parseOnly) { LOGGER.PrintLine("解析m3u8成功, 程序退出"); Environment.Exit(0); } if (File.Exists(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))) { JObject initJson = JObject.Parse(File.ReadAllText(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))); isVOD = Convert.ToBoolean(initJson["m3u8Info"]["vod"].ToString()); //传给Watcher总时长 Watcher.TotalDuration = initJson["m3u8Info"]["totalDuration"].Value <double>(); LOGGER.PrintLine($"文件时长:{Global.FormatTime((int)Watcher.TotalDuration)}"); LOGGER.PrintLine("总分片:" + initJson["m3u8Info"]["originalCount"].Value <int>() + ", 已选择分片:" + initJson["m3u8Info"]["count"].Value <int>()); } else { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(workDir, fileName)); directoryInfo.Delete(true); LOGGER.PrintLine("地址无效", LOGGER.Error); LOGGER.CursorIndex = 5; inputRetryCount--; goto input; } //点播 if (isVOD == true) { ServicePointManager.DefaultConnectionLimit = 10000; DownloadManager md = new DownloadManager(); md.DownDir = parser.DownDir; md.Headers = reqHeaders; md.Threads = Environment.ProcessorCount; if (md.Threads > maxThreads) { md.Threads = maxThreads; } if (md.Threads < minThreads) { md.Threads = minThreads; } if (File.Exists("minT.txt")) { int t = Convert.ToInt32(File.ReadAllText("minT.txt")); if (md.Threads <= t) { md.Threads = t; } } md.TimeOut = timeOut * 1000; md.NoMerge = noMerge; md.DownName = fileName; md.DelAfterDone = delAfterDone; md.MuxFormat = "mp4"; md.RetryCount = retryCount; md.MuxSetJson = muxSetJson; md.MuxFastStart = muxFastStart; md.DoDownload(); } //直播 if (isVOD == false) { LOGGER.WriteLine("Living Stream Found"); LOGGER.WriteLine("Start Recording"); LOGGER.PrintLine("识别为直播流, 开始录制"); //LOGGER.STOPLOG = true; //停止记录日志 //开辟文件流,且不关闭。(便于播放器不断读取文件) string LivePath = Path.Combine(Directory.GetParent(parser.DownDir).FullName , DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + "_" + fileName + ".ts"); FileStream outputStream = new FileStream(LivePath, FileMode.Append); HLSLiveDownloader live = new HLSLiveDownloader(); live.DownDir = parser.DownDir; live.Headers = reqHeaders; live.LiveStream = outputStream; live.LiveFile = LivePath; live.TimerStart(); //开始录制 Console.ReadKey(); } //监听测试 /*httplitsen: * HTTPListener.StartListening();*/ LOGGER.WriteLineError("Download Failed"); LOGGER.PrintLine("下载失败, 程序退出", LOGGER.Error); Console.CursorVisible = true; Environment.Exit(-1); //Console.Write("按任意键继续..."); Console.ReadKey(); return; } catch (Exception ex) { Console.CursorVisible = true; LOGGER.PrintLine(ex.Message, LOGGER.Error); } }
public static void processCMD(string[] args) { string fileName = ""; int minThreads = 16; int retryCount = 15; int timeOut = 10; //默认10秒 string baseUrl = ""; //string reqHeaders = ""; string keyFile = ""; string keyBase64 = ""; string keyIV = ""; string muxSetJson = "MUXSETS.json"; string workDir = CURRENT_PATH + "\\Downloads"; bool muxFastStart = false; bool delAfterDone = false; bool parseOnly = false; bool noMerge = false; int keyLength = 0; //分析命令行参数 #region 分析命令行参数 parseArgs: var arguments = CommandLineArgumentParser.Parse(args); if (args.Length == 1 && args[0] == "--help") { Console.WriteLine(strings.helpInfo); return; } if (arguments.Has("--enableDelAfterDone")) { delAfterDone = true; } if (arguments.Has("--enableParseOnly")) { parseOnly = true; } if (arguments.Has("--enableBinaryMerge")) { DownloadManager.BinaryMerge = true; } if (arguments.Has("--disableDateInfo")) { FFmpeg.WriteDate = false; } if (arguments.Has("--noMerge")) { noMerge = true; } if (arguments.Has("--noProxy")) { Global.NoProxy = true; } if (arguments.Has("--headers")) { reqHeaders = arguments.Get("--headers").Next; } if (arguments.Has("--enableMuxFastStart")) { muxFastStart = true; } if (arguments.Has("--disableIntegrityCheck")) { DownloadManager.DisableIntegrityCheck = true; } if (arguments.Has("--enableAudioOnly")) { Global.VIDEO_TYPE = "IGNORE"; } if (arguments.Has("--muxSetJson")) { muxSetJson = arguments.Get("--muxSetJson").Next; } if (arguments.Has("--workDir")) { workDir = arguments.Get("--workDir").Next; DownloadManager.HasSetDir = true; } if (arguments.Has("--saveName")) { fileName = Global.GetValidFileName(arguments.Get("--saveName").Next); } if (arguments.Has("--useKeyFile")) { if (File.Exists(arguments.Get("--useKeyFile").Next)) { keyFile = arguments.Get("--useKeyFile").Next; } } if (arguments.Has("--useKeyBase64")) { keyBase64 = arguments.Get("--useKeyBase64").Next; } if (arguments.Has("--useKeyIV")) { keyIV = arguments.Get("--useKeyIV").Next; } if (arguments.Has("--stopSpeed")) { Global.STOP_SPEED = Convert.ToInt64(arguments.Get("--stopSpeed").Next); } if (arguments.Has("--maxSpeed")) { Global.MAX_SPEED = Convert.ToInt64(arguments.Get("--maxSpeed").Next); } if (arguments.Has("--baseUrl")) { baseUrl = arguments.Get("--baseUrl").Next; } if (arguments.Has("--maxThreads")) { maxThreads = Convert.ToInt32(arguments.Get("--maxThreads").Next); } if (arguments.Has("--minThreads")) { minThreads = Convert.ToInt32(arguments.Get("--minThreads").Next); } if (arguments.Has("--keyLength")) { keyLength = Convert.ToInt32(arguments.Get("--keyLength").Next); } if (arguments.Has("--retryCount")) { retryCount = Convert.ToInt32(arguments.Get("--retryCount").Next); } if (arguments.Has("--timeOut")) { timeOut = Convert.ToInt32(arguments.Get("--timeOut").Next); } if (arguments.Has("--liveRecDur")) { //时间码 Regex reg2 = new Regex(@"(\d+):(\d+):(\d+)"); var t = arguments.Get("--liveRecDur").Next; if (reg2.IsMatch(t)) { int HH = Convert.ToInt32(reg2.Match(t).Groups[1].Value); int MM = Convert.ToInt32(reg2.Match(t).Groups[2].Value); int SS = Convert.ToInt32(reg2.Match(t).Groups[3].Value); HLSLiveDownloader.REC_DUR_LIMIT = SS + MM * 60 + HH * 60 * 60; } } if (arguments.Has("--downloadRange")) { string p = arguments.Get("--downloadRange").Next; if (p.Contains(":")) { //时间码 Regex reg2 = new Regex(@"((\d+):(\d+):(\d+))?-((\d+):(\d+):(\d+))?"); if (reg2.IsMatch(p)) { Parser.DurStart = reg2.Match(p).Groups[1].Value; Parser.DurEnd = reg2.Match(p).Groups[5].Value; Parser.DelAd = false; } } else { //数字 Regex reg = new Regex(@"(\d*)-(\d*)"); if (reg.IsMatch(p)) { if (!string.IsNullOrEmpty(reg.Match(p).Groups[1].Value)) { Parser.RangeStart = Convert.ToInt32(reg.Match(p).Groups[1].Value); Parser.DelAd = false; } if (!string.IsNullOrEmpty(reg.Match(p).Groups[2].Value)) { Parser.RangeEnd = Convert.ToInt32(reg.Match(p).Groups[2].Value); Parser.DelAd = false; } } } } //如果只有URL,没有附加参数,则尝试解析配置文件 if (args.Length == 1 || (args.Length == 3 && args[1].ToLower() == "--savename")) { if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))) { if (args.Length == 3) { args = Global.ParseArguments($"\"{args[0]}\" {args[1]} {args[2]} " + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))).ToArray(); //解析命令行 } else { args = Global.ParseArguments($"\"{args[0]}\" " + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"))).ToArray(); //解析命令行 } goto parseArgs; } } //ReadLine字数上限 Stream steam = Console.OpenStandardInput(); Console.SetIn(new StreamReader(steam, Encoding.Default, false, 5000)); int inputRetryCount = 20; #endregion input: string testurl = ""; //重试太多次,退出 if (inputRetryCount == 0) { Environment.Exit(-1); } if (args.Length > 0) { testurl = args[0]; } else { } if (fileName == "") { fileName = Global.GetUrlFileName(testurl) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"); } if (testurl.Contains("twitcasting") && testurl.Contains("/fmp4/")) { DownloadManager.BinaryMerge = true; } string m3u8Content = string.Empty; bool isVOD = true; //避免文件路径过长 if (workDir.Length >= 200) { //目录不能随便改 直接抛出异常 throw new Exception("保存目录过长!"); } else if (workDir.Length + fileName.Length >= 200) { //尝试缩短文件名 while (workDir.Length + fileName.Length >= 200) { fileName = fileName.Substring(0, fileName.Length - 1); } } //开始解析 Console.CursorVisible = false; LOGGER.PrintLine($"{string.Format(strings.fileName, "(" + currentIndex + "/" + fileCount + ")")}{fileName}"); LOGGER.PrintLine($"{strings.savePath}{Path.GetDirectoryName(Path.Combine(workDir, fileName))}"); Parser parser = new Parser(); parser.DownName = fileName; parser.DownDir = Path.Combine(workDir, parser.DownName); parser.M3u8Url = testurl; parser.KeyBase64 = keyBase64; parser.KeyIV = keyIV; parser.KeyFile = keyFile; if (baseUrl != "") { parser.BaseUrl = baseUrl; } parser.Headers = reqHeaders; string exePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); LOGGER.LOGFILE = Path.Combine(exePath, "Logs", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log"); LOGGER.InitLog(); LOGGER.WriteLine(strings.startParsing + testurl); LOGGER.PrintLine(strings.startParsing, LOGGER.Warning); if (testurl.EndsWith(".json") && File.Exists(testurl)) //可直接跳过解析 { if (!Directory.Exists(Path.Combine(workDir, fileName))) //若文件夹不存在则新建文件夹 { Directory.CreateDirectory(Path.Combine(workDir, fileName)); //新建文件夹 } File.Copy(testurl, Path.Combine(Path.Combine(workDir, fileName), "meta.json"), true); } else { parser.Parse(); //开始解析 } //仅解析模式 if (parseOnly) { LOGGER.PrintLine(strings.parseExit); Environment.Exit(0); } if (File.Exists(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))) { JObject initJson = JObject.Parse(File.ReadAllText(Path.Combine(Path.Combine(workDir, fileName), "meta.json"))); isVOD = Convert.ToBoolean(initJson["m3u8Info"]["vod"].ToString()); //传给Watcher总时长 Watcher.TotalDuration = initJson["m3u8Info"]["totalDuration"].Value <double>(); LOGGER.PrintLine($"{strings.fileDuration}{Global.FormatTime((int)Watcher.TotalDuration)}"); LOGGER.PrintLine(strings.segCount + initJson["m3u8Info"]["originalCount"].Value <int>() + $", {strings.selectedCount}" + initJson["m3u8Info"]["count"].Value <int>()); } else { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(workDir, fileName)); directoryInfo.Delete(true); LOGGER.PrintLine(strings.InvalidUri, LOGGER.Error); LOGGER.CursorIndex = 5; inputRetryCount--; goto input; } //点播 if (isVOD == true) { ServicePointManager.DefaultConnectionLimit = 10000; DownloadManager md = new DownloadManager(); md.DownDir = parser.DownDir; md.Headers = reqHeaders; md.Threads = Environment.ProcessorCount; if (md.Threads > maxThreads) { md.Threads = maxThreads; } if (md.Threads < minThreads) { md.Threads = minThreads; } if (File.Exists("minT.txt")) { int t = Convert.ToInt32(File.ReadAllText("minT.txt")); if (md.Threads <= t) { md.Threads = t; } } md.TimeOut = timeOut * 1000; md.NoMerge = noMerge; md.DownName = fileName; md.DelAfterDone = delAfterDone; md.MuxFormat = "mp4"; md.RetryCount = retryCount; md.MuxSetJson = muxSetJson; md.MuxFastStart = muxFastStart; md.KeyLength = keyLength; md.DoDownload(listCount--); currentIndex++; } //直播 if (isVOD == false) { LOGGER.WriteLine(strings.liveStreamFoundAndRecoding); LOGGER.PrintLine(strings.liveStreamFoundAndRecoding); //LOGGER.STOPLOG = true; //停止记录日志 //开辟文件流,且不关闭。(便于播放器不断读取文件) string LivePath = Path.Combine(Directory.GetParent(parser.DownDir).FullName , DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + "_" + fileName + ".ts"); FileStream outputStream = new FileStream(LivePath, FileMode.Append); HLSLiveDownloader live = new HLSLiveDownloader(); live.DownDir = parser.DownDir; live.Headers = reqHeaders; live.LiveStream = outputStream; live.LiveFile = LivePath; live.TimerStart(); //开始录制 Console.ReadKey(); } }