mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-04-14 02:54:50 +09:00
Rewrite zsh completion script, fix #30900
1. `devscripts/zsh-completion.py` 2. `sudo mv youtube-dl.zsh /usr/share/zsh/site-functions/_youtube-dl` 3. `compinit`
This commit is contained in:
parent
adb5294177
commit
66c952916d
@ -1,28 +1,22 @@
|
||||
#compdef youtube-dl
|
||||
#compdef {{programs}}
|
||||
# https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide
|
||||
|
||||
__youtube_dl() {
|
||||
local curcontext="$curcontext" fileopts diropts cur prev
|
||||
typeset -A opt_args
|
||||
fileopts="{{fileopts}}"
|
||||
diropts="{{diropts}}"
|
||||
cur=$words[CURRENT]
|
||||
case $cur in
|
||||
:)
|
||||
_arguments '*: :(::ytfavorites ::ytrecommended ::ytsubscriptions ::ytwatchlater ::ythistory)'
|
||||
typeset -A opt_args
|
||||
_arguments -S -s \
|
||||
{{flags}} \
|
||||
'*:URL:_urls'
|
||||
|
||||
case $state in
|
||||
external-downloader-args)
|
||||
case "${opt_args[--external-downloader]}" in
|
||||
curl) _curl
|
||||
;;
|
||||
*)
|
||||
prev=$words[CURRENT-1]
|
||||
if [[ ${prev} =~ ${fileopts} ]]; then
|
||||
_path_files
|
||||
elif [[ ${prev} =~ ${diropts} ]]; then
|
||||
_path_files -/
|
||||
elif [[ ${prev} == "--recode-video" ]]; then
|
||||
_arguments '*: :(mp4 flv ogg webm mkv)'
|
||||
else
|
||||
_arguments '*: :({{flags}})'
|
||||
fi
|
||||
ffmpeg) _ffmpeg
|
||||
;;
|
||||
httpie) _httpie
|
||||
;;
|
||||
wget) _wget
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__youtube_dl
|
||||
;;
|
||||
esac
|
||||
|
@ -1,49 +1,203 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
"""Generate zsh completion script.
|
||||
|
||||
Usage
|
||||
-----
|
||||
.. code-block:: zsh
|
||||
devscripts/zsh-completion.py
|
||||
sudo mv youtube-dl.zsh /usr/share/zsh/site-functions/_youtube-dl
|
||||
rm -f ~/.zcompdump # optional
|
||||
compinit # regenerate ~/.zcompdump
|
||||
|
||||
Debug
|
||||
-----
|
||||
.. code-block:: zsh
|
||||
devscripts/zsh-completion.py MODULE_NAME - # will output to stdout
|
||||
|
||||
Refer
|
||||
-----
|
||||
- https://github.com/ytdl-org/youtube-dl/blob/master/devscripts/zsh-completion.py
|
||||
- https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code-block::
|
||||
'(- *)'{-h,--help}'[show this help message and exit]'
|
||||
|<-1->||<---2--->||<---------------3--------------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo --<TAB>
|
||||
option
|
||||
--help show this help message and exit
|
||||
% foo --help <TAB>
|
||||
no more arguments
|
||||
|
||||
.. code-block::
|
||||
--color'[When to show color. Default: auto. Support: auto, always, never]:when:(auto always never)'
|
||||
|<-2->||<------------------------------3------------------------------->||<4>||<--------5-------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo --color <TAB>
|
||||
when
|
||||
always
|
||||
auto
|
||||
never
|
||||
|
||||
.. code-block::
|
||||
--color'[When to show color. Default: auto. Support: auto, always, never]:when:((auto\:"only when output is stdout" always\:always never\:never))'
|
||||
|<-2->||<------------------------------3------------------------------->||<4>||<--------------------------------5------------------------------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo --color <TAB>
|
||||
when
|
||||
always always
|
||||
auto only when output is stdout
|
||||
never never
|
||||
|
||||
.. code-block::
|
||||
--config='[Config file. Default: ~/.config/foo/foo.toml]:config file:_files -g *.toml'
|
||||
|<--2-->||<---------------------3--------------------->||<---4---->||<------5------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo --config <TAB>
|
||||
config file
|
||||
a.toml b/ ...
|
||||
...
|
||||
|
||||
.. code-block::
|
||||
{1,2}'::_command_names -e'
|
||||
|<2->|4|<-------5------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo help<TAB>
|
||||
_command_names -e
|
||||
help2man generate a simple manual page
|
||||
helpviewer
|
||||
...
|
||||
% foo hello hello <TAB>
|
||||
no more arguments
|
||||
|
||||
.. code-block::
|
||||
'*: :_command_names -e'
|
||||
2|4||<-------5------->|
|
||||
|
||||
.. code-block:: console
|
||||
% foo help<TAB>
|
||||
external command
|
||||
help2man generate a simple manual page
|
||||
helpviewer
|
||||
...
|
||||
% foo hello hello help<TAB>
|
||||
external command
|
||||
help2man generate a simple manual page
|
||||
helpviewer
|
||||
...
|
||||
|
||||
+----+------------+----------+------+
|
||||
| id | variable | required | expr |
|
||||
+====+============+==========+======+
|
||||
| 1 | prefix | F | (.*) |
|
||||
| 2 | optionstr | T | .* |
|
||||
| 3 | helpstr | F | [.*] |
|
||||
| 4 | metavar | F | :.* |
|
||||
| 5 | completion | F | :.* |
|
||||
+----+------------+----------+------+
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
from optparse import SUPPRESS_HELP
|
||||
import os
|
||||
from os.path import dirname as dirn
|
||||
import sys
|
||||
from typing import Final
|
||||
|
||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
||||
import youtube_dl
|
||||
from setuptools import find_packages
|
||||
|
||||
ZSH_COMPLETION_FILE = "youtube-dl.zsh"
|
||||
rootpath = dirn(dirn(os.path.abspath(__file__)))
|
||||
path = os.path.join(rootpath, "src")
|
||||
packages = find_packages(path)
|
||||
if packages == []:
|
||||
path = rootpath
|
||||
sys.path.insert(0, path)
|
||||
PACKAGE: Final = "youtube_dl" if sys.argv[1:2] == [] else sys.argv[1]
|
||||
parser = __import__(PACKAGE).parseOpts()[0]
|
||||
BINNAME: Final = PACKAGE.replace("_", "-")
|
||||
BINNAMES: Final = [BINNAME]
|
||||
ZSH_COMPLETION_FILE: Final = (
|
||||
"youtube-dl.zsh" if sys.argv[2:3] == [] else sys.argv[2]
|
||||
)
|
||||
ZSH_COMPLETION_TEMPLATE = "devscripts/zsh-completion.in"
|
||||
|
||||
opts = parser._get_all_options()
|
||||
|
||||
def build_completion(opt_parser):
|
||||
opts = [opt for group in opt_parser.option_groups
|
||||
for opt in group.option_list]
|
||||
opts_file = [opt for opt in opts if opt.metavar == "FILE"]
|
||||
opts_dir = [opt for opt in opts if opt.metavar == "DIR"]
|
||||
flags = []
|
||||
for opt in opts:
|
||||
optionstrs = opt._long_opts + opt._short_opts
|
||||
if len(optionstrs) == 1:
|
||||
optionstr = optionstrs[0]
|
||||
else:
|
||||
optionstr = "'{" + ",".join(optionstrs) + "}'"
|
||||
|
||||
fileopts = []
|
||||
for opt in opts_file:
|
||||
if opt._short_opts:
|
||||
fileopts.extend(opt._short_opts)
|
||||
if opt._long_opts:
|
||||
fileopts.extend(opt._long_opts)
|
||||
if opt.action in ["help", "version"]:
|
||||
prefix = "- *"
|
||||
else:
|
||||
prefix = " ".join(optionstrs)
|
||||
prefix = "'(" + prefix + ")"
|
||||
|
||||
diropts = []
|
||||
for opt in opts_dir:
|
||||
if opt._short_opts:
|
||||
diropts.extend(opt._short_opts)
|
||||
if opt._long_opts:
|
||||
diropts.extend(opt._long_opts)
|
||||
if opt.help == SUPPRESS_HELP:
|
||||
helpstr = ""
|
||||
else:
|
||||
helpstr = opt.help.replace("'", "'\\''").replace("]", "\\]")
|
||||
helpstr = "[" + helpstr + "]"
|
||||
|
||||
flags = [opt.get_opt_string() for opt in opts]
|
||||
if isinstance(opt.metavar, str):
|
||||
metavar = opt.metavar
|
||||
elif optionstr == "--external-downloader-args":
|
||||
metavar = " " # use default
|
||||
else: # opt.metavar is None
|
||||
metavar = ""
|
||||
if metavar != "":
|
||||
# use lowcase conventionally
|
||||
metavar = metavar.lower().replace(":", "\\:")
|
||||
|
||||
with open(ZSH_COMPLETION_TEMPLATE) as f:
|
||||
template = f.read()
|
||||
if opt.choices:
|
||||
completion = "(" + " ".join(opt.choices) + ")"
|
||||
elif optionstr == "--external-downloader-args":
|
||||
completion = "->external-downloader-args"
|
||||
elif metavar == "file":
|
||||
completion = "_files"
|
||||
metavar = " "
|
||||
elif metavar == "dir":
|
||||
completion = "_dirs"
|
||||
metavar = " "
|
||||
elif metavar == "url":
|
||||
completion = "_urls"
|
||||
metavar = " "
|
||||
elif metavar == "command":
|
||||
completion = "_command_names -e"
|
||||
metavar = " "
|
||||
else:
|
||||
completion = ""
|
||||
|
||||
template = template.replace("{{fileopts}}", "|".join(fileopts))
|
||||
template = template.replace("{{diropts}}", "|".join(diropts))
|
||||
template = template.replace("{{flags}}", " ".join(flags))
|
||||
if metavar != "":
|
||||
metavar = ":" + metavar
|
||||
if completion != "":
|
||||
completion = ":" + completion
|
||||
|
||||
with open(ZSH_COMPLETION_FILE, "w") as f:
|
||||
f.write(template)
|
||||
flag = "{0}{1}{2}{3}{4}'".format(
|
||||
prefix, optionstr, helpstr, metavar, completion
|
||||
)
|
||||
|
||||
flags += [flag]
|
||||
|
||||
parser = youtube_dl.parseOpts()[0]
|
||||
build_completion(parser)
|
||||
with open(ZSH_COMPLETION_TEMPLATE) as f:
|
||||
template = f.read()
|
||||
|
||||
template = template.replace("{{programs}}", " ".join(BINNAMES))
|
||||
template = template.replace("{{flags}}", " \\\n ".join(flags))
|
||||
|
||||
with (
|
||||
open(ZSH_COMPLETION_FILE, "w")
|
||||
if ZSH_COMPLETION_FILE != "-"
|
||||
else sys.stdout
|
||||
) as f:
|
||||
f.write(template)
|
||||
|
@ -178,7 +178,7 @@ def parseOpts(overrideArguments=None):
|
||||
'(%APPDATA%/youtube-dl/config.txt on Windows)')
|
||||
general.add_option(
|
||||
'--config-location',
|
||||
dest='config_location', metavar='PATH',
|
||||
dest='config_location', metavar='FILE',
|
||||
help='Location of the configuration file; either the path to the config or its containing directory.')
|
||||
general.add_option(
|
||||
'--flat-playlist',
|
||||
@ -414,13 +414,15 @@ def parseOpts(overrideArguments=None):
|
||||
'--youtube-skip-dash-manifest',
|
||||
action='store_false', dest='youtube_include_dash_manifest',
|
||||
help='Do not download the DASH manifests and related data on YouTube videos')
|
||||
choices = ['mkv', 'mp4', 'ogg', 'webm', 'flv']
|
||||
video_format.add_option(
|
||||
'--merge-output-format',
|
||||
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
|
||||
choices=choices,
|
||||
help=(
|
||||
'If a merge is required (e.g. bestvideo+bestaudio), '
|
||||
'output to given container format. One of mkv, mp4, ogg, webm, flv. '
|
||||
'Ignored if no merge is required'))
|
||||
'output to given container format. (currently supported: {0})'
|
||||
'Ignored if no merge is required'.format(' '.join(choices))))
|
||||
|
||||
subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
|
||||
subtitles.add_option(
|
||||
@ -519,8 +521,9 @@ def parseOpts(overrideArguments=None):
|
||||
downloader.add_option(
|
||||
'--external-downloader',
|
||||
dest='external_downloader', metavar='COMMAND',
|
||||
choices=list_external_downloaders(),
|
||||
help='Use the specified external downloader. '
|
||||
'Currently supports %s' % ','.join(list_external_downloaders()))
|
||||
'(currently supported: %s)' % ' '.join(list_external_downloaders()))
|
||||
downloader.add_option(
|
||||
'--external-downloader-args',
|
||||
dest='external_downloader_args', metavar='ARGS',
|
||||
@ -787,17 +790,22 @@ def parseOpts(overrideArguments=None):
|
||||
'-x', '--extract-audio',
|
||||
action='store_true', dest='extractaudio', default=False,
|
||||
help='Convert video files to audio-only files (requires ffmpeg/avconv and ffprobe/avprobe)')
|
||||
choices = ["best", "aac", "flac", "mp3", "m4a", "opus", "vorbis", "wav"]
|
||||
postproc.add_option(
|
||||
'--audio-format', metavar='FORMAT', dest='audioformat', default='best',
|
||||
help='Specify audio format: "best", "aac", "flac", "mp3", "m4a", "opus", "vorbis", or "wav"; "%default" by default; No effect without -x')
|
||||
choices=choices,
|
||||
help='Specify audio format. (currently supported: {0}); %default by default; No effect without -x'.format(" ".join(choices)))
|
||||
postproc.add_option(
|
||||
'--audio-quality', metavar='QUALITY',
|
||||
dest='audioquality', default='5',
|
||||
choices=list(map(str, range(10))),
|
||||
help='Specify ffmpeg/avconv audio quality, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default %default)')
|
||||
choices = ["mp4", "flv", "ogg", "webm", "mkv", "avi"]
|
||||
postproc.add_option(
|
||||
'--recode-video',
|
||||
metavar='FORMAT', dest='recodevideo', default=None,
|
||||
help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)')
|
||||
choices=choices,
|
||||
help='Encode the video to another format if necessary (currently supported: {0})'.format(" ".join(choices)))
|
||||
postproc.add_option(
|
||||
'--postprocessor-args',
|
||||
dest='postprocessor_args', metavar='ARGS',
|
||||
@ -858,10 +866,12 @@ def parseOpts(overrideArguments=None):
|
||||
'--exec',
|
||||
metavar='CMD', dest='exec_cmd',
|
||||
help='Execute a command on the file after downloading and post-processing, similar to find\'s -exec syntax. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'')
|
||||
choices = ["srt", "ass", "vtt", "lrc"]
|
||||
postproc.add_option(
|
||||
'--convert-subs', '--convert-subtitles',
|
||||
metavar='FORMAT', dest='convertsubtitles', default=None,
|
||||
help='Convert the subtitles to other format (currently supported: srt|ass|vtt|lrc)')
|
||||
choices=choices,
|
||||
help='Convert the subtitles to other format (currently supported: {0})'.format(" ".join(choices)))
|
||||
|
||||
parser.add_option_group(general)
|
||||
parser.add_option_group(network)
|
||||
|
Loading…
x
Reference in New Issue
Block a user