mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-04-16 20:14: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() {
|
typeset -A opt_args
|
||||||
local curcontext="$curcontext" fileopts diropts cur prev
|
_arguments -S -s \
|
||||||
typeset -A opt_args
|
{{flags}} \
|
||||||
fileopts="{{fileopts}}"
|
'*:URL:_urls'
|
||||||
diropts="{{diropts}}"
|
|
||||||
cur=$words[CURRENT]
|
case $state in
|
||||||
case $cur in
|
external-downloader-args)
|
||||||
:)
|
case "${opt_args[--external-downloader]}" in
|
||||||
_arguments '*: :(::ytfavorites ::ytrecommended ::ytsubscriptions ::ytwatchlater ::ythistory)'
|
curl) _curl
|
||||||
;;
|
;;
|
||||||
*)
|
ffmpeg) _ffmpeg
|
||||||
prev=$words[CURRENT-1]
|
;;
|
||||||
if [[ ${prev} =~ ${fileopts} ]]; then
|
httpie) _httpie
|
||||||
_path_files
|
;;
|
||||||
elif [[ ${prev} =~ ${diropts} ]]; then
|
wget) _wget
|
||||||
_path_files -/
|
|
||||||
elif [[ ${prev} == "--recode-video" ]]; then
|
|
||||||
_arguments '*: :(mp4 flv ogg webm mkv)'
|
|
||||||
else
|
|
||||||
_arguments '*: :({{flags}})'
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
;;
|
||||||
|
esac
|
||||||
__youtube_dl
|
|
||||||
|
@ -1,49 +1,203 @@
|
|||||||
#!/usr/bin/env python
|
#!/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
|
import os
|
||||||
from os.path import dirname as dirn
|
from os.path import dirname as dirn
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
from setuptools import find_packages
|
||||||
import youtube_dl
|
|
||||||
|
|
||||||
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"
|
ZSH_COMPLETION_TEMPLATE = "devscripts/zsh-completion.in"
|
||||||
|
|
||||||
|
opts = parser._get_all_options()
|
||||||
|
|
||||||
def build_completion(opt_parser):
|
flags = []
|
||||||
opts = [opt for group in opt_parser.option_groups
|
for opt in opts:
|
||||||
for opt in group.option_list]
|
optionstrs = opt._long_opts + opt._short_opts
|
||||||
opts_file = [opt for opt in opts if opt.metavar == "FILE"]
|
if len(optionstrs) == 1:
|
||||||
opts_dir = [opt for opt in opts if opt.metavar == "DIR"]
|
optionstr = optionstrs[0]
|
||||||
|
else:
|
||||||
|
optionstr = "'{" + ",".join(optionstrs) + "}'"
|
||||||
|
|
||||||
fileopts = []
|
if opt.action in ["help", "version"]:
|
||||||
for opt in opts_file:
|
prefix = "- *"
|
||||||
if opt._short_opts:
|
else:
|
||||||
fileopts.extend(opt._short_opts)
|
prefix = " ".join(optionstrs)
|
||||||
if opt._long_opts:
|
prefix = "'(" + prefix + ")"
|
||||||
fileopts.extend(opt._long_opts)
|
|
||||||
|
|
||||||
diropts = []
|
if opt.help == SUPPRESS_HELP:
|
||||||
for opt in opts_dir:
|
helpstr = ""
|
||||||
if opt._short_opts:
|
else:
|
||||||
diropts.extend(opt._short_opts)
|
helpstr = opt.help.replace("'", "'\\''").replace("]", "\\]")
|
||||||
if opt._long_opts:
|
helpstr = "[" + helpstr + "]"
|
||||||
diropts.extend(opt._long_opts)
|
|
||||||
|
|
||||||
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:
|
if opt.choices:
|
||||||
template = f.read()
|
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))
|
if metavar != "":
|
||||||
template = template.replace("{{diropts}}", "|".join(diropts))
|
metavar = ":" + metavar
|
||||||
template = template.replace("{{flags}}", " ".join(flags))
|
if completion != "":
|
||||||
|
completion = ":" + completion
|
||||||
|
|
||||||
with open(ZSH_COMPLETION_FILE, "w") as f:
|
flag = "{0}{1}{2}{3}{4}'".format(
|
||||||
f.write(template)
|
prefix, optionstr, helpstr, metavar, completion
|
||||||
|
)
|
||||||
|
|
||||||
|
flags += [flag]
|
||||||
|
|
||||||
parser = youtube_dl.parseOpts()[0]
|
with open(ZSH_COMPLETION_TEMPLATE) as f:
|
||||||
build_completion(parser)
|
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)')
|
'(%APPDATA%/youtube-dl/config.txt on Windows)')
|
||||||
general.add_option(
|
general.add_option(
|
||||||
'--config-location',
|
'--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.')
|
help='Location of the configuration file; either the path to the config or its containing directory.')
|
||||||
general.add_option(
|
general.add_option(
|
||||||
'--flat-playlist',
|
'--flat-playlist',
|
||||||
@ -414,13 +414,15 @@ def parseOpts(overrideArguments=None):
|
|||||||
'--youtube-skip-dash-manifest',
|
'--youtube-skip-dash-manifest',
|
||||||
action='store_false', dest='youtube_include_dash_manifest',
|
action='store_false', dest='youtube_include_dash_manifest',
|
||||||
help='Do not download the DASH manifests and related data on YouTube videos')
|
help='Do not download the DASH manifests and related data on YouTube videos')
|
||||||
|
choices = ['mkv', 'mp4', 'ogg', 'webm', 'flv']
|
||||||
video_format.add_option(
|
video_format.add_option(
|
||||||
'--merge-output-format',
|
'--merge-output-format',
|
||||||
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
|
action='store', dest='merge_output_format', metavar='FORMAT', default=None,
|
||||||
|
choices=choices,
|
||||||
help=(
|
help=(
|
||||||
'If a merge is required (e.g. bestvideo+bestaudio), '
|
'If a merge is required (e.g. bestvideo+bestaudio), '
|
||||||
'output to given container format. One of mkv, mp4, ogg, webm, flv. '
|
'output to given container format. (currently supported: {0})'
|
||||||
'Ignored if no merge is required'))
|
'Ignored if no merge is required'.format(' '.join(choices))))
|
||||||
|
|
||||||
subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
|
subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
|
||||||
subtitles.add_option(
|
subtitles.add_option(
|
||||||
@ -519,8 +521,9 @@ def parseOpts(overrideArguments=None):
|
|||||||
downloader.add_option(
|
downloader.add_option(
|
||||||
'--external-downloader',
|
'--external-downloader',
|
||||||
dest='external_downloader', metavar='COMMAND',
|
dest='external_downloader', metavar='COMMAND',
|
||||||
|
choices=list_external_downloaders(),
|
||||||
help='Use the specified external downloader. '
|
help='Use the specified external downloader. '
|
||||||
'Currently supports %s' % ','.join(list_external_downloaders()))
|
'(currently supported: %s)' % ' '.join(list_external_downloaders()))
|
||||||
downloader.add_option(
|
downloader.add_option(
|
||||||
'--external-downloader-args',
|
'--external-downloader-args',
|
||||||
dest='external_downloader_args', metavar='ARGS',
|
dest='external_downloader_args', metavar='ARGS',
|
||||||
@ -787,17 +790,22 @@ def parseOpts(overrideArguments=None):
|
|||||||
'-x', '--extract-audio',
|
'-x', '--extract-audio',
|
||||||
action='store_true', dest='extractaudio', default=False,
|
action='store_true', dest='extractaudio', default=False,
|
||||||
help='Convert video files to audio-only files (requires ffmpeg/avconv and ffprobe/avprobe)')
|
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(
|
postproc.add_option(
|
||||||
'--audio-format', metavar='FORMAT', dest='audioformat', default='best',
|
'--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(
|
postproc.add_option(
|
||||||
'--audio-quality', metavar='QUALITY',
|
'--audio-quality', metavar='QUALITY',
|
||||||
dest='audioquality', default='5',
|
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)')
|
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(
|
postproc.add_option(
|
||||||
'--recode-video',
|
'--recode-video',
|
||||||
metavar='FORMAT', dest='recodevideo', default=None,
|
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(
|
postproc.add_option(
|
||||||
'--postprocessor-args',
|
'--postprocessor-args',
|
||||||
dest='postprocessor_args', metavar='ARGS',
|
dest='postprocessor_args', metavar='ARGS',
|
||||||
@ -858,10 +866,12 @@ def parseOpts(overrideArguments=None):
|
|||||||
'--exec',
|
'--exec',
|
||||||
metavar='CMD', dest='exec_cmd',
|
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 {}\'')
|
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(
|
postproc.add_option(
|
||||||
'--convert-subs', '--convert-subtitles',
|
'--convert-subs', '--convert-subtitles',
|
||||||
metavar='FORMAT', dest='convertsubtitles', default=None,
|
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(general)
|
||||||
parser.add_option_group(network)
|
parser.add_option_group(network)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user