Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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);
            }
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
        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();
            }
        }