private void NextStepIsToChooseQuality()
        {
            if (CsDownloadVidFilepaths.GetYtdlPath(cbUsePytube.Checked,
                                                   required: false) == null)
            {
                return;
            }

            listBoxFmts.Items.Clear();
            AddGenericFormatsToListbox();
            GetOptionsFromUI(out List <string> urlsRet, out int waitBetween,
                             out string filenamePattern, out string outDir);

            // look up formats
            txtStatus.Visible                   = true;
            lblShortStatus.Visible              = true;
            panelChooseQuality.Visible          = true;
            btnNextStepIsToChooseOutput.Enabled = false;
            btnNextStepIsToChooseOutput.Text    = "Looking up formats...";
            var urlToGet = urlsRet[0];
            var info     = GetStartInfo(urlToGet, "", true);

            // run all in a separate thread, so that UI remains responsive.
            _runner.RunInThread(() =>
            {
                LoadFormats_StartProc(urlToGet, info);
            });
        }
        private static void GetPlaylistImpl(string url, string txtpath, RunToolHelper runner)
        {
            bool isPytube = false; // use only ytdl, not pytube
            var  args     = new List <string>();

            args.Add("--ignore-config"); // don't look for global config file
            args.Add("--no-mark-watched");
            args.Add("--no-call-home");
            args.Add("-j"); // send output in json format
            args.Add("--flat-playlist");
            args.Add("-i"); // continue after errs
            args.Add(url);

            var info = new ProcessStartInfo();

            info.FileName               = CsDownloadVidFilepaths.GetYtdlPath(isPytube);
            info.Arguments              = Utils.CombineProcessArguments(args.ToArray());
            info.CreateNoWindow         = true;
            info.RedirectStandardError  = true;
            info.RedirectStandardOutput = true;
            info.UseShellExecute        = false;

            if (CsDownloadVidFilepaths.GetYtdlPath(isPytube).EndsWith(".py"))
            {
                info.FileName  = CsDownloadVidFilepaths.GetPython();
                info.Arguments = "\"" + CsDownloadVidFilepaths.GetYtdlPath(isPytube) + "\" " +
                                 Utils.CombineProcessArguments(args.ToArray());
            }

            var     stdoutGot = "";
            Process p         = new Process();

            p.StartInfo = info;
            p.Start();
            p.OutputDataReceived += (o, eparam) => { stdoutGot += eparam.Data; };
            p.BeginOutputReadLine();
            p.WaitForExit();

            if (p.ExitCode != 0)
            {
                throw new CsDownloadVidException("error - non-zero exit code of " + p.ExitCode);
            }

            stdoutGot = stdoutGot.Trim();
            if (!stdoutGot.StartsWith("{"))
            {
                throw new CsDownloadVidException("error - did not get valid json back " +
                                                 stdoutGot);
            }

            GetPlaylistImplFromJson(runner, url, stdoutGot, txtpath);
        }
        ProcessStartInfo GetStartInfo(string url, string format, bool listSupportedFormatsOnly)
        {
            var args = new List <string>();

            args.Add("--ignore-config"); // don't look for global config file
            args.Add("--no-mark-watched");
            args.Add("--no-call-home");
            args.Add("--no-mtime"); // don't adjust the lmt of the file, it's confusing
            args.Add("--no-playlist");

            if (listSupportedFormatsOnly)
            {
                args.Add("--list-formats");
                args.Add("--simulate");
            }
            else
            {
                args.Add("--format");
                args.Add(format);

                // post-process, otherwise the m4a won't show correctly in some media players
                if (chkDashToM4a.Checked)
                {
                    args.Add("--ffmpeg-location");
                    args.Add(CsDownloadVidFilepaths.GetFfmpeg());
                }
            }

            if (cbUsePytube.Checked)
            {
                args.Add("--outputdir=" + txtOutputDir.Text);
            }
            else
            {
                var outputTemplate = Path.Combine(txtOutputDir.Text, txtFilenamePattern.Text);
                args.Add("--output");
                args.Add(outputTemplate);
            }

            var sArgs = Utils.CombineProcessArguments(args.ToArray());

            if (!string.IsNullOrWhiteSpace(txtAdditionalArgs.Text))
            {
                sArgs += " " + txtAdditionalArgs.Text + " ";
            }

            sArgs += " " + Utils.CombineProcessArguments(new string[] { url });

            var info = new ProcessStartInfo();

            info.FileName               = CsDownloadVidFilepaths.GetYtdlPath(this.cbUsePytube.Checked);
            info.Arguments              = sArgs;
            info.CreateNoWindow         = true;
            info.RedirectStandardError  = true;
            info.RedirectStandardOutput = true;
            info.UseShellExecute        = false;

            if (CsDownloadVidFilepaths.GetYtdlPath(this.cbUsePytube.Checked).EndsWith(".py"))
            {
                info.FileName  = CsDownloadVidFilepaths.GetPython();
                info.Arguments = "\"" + CsDownloadVidFilepaths.GetYtdlPath(
                    this.cbUsePytube.Checked) + "\" " + sArgs;
            }

            return(info);
        }