1import argparse
2import re
3
4from string import printable
5from textwrap import dedent
6
7from .constants import (
8    LIVESTREAMER_VERSION, STREAM_PASSTHROUGH, DEFAULT_PLAYER_ARGUMENTS
9)
10from .utils import find_default_player
11
12
13_filesize_re = re.compile("""
14    (?P<size>\d+(\.\d+)?)
15    (?P<modifier>[Kk]|[Mm])?
16    (?:[Bb])?
17""", re.VERBOSE)
18_keyvalue_re = re.compile("(?P<key>[^=]+)\s*=\s*(?P<value>.*)")
19_printable_re = re.compile("[{0}]".format(printable))
20_option_re = re.compile("""
21    (?P<name>[A-z-]+) # A option name, valid characters are A to z and dash.
22    \s*
23    (?P<op>=)? # Separating the option and the value with a equals sign is
24               # common, but optional.
25    \s*
26    (?P<value>.*) # The value, anything goes.
27""", re.VERBOSE)
28
29
30class ArgumentParser(argparse.ArgumentParser):
31    def convert_arg_line_to_args(self, line):
32        # Strip any non-printable characters that might be in the
33        # beginning of the line (e.g. Unicode BOM marker).
34        match = _printable_re.search(line)
35        if not match:
36            return
37        line = line[match.start():].strip()
38
39        # Skip lines that do not start with a valid option (e.g. comments)
40        option = _option_re.match(line)
41        if not option:
42            return
43
44        name, value = option.group("name", "value")
45        if name and value:
46            yield "--{0}={1}".format(name, value)
47        elif name:
48            yield "--{0}".format(name)
49
50
51class HelpFormatter(argparse.RawDescriptionHelpFormatter):
52    """A nicer help formatter.
53
54    Help for arguments can be indented and contain new lines.
55    It will be de-dented and arguments in the help will be
56    separated by a blank line for better readability.
57
58    Originally written by Jakub Roztocil of the httpie project.
59    """
60    def __init__(self, max_help_position=4, *args, **kwargs):
61        # A smaller indent for args help.
62        kwargs["max_help_position"] = max_help_position
63        argparse.RawDescriptionHelpFormatter.__init__(self, *args, **kwargs)
64
65    def _split_lines(self, text, width):
66        text = dedent(text).strip() + "\n\n"
67        return text.splitlines()
68
69
70def comma_list(values):
71    return [val.strip() for val in values.split(",")]
72
73
74def comma_list_filter(acceptable):
75    def func(p):
76        values = comma_list(p)
77        return list(filter(lambda v: v in acceptable, values))
78
79    return func
80
81
82def num(type, min=None, max=None):
83    def func(value):
84        value = type(value)
85
86        if min is not None and not (value > min):
87            raise argparse.ArgumentTypeError(
88                "{0} value must be more than {1} but is {2}".format(
89                    type.__name__, min, value
90                )
91            )
92
93        if max is not None and not (value <= max):
94            raise argparse.ArgumentTypeError(
95                "{0} value must be at most {1} but is {2}".format(
96                    type.__name__, max, value
97                )
98            )
99
100        return value
101
102    func.__name__ = type.__name__
103
104    return func
105
106
107def filesize(value):
108    match = _filesize_re.match(value)
109    if not match:
110        raise ValueError
111
112    size = float(match.group("size"))
113    if not size:
114        raise ValueError
115
116    modifier = match.group("modifier")
117    if modifier in ("M", "m"):
118        size *= 1024 * 1024
119    elif modifier in ("K", "k"):
120        size *= 1024
121
122    return num(int, min=0)(size)
123
124
125def keyvalue(value):
126    match = _keyvalue_re.match(value)
127    if not match:
128        raise ValueError
129
130    return match.group("key", "value")
131
132
133parser = ArgumentParser(
134    fromfile_prefix_chars="@",
135    formatter_class=HelpFormatter,
136    add_help=False,
137    usage="%(prog)s [OPTIONS] [URL] [STREAM]",
138    description=dedent("""
139    Livestreamer is command-line utility that extracts streams from
140    various services and pipes them into a video player of choice.
141    """),
142    epilog=dedent("""
143    For more in-depth documention see:
144      http://docs.livestreamer.io/
145
146    Please report broken plugins or bugs to the issue tracker on Github:
147      https://github.com/chrippa/livestreamer/issues
148    """)
149)
150
151positional = parser.add_argument_group("Positional arguments")
152positional.add_argument(
153    "url",
154    metavar="URL",
155    nargs="?",
156    help="""
157    A URL to attempt to extract streams from.
158
159    If it's a HTTP URL then "http://" can be omitted.
160    """
161)
162positional.add_argument(
163    "stream",
164    metavar="STREAM",
165    nargs="?",
166    type=comma_list,
167    help="""
168    Stream to play.
169
170    Use "best" or "worst" for highest or lowest quality available.
171
172    Fallback streams can be specified by using a comma-separated list:
173
174      "720p,480p,best"
175
176    If no stream is specified and --default-stream is not used then a
177    list of available streams will be printed.
178    """
179)
180
181general = parser.add_argument_group("General options")
182general.add_argument(
183    "-h", "--help",
184    action="store_true",
185    help="""
186    Show this help message and exit.
187    """
188)
189general.add_argument(
190    "-V", "--version",
191    action="version",
192    version="%(prog)s {0}".format(LIVESTREAMER_VERSION),
193    help="""
194    Show version number and exit.
195    """
196)
197general.add_argument(
198    "--plugins",
199    action="store_true",
200    help="""
201    Print a list of all currently installed plugins.
202    """
203)
204general.add_argument(
205    "--can-handle-url",
206    metavar="URL",
207    help="""
208    Check if Livestreamer has a plugin that can handle the specified URL.
209
210    Returns status code 1 for false and 0 for true.
211
212    Useful for external scripting.
213    """
214)
215general.add_argument(
216    "--config",
217    action="append",
218    metavar="FILENAME",
219    help="""
220    Load options from this config file.
221
222    Can be repeated to load multiple files, in which case
223    the options are merged on top of each other where the
224    last config has highest priority.
225    """
226)
227general.add_argument(
228    "-l", "--loglevel",
229    metavar="LEVEL",
230    default="info",
231    help="""
232    Set the log message threshold.
233
234    Valid levels are: none, error, warning, info, debug
235    """
236)
237general.add_argument(
238    "-Q", "--quiet",
239    action="store_true",
240    help="""
241    Hide all log output.
242
243    Alias for "--loglevel none".
244    """
245)
246general.add_argument(
247    "-j", "--json",
248    action="store_true",
249    help="""
250    Output JSON representations instead of the normal text output.
251
252    Useful for external scripting.
253    """
254)
255general.add_argument(
256    "--no-version-check",
257    action="store_true",
258    help="""
259    Do not check for new Livestreamer releases.
260    """
261)
262general.add_argument(
263    "--version-check",
264    action="store_true",
265    help="""
266    Runs a version check and exits.
267    """
268)
269general.add_argument(
270    "--yes-run-as-root",
271    action="store_true",
272    help=argparse.SUPPRESS
273)
274
275player = parser.add_argument_group("Player options")
276player.add_argument(
277    "-p", "--player",
278    metavar="COMMAND",
279    default=find_default_player(),
280    help="""
281    Player to feed stream data to. This is a shell-like syntax to
282    support passing options to the player. For example:
283
284      "vlc --file-caching=5000"
285
286    To use a player that is located in a path with spaces you must
287    quote the path:
288
289      "'/path/with spaces/vlc' --file-caching=5000"
290
291    By default VLC will be used if it can be found in its default
292    location.
293    """
294)
295player.add_argument(
296    "-a", "--player-args",
297    metavar="ARGUMENTS",
298    default=DEFAULT_PLAYER_ARGUMENTS,
299    help="""
300    This option allows you to customize the default arguments which
301    are put together with the value of --player to create a command
302    to execute.
303
304    This value can contain formatting variables surrounded by curly
305    braces, {{ and }}. If you need to include a brace character, it
306    can be escaped by doubling, e.g. {{{{ and }}}}.
307
308    Formatting variables available:
309
310    filename
311      This is the filename that the player will use.
312      It's usually "-" (stdin), but can also be a URL or a file
313      depending on the options used.
314
315    It's usually enough to use --player instead of this unless you
316    need to add arguments after the filename.
317
318    Default is "{0}".
319    """.format(DEFAULT_PLAYER_ARGUMENTS)
320)
321player.add_argument(
322    "-v", "--verbose-player",
323    action="store_true",
324    help="""
325    Allow the player to display its console output.
326    """
327)
328player.add_argument(
329    "-n", "--player-fifo", "--fifo",
330    action="store_true",
331    help="""
332    Make the player read the stream through a named pipe instead of
333    the stdin pipe.
334    """
335)
336player.add_argument(
337    "--player-http",
338    action="store_true",
339    help="""
340    Make the player read the stream through HTTP instead of
341    the stdin pipe.
342    """
343)
344player.add_argument(
345    "--player-continuous-http",
346    action="store_true",
347    help="""
348    Make the player read the stream through HTTP, but unlike
349    --player-http it will continuously try to open the stream if the
350    player requests it.
351
352    This makes it possible to handle stream disconnects if your player
353    is capable of reconnecting to a HTTP stream. This is usually
354    done by setting your player to a "repeat mode".
355
356    """
357)
358player.add_argument(
359    "--player-external-http",
360    action="store_true",
361    help="""
362    Serve stream data through HTTP without running any player. This is useful
363    to allow external devices like smartphones or streaming boxes to watch
364    streams they wouldn't be able to otherwise.
365
366    Behavior will be similar to the continuous HTTP option, but no player
367    program will be started, and the server will listen on all available
368    connections instead of just in the local (loopback) interface.
369
370    The URLs that can be used to access the stream will be printed to the
371    console, and the server can be interrupted using CTRL-C.
372    """
373)
374player.add_argument(
375    "--player-external-http-port",
376    metavar="PORT",
377    type=num(int, min=0, max=65535),
378    default=0,
379    help="""
380    A fixed port to use for the external HTTP server if that mode is enabled.
381    Omit or set to 0 to use a random high (>1024) port.
382    """
383)
384player.add_argument(
385    "--player-passthrough",
386    metavar="TYPES",
387    type=comma_list_filter(STREAM_PASSTHROUGH),
388    default=[],
389    help="""
390    A comma-delimited list of stream types to pass to the player as a
391    URL to let it handle the transport of the stream instead.
392
393    Stream types that can be converted into a playable URL are:
394
395    - {0}
396
397    Make sure your player can handle the stream type when using this.
398    """.format("\n    - ".join(STREAM_PASSTHROUGH))
399)
400player.add_argument(
401    "--player-no-close",
402    action="store_true",
403    help="""
404    By default Livestreamer will close the player when the stream ends.
405    This is to avoid "dead" GUI players lingering after a stream ends.
406
407    It does however have the side-effect of sometimes closing a player
408    before it has played back all of its cached data.
409
410    This option will instead let the player decide when to exit.
411    """
412)
413
414output = parser.add_argument_group("File output options")
415output.add_argument(
416    "-o", "--output",
417    metavar="FILENAME",
418    help="""
419    Write stream data to FILENAME instead of playing it.
420
421    You will be prompted if the file already exists.
422    """
423)
424output.add_argument(
425    "-f", "--force",
426    action="store_true",
427    help="""
428    When using -o, always write to file even if it already exists.
429    """
430)
431output.add_argument(
432    "-O", "--stdout",
433    action="store_true",
434    help="""
435    Write stream data to stdout instead of playing it.
436    """
437)
438
439stream = parser.add_argument_group("Stream options")
440stream.add_argument(
441    "--default-stream",
442    type=comma_list,
443    metavar="STREAM",
444    help="""
445    Open this stream when no stream argument is specified, e.g. "best".
446    """
447)
448stream.add_argument(
449    "--retry-streams",
450    metavar="DELAY",
451    type=num(float, min=0),
452    help="""
453    Will retry fetching streams until streams are found while
454    waiting DELAY (seconds) between each attempt.
455    """
456)
457stream.add_argument(
458    "--retry-open",
459    metavar="ATTEMPTS",
460    type=num(int, min=0),
461    default=1,
462    help="""
463    Will try ATTEMPTS times to open the stream until giving up.
464
465    Default is 1.
466    """
467)
468stream.add_argument(
469    "--stream-types", "--stream-priority",
470    metavar="TYPES",
471    type=comma_list,
472    help="""
473    A comma-delimited list of stream types to allow.
474
475    The order will be used to separate streams when there are multiple
476    streams with the same name but different stream types.
477
478    Default is "rtmp,hls,hds,http,akamaihd".
479    """
480)
481stream.add_argument(
482    "--stream-sorting-excludes",
483    metavar="STREAMS",
484    type=comma_list,
485    help="""
486    Fine tune best/worst synonyms by excluding unwanted streams.
487
488    Uses a filter expression in the format:
489
490      [operator]<value>
491
492    Valid operators are >, >=, < and <=. If no operator is specified
493    then equality is tested.
494
495    For example this will exclude streams ranked higher than "480p":
496
497      ">480p"
498
499    Multiple filters can be used by separating each expression with
500    a comma.
501
502    For example this will exclude streams from two quality types:
503
504      ">480p,>medium"
505
506    """
507)
508
509transport = parser.add_argument_group("Stream transport options")
510transport.add_argument(
511    "--hds-live-edge",
512    type=num(float, min=0),
513    metavar="SECONDS",
514    help="""
515    The time live HDS streams will start from the edge of stream.
516
517    Default is 10.0.
518    """
519)
520transport.add_argument(
521    "--hds-segment-attempts",
522    type=num(int, min=0),
523    metavar="ATTEMPTS",
524    help="""
525    How many attempts should be done to download each HDS segment
526    before giving up.
527
528    Default is 3.
529    """
530)
531transport.add_argument(
532    "--hds-segment-threads",
533    type=num(int, max=10),
534    metavar="THREADS",
535    help="""
536    The size of the thread pool used to download HDS segments.
537    Minimum value is 1 and maximum is 10.
538
539    Default is 1.
540    """
541)
542transport.add_argument(
543    "--hds-segment-timeout",
544    type=num(float, min=0),
545    metavar="TIMEOUT",
546    help="""
547    HDS segment connect and read timeout.
548
549    Default is 10.0.
550    """
551)
552transport.add_argument(
553    "--hds-timeout",
554    type=num(float, min=0),
555    metavar="TIMEOUT",
556    help="""
557    Timeout for reading data from HDS streams.
558
559    Default is 60.0.
560    """
561)
562transport.add_argument(
563    "--hls-live-edge",
564    type=num(int, min=0),
565    metavar="SEGMENTS",
566    help="""
567    How many segments from the end to start live HLS streams on.
568
569    The lower the value the lower latency from the source you will be,
570    but also increases the chance of buffering.
571
572    Default is 3.
573    """
574)
575transport.add_argument(
576    "--hls-segment-attempts",
577    type=num(int, min=0),
578    metavar="ATTEMPTS",
579    help="""
580    How many attempts should be done to download each HLS segment
581    before giving up.
582
583    Default is 3.
584    """
585)
586transport.add_argument(
587    "--hls-segment-threads",
588    type=num(int, max=10),
589    metavar="THREADS",
590    help="""
591    The size of the thread pool used to download HLS segments.
592    Minimum value is 1 and maximum is 10.
593
594    Default is 1.
595    """
596)
597transport.add_argument(
598    "--hls-segment-timeout",
599    type=num(float, min=0),
600    metavar="TIMEOUT",
601    help="""
602    HLS segment connect and read timeout.
603
604    Default is 10.0.
605    """)
606transport.add_argument(
607    "--hls-timeout",
608    type=num(float, min=0),
609    metavar="TIMEOUT",
610    help="""
611    Timeout for reading data from HLS streams.
612
613    Default is 60.0.
614    """)
615transport.add_argument(
616    "--http-stream-timeout",
617    type=num(float, min=0),
618    metavar="TIMEOUT",
619    help="""
620    Timeout for reading data from HTTP streams.
621
622    Default is 60.0.
623    """
624)
625transport.add_argument(
626    "--ringbuffer-size",
627    metavar="SIZE",
628    type=filesize,
629    help="""
630    The maximum size of ringbuffer. Add a M or K suffix to specify mega
631    or kilo bytes instead of bytes.
632
633    The ringbuffer is used as a temporary storage between the stream
634    and the player. This is to allows us to download the stream faster
635    than the player wants to read it.
636
637    The smaller the size, the higher chance of the player buffering
638    if there are download speed dips and the higher size the more data
639    we can use as a storage to catch up from speed dips.
640
641    It also allows you to temporary pause as long as the ringbuffer
642    doesn't get full since we continue to download the stream in the
643    background.
644
645    Note: A smaller size is recommended on lower end systems (such as
646    Raspberry Pi) when playing stream types that require some extra
647    processing (such as HDS) to avoid unnecessary background
648    processing.
649
650    Default is "16M".
651    """)
652transport.add_argument(
653    "--rtmp-proxy", "--rtmpdump-proxy",
654    metavar="PROXY",
655    help="""
656    A SOCKS proxy that RTMP streams will use.
657
658    Example: 127.0.0.1:9050
659    """
660)
661transport.add_argument(
662    "--rtmp-rtmpdump", "--rtmpdump", "-r",
663    metavar="FILENAME",
664    help="""
665    RTMPDump is used to access RTMP streams. You can specify the
666    location of the rtmpdump executable if it is not in your PATH.
667
668    Example: "/usr/local/bin/rtmpdump"
669    """
670)
671transport.add_argument(
672    "--rtmp-timeout",
673    type=num(float, min=0),
674    metavar="TIMEOUT",
675    help="""
676    Timeout for reading data from RTMP streams.
677
678    Default is 60.0.
679    """
680)
681transport.add_argument(
682    "--stream-segment-attempts",
683    type=num(int, min=0),
684    metavar="ATTEMPTS",
685    help="""
686    How many attempts should be done to download each segment before giving up.
687
688    This is generic option used by streams not covered by other options,
689    such as stream protocols specific to plugins, e.g. UStream.
690
691    Default is 3.
692    """
693)
694transport.add_argument(
695    "--stream-segment-threads",
696    type=num(int, max=10),
697    metavar="THREADS",
698    help="""
699    The size of the thread pool used to download segments.
700    Minimum value is 1 and maximum is 10.
701
702    This is generic option used by streams not covered by other options,
703    such as stream protocols specific to plugins, e.g. UStream.
704
705    Default is 1.
706    """
707)
708transport.add_argument(
709    "--stream-segment-timeout",
710    type=num(float, min=0),
711    metavar="TIMEOUT",
712    help="""
713    Segment connect and read timeout.
714
715    This is generic option used by streams not covered by other options,
716    such as stream protocols specific to plugins, e.g. UStream.
717
718    Default is 10.0.
719    """)
720transport.add_argument(
721    "--stream-timeout",
722    type=num(float, min=0),
723    metavar="TIMEOUT",
724    help="""
725    Timeout for reading data from streams.
726
727    This is generic option used by streams not covered by other options,
728    such as stream protocols specific to plugins, e.g. UStream.
729
730    Default is 60.0.
731    """)
732transport.add_argument(
733    "--stream-url",
734    action="store_true",
735    help="""
736    If possible, translate the stream to a URL and print it.
737    """
738)
739transport.add_argument(
740    "--subprocess-cmdline", "--cmdline", "-c",
741    action="store_true",
742    help="""
743    Print command-line used internally to play stream.
744
745    This is only available on RTMP streams.
746    """
747)
748transport.add_argument(
749    "--subprocess-errorlog", "--errorlog", "-e",
750    action="store_true",
751    help="""
752    Log possible errors from internal subprocesses to a temporary file.
753    The file will be saved in your systems temporary directory.
754
755    Useful when debugging rtmpdump related issues.
756    """
757)
758
759
760http = parser.add_argument_group("HTTP options")
761http.add_argument(
762    "--http-proxy",
763    metavar="HTTP_PROXY",
764    help="""
765    A HTTP proxy to use for all HTTP requests.
766
767    Example: http://hostname:port/
768    """
769)
770http.add_argument(
771    "--https-proxy",
772    metavar="HTTPS_PROXY",
773    help="""
774    A HTTPS capable proxy to use for all HTTPS requests.
775
776    Example: http://hostname:port/
777    """
778)
779http.add_argument(
780    "--http-cookie",
781    metavar="KEY=VALUE",
782    type=keyvalue,
783    action="append",
784    help="""
785    A cookie to add to each HTTP request.
786
787    Can be repeated to add multiple cookies.
788    """
789)
790http.add_argument(
791    "--http-header",
792    metavar="KEY=VALUE",
793    type=keyvalue,
794    action="append",
795    help="""
796    A header to add to each HTTP request.
797
798    Can be repeated to add multiple headers.
799    """
800)
801http.add_argument(
802    "--http-query-param",
803    metavar="KEY=VALUE",
804    type=keyvalue,
805    action="append",
806    help="""
807    A query parameter to add to each HTTP request.
808
809    Can be repeated to add multiple query parameters.
810    """
811)
812http.add_argument(
813    "--http-ignore-env",
814    action="store_true",
815    help="""
816    Ignore HTTP settings set in the environment such as environment
817    variables (HTTP_PROXY, etc) or ~/.netrc authentication.
818    """
819)
820http.add_argument(
821    "--http-no-ssl-verify",
822    action="store_true",
823    help="""
824    Don't attempt to verify SSL certificates.
825
826    Usually a bad idea, only use this if you know what you're doing.
827    """
828)
829http.add_argument(
830    "--http-ssl-cert",
831    metavar="FILENAME",
832    help="""
833    SSL certificate to use.
834
835    Expects a .pem file.
836    """
837)
838http.add_argument(
839    "--http-ssl-cert-crt-key",
840    metavar=("CRT_FILENAME", "KEY_FILENAME"),
841    nargs=2,
842    help="""
843    SSL certificate to use.
844
845    Expects a .crt and a .key file.
846    """
847)
848http.add_argument(
849    "--http-timeout",
850    metavar="TIMEOUT",
851    type=num(float, min=0),
852    help="""
853    General timeout used by all HTTP requests except the ones covered
854    by other options.
855
856    Default is 20.0.
857    """
858)
859
860
861plugin = parser.add_argument_group("Plugin options")
862plugin.add_argument(
863    "--plugin-dirs",
864    metavar="DIRECTORY",
865    type=comma_list,
866    help="""
867    Attempts to load plugins from these directories.
868
869    Multiple directories can be used by separating them with a
870    semi-colon.
871    """
872)
873plugin.add_argument(
874    "--twitch-oauth-token",
875    metavar="TOKEN",
876    help="""
877    An OAuth token to use for Twitch authentication.
878    Use --twitch-oauth-authenticate to create a token.
879    """
880)
881plugin.add_argument(
882    "--twitch-oauth-authenticate",
883    action="store_true",
884    help="""
885    Open a web browser where you can grant Livestreamer access
886    to your Twitch account which creates a token for use with
887    --twitch-oauth-token.
888    """
889)
890plugin.add_argument(
891    "--twitch-cookie",
892    metavar="COOKIES",
893    help="""
894    Twitch cookies to authenticate to allow access to subscription channels.
895
896    Example:
897
898      "_twitch_session_id=xxxxxx; persistent=xxxxx"
899
900    Note: This method is the old and clunky way of authenticating with
901    Twitch, using --twitch-oauth-authenticate is the recommended and
902    simpler way of doing it now.
903
904    """
905)
906plugin.add_argument(
907    "--ustream-password",
908    metavar="PASSWORD",
909    help="""
910    A password to access password protected UStream.tv channels.
911    """
912)
913plugin.add_argument(
914    "--crunchyroll-username",
915    metavar="USERNAME",
916    help="""
917    A Crunchyroll username to allow access to restricted streams.
918    """
919)
920plugin.add_argument(
921    "--crunchyroll-password",
922    metavar="PASSWORD",
923    nargs="?",
924    const=True,
925    default=None,
926    help="""
927    A Crunchyroll password for use with --crunchyroll-username.
928
929    If left blank you will be prompted.
930    """
931)
932plugin.add_argument(
933    "--crunchyroll-purge-credentials",
934    action="store_true",
935    help="""
936    Purge cached Crunchyroll credentials to initiate a new session
937    and reauthenticate.
938    """
939)
940plugin.add_argument(
941    "--livestation-email",
942    metavar="EMAIL",
943    help="""
944    A Livestation account email to access restricted or premium
945    quality streams.
946    """
947)
948plugin.add_argument(
949    "--livestation-password",
950    metavar="PASSWORD",
951    help="""
952    A Livestation account password to use with --livestation-email.
953    """
954)
955
956
957# Deprecated options
958stream.add_argument(
959    "--best-stream-default",
960    action="store_true",
961    help=argparse.SUPPRESS
962)
963player.add_argument(
964    "-q", "--quiet-player",
965    action="store_true",
966    help=argparse.SUPPRESS
967)
968transport.add_argument(
969    "--hds-fragment-buffer",
970    type=int,
971    metavar="fragments",
972    help=argparse.SUPPRESS
973)
974plugin.add_argument(
975    "--jtv-legacy-names", "--twitch-legacy-names",
976    action="store_true",
977    help=argparse.SUPPRESS
978)
979plugin.add_argument(
980    "--gomtv-cookie",
981    metavar="cookie",
982    help=argparse.SUPPRESS
983)
984plugin.add_argument(
985    "--gomtv-username",
986    metavar="username",
987    help=argparse.SUPPRESS
988)
989plugin.add_argument(
990    "--gomtv-password",
991    metavar="password",
992    nargs="?",
993    const=True,
994    default=None,
995    help=argparse.SUPPRESS
996)
997plugin.add_argument(
998    "--jtv-cookie",
999    help=argparse.SUPPRESS
1000)
1001plugin.add_argument(
1002    "--jtv-password", "--twitch-password",
1003    help=argparse.SUPPRESS
1004)
1005http.add_argument(
1006    "--http-cookies",
1007    metavar="COOKIES",
1008    help=argparse.SUPPRESS
1009)
1010http.add_argument(
1011    "--http-headers",
1012    metavar="HEADERS",
1013    help=argparse.SUPPRESS
1014)
1015http.add_argument(
1016    "--http-query-params",
1017    metavar="PARAMS",
1018    help=argparse.SUPPRESS
1019)
1020
1021__all__ = ["parser"]
1022