Nil Admirari 2 weeks ago committed by GitHub
commit e0dbf8dbd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,33 +1,84 @@
__yt_dlp()
{
local cur prev opts fileopts diropts keywords
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="{{flags}}"
keywords=":ytfavorites :ytrecommended :ytsubscriptions :ytwatchlater :ythistory"
fileopts="-a|--batch-file|--download-archive|--cookies|--load-info-json"
diropts="--cache-dir"
_comp_cmd_yt-dlp() {
# Not using "$2" and "$3" to partially workaround YouTube keyword completions.
local have_bashcomp=0 cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD - 1]}"
if [[ ${prev} =~ ${fileopts} ]]; then
local IFS=$'\n'
type compopt &>/dev/null && compopt -o filenames
COMPREPLY=( $(compgen -f -- ${cur}) )
return 0
elif [[ ${prev} =~ ${diropts} ]]; then
local IFS=$'\n'
type compopt &>/dev/null && compopt -o dirnames
COMPREPLY=( $(compgen -d -- ${cur}) )
return 0
# Long options with equals and YouTube keyword completions
# do not work without bash-completion.
if declare -F _comp_initialize &> /dev/null; then
have_bashcomp=1
# Unused variables assigned by _comp_initialize.
# shellcheck disable=SC2034
local words cword comp_args was_split
# ':' must be excluded from COMP_WORDBREAKS to handle :yt* keywords
_comp_initialize -n : -s -- "$@" || return
fi
if [[ ${cur} =~ : ]]; then
COMPREPLY=( $(compgen -W "${keywords}" -- ${cur}) )
return 0
elif [[ ${cur} == * ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
local filedir_action
case "$prev" in
YT_DLP_FILE_OPTS_CASE )
filedir_action='file'
;;
YT_DLP_DIR_OPTS_CASE )
filedir_action='directory'
;;
* )
;;
esac
local compreply_lines
if [[ "$filedir_action" ]]; then
if (( "$have_bashcomp" )); then
if [[ "$filedir_action" = directory ]]; then
_comp_compgen_filedir -d
else
_comp_compgen_filedir
fi
else
# macOS Bash does not have compopt.
if type compopt &>/dev/null; then
compopt -o filenames
fi
compreply_lines="$(compgen -A "$filedir_action" -- "$cur")"
fi
elif [[ "$cur" = :* ]]; then
# Adding keywords one by one since macOS Bash
# can't initialise a local array from brace expansions.
local k keywords
for k in :ytnotif{,ication}{,s} \
:ytfav{,o{,u}rite}{,s} \
:ytwatchlater \
:ytrec{,ommended} \
:ytsub{,scription}{,s} \
:ythis{,tory}; do
keywords+=("$k")
done
if (( "$have_bashcomp" )); then
_comp_compgen -- -W "${keywords[*]}"
_comp_ltrim_colon_completions "$cur"
else
compreply_lines="$(compgen -W "${keywords[*]}" -- "$cur")"
compreply_lines="${compreply_lines//:/}"
fi
else
local -r opts=( YT_DLP_OPTS_ARRAY )
if type compopt &> /dev/null; then
compopt -o nosort
fi
if (( "$have_bashcomp" )); then
_comp_compgen -- -W "${opts[*]}"
else
compreply_lines="$(compgen -W "${opts[*]}" -- "$cur")"
fi
fi
}
complete -F __yt_dlp yt-dlp
if [[ "$have_bashcomp" != 1 && "$compreply_lines" ]]; then
COMPREPLY=()
local line
while IFS='' read -r line; do
COMPREPLY+=("$line")
done <<< "$compreply_lines"
fi
} \
&& complete -F _comp_cmd_yt-dlp yt-dlp

@ -8,23 +8,24 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import yt_dlp
from devscripts.utils import gather_completion_opts
BASH_COMPLETION_FILE = 'completions/bash/yt-dlp'
BASH_COMPLETION_TEMPLATE = 'devscripts/bash-completion.in'
def build_completion(opt_parser):
opts_flag = []
for group in opt_parser.option_groups:
for option in group.option_list:
# for every long flag
opts_flag.append(option.get_opt_string())
opts = gather_completion_opts(opt_parser)
with open(BASH_COMPLETION_TEMPLATE) as f:
template = f.read()
template = template.replace('YT_DLP_FILE_OPTS_CASE', ' | '.join(opts.file_opts))
template = template.replace('YT_DLP_DIR_OPTS_CASE', ' | '.join(opts.dir_opts))
template = template.replace('YT_DLP_OPTS_ARRAY', ' '.join(opts.opts))
with open(BASH_COMPLETION_FILE, 'w') as f:
# just using the special char
filled_template = template.replace('{{flags}}', ' '.join(opts_flag))
f.write(filled_template)
f.write(template)
parser = yt_dlp.parseOpts(ignore_config_files=True)[0]

@ -2,7 +2,9 @@ import argparse
import datetime as dt
import functools
import re
import shlex
import subprocess
from dataclasses import dataclass
def read_file(fname):
@ -64,3 +66,36 @@ def run_process(*args, **kwargs):
kwargs.setdefault('encoding', 'utf-8')
kwargs.setdefault('errors', 'replace')
return subprocess.run(args, **kwargs)
@dataclass
class YtDlpCompletionOpts:
opts: tuple[str, ...]
file_opts: tuple[str, ...]
dir_opts: tuple[str, ...]
def gather_completion_opts(yt_dlp_opt_parser):
opts, long_opts = [], []
file_opts, dir_opts = [], []
for opt in yt_dlp_opt_parser._get_all_options():
opts.extend(opt._short_opts)
long_opts.extend(opt._long_opts)
if opt.metavar in {'FILE', 'PATH', 'CERTFILE', 'KEYFILE'}:
file_opts.extend(opt._short_opts)
file_opts.extend(opt._long_opts)
elif opt.metavar == 'DIR':
dir_opts.extend(opt._short_opts)
dir_opts.extend(opt._long_opts)
opts.sort()
long_opts.sort()
opts.extend(long_opts)
# Escape after sorting.
return YtDlpCompletionOpts(
tuple(shlex.quote(o) for o in opts),
tuple(shlex.quote(o) for o in file_opts),
tuple(shlex.quote(o) for o in dir_opts),
)

@ -8,46 +8,21 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import yt_dlp
from devscripts.utils import gather_completion_opts
ZSH_COMPLETION_FILE = 'completions/zsh/_yt-dlp'
ZSH_COMPLETION_TEMPLATE = 'devscripts/zsh-completion.in'
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']
opts_path = [opt for opt in opts if opt.metavar == 'PATH']
fileopts = []
for opt in opts_file:
if opt._short_opts:
fileopts.extend(opt._short_opts)
if opt._long_opts:
fileopts.extend(opt._long_opts)
for opt in opts_path:
if opt._short_opts:
fileopts.extend(opt._short_opts)
if opt._long_opts:
fileopts.extend(opt._long_opts)
diropts = []
for opt in opts_dir:
if opt._short_opts:
diropts.extend(opt._short_opts)
if opt._long_opts:
diropts.extend(opt._long_opts)
flags = [opt.get_opt_string() for opt in opts]
opts = gather_completion_opts(opt_parser)
with open(ZSH_COMPLETION_TEMPLATE) as f:
template = f.read()
template = template.replace('{{fileopts}}', '|'.join(fileopts))
template = template.replace('{{diropts}}', '|'.join(diropts))
template = template.replace('{{flags}}', ' '.join(flags))
template = template.replace('{{fileopts}}', '|'.join(opts.file_opts))
template = template.replace('{{diropts}}', '|'.join(opts.dir_opts))
template = template.replace('{{flags}}', ' '.join(opts.opts))
with open(ZSH_COMPLETION_FILE, 'w') as f:
f.write(template)

@ -1535,7 +1535,7 @@ def create_parser():
help='Netscape formatted file to read cookies from and dump cookie jar in')
filesystem.add_option(
'--no-cookies',
action='store_const', const=None, dest='cookiefile', metavar='FILE',
action='store_const', const=None, dest='cookiefile',
help='Do not read/dump cookies from/to file (default)')
filesystem.add_option(
'--cookies-from-browser',

Loading…
Cancel
Save