mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2024-11-14 17:40:24 -08:00
56c6773c6b
Updates colorama to 0.4.6 Adds confuse version 1.7.0 Updates jellyfish to 0.9.0 Adds mediafile 0.10.1 Updates munkres to 1.1.4 Updates musicbrainzngs to 0.7.1 Updates mutagen to 1.46.0 Updates pyyaml to 6.0 Updates unidecode to 1.3.6
286 lines
10 KiB
Python
286 lines
10 KiB
Python
# This file is part of beets.
|
|
# Copyright 2015, winters jean-marie.
|
|
# Copyright 2020, Justin Mayer <https://justinmayer.com>
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
|
|
"""This plugin generates tab completions for Beets commands for the Fish shell
|
|
<https://fishshell.com/>, including completions for Beets commands, plugin
|
|
commands, and option flags. Also generated are completions for all the album
|
|
and track fields, suggesting for example `genre:` or `album:` when querying the
|
|
Beets database. Completions for the *values* of those fields are not generated
|
|
by default but can be added via the `-e` / `--extravalues` flag. For example:
|
|
`beet fish -e genre -e albumartist`
|
|
"""
|
|
|
|
|
|
from beets.plugins import BeetsPlugin
|
|
from beets import library, ui
|
|
from beets.ui import commands
|
|
from operator import attrgetter
|
|
import os
|
|
BL_NEED2 = """complete -c beet -n '__fish_beet_needs_command' {} {}\n"""
|
|
BL_USE3 = """complete -c beet -n '__fish_beet_using_command {}' {} {}\n"""
|
|
BL_SUBS = """complete -c beet -n '__fish_at_level {} ""' {} {}\n"""
|
|
BL_EXTRA3 = """complete -c beet -n '__fish_beet_use_extra {}' {} {}\n"""
|
|
|
|
HEAD = '''
|
|
function __fish_beet_needs_command
|
|
set cmd (commandline -opc)
|
|
if test (count $cmd) -eq 1
|
|
return 0
|
|
end
|
|
return 1
|
|
end
|
|
|
|
function __fish_beet_using_command
|
|
set cmd (commandline -opc)
|
|
set needle (count $cmd)
|
|
if test $needle -gt 1
|
|
if begin test $argv[1] = $cmd[2];
|
|
and not contains -- $cmd[$needle] $FIELDS; end
|
|
return 0
|
|
end
|
|
end
|
|
return 1
|
|
end
|
|
|
|
function __fish_beet_use_extra
|
|
set cmd (commandline -opc)
|
|
set needle (count $cmd)
|
|
if test $argv[2] = $cmd[$needle]
|
|
return 0
|
|
end
|
|
return 1
|
|
end
|
|
'''
|
|
|
|
|
|
class FishPlugin(BeetsPlugin):
|
|
|
|
def commands(self):
|
|
cmd = ui.Subcommand('fish', help='generate Fish shell tab completions')
|
|
cmd.func = self.run
|
|
cmd.parser.add_option('-f', '--noFields', action='store_true',
|
|
default=False,
|
|
help='omit album/track field completions')
|
|
cmd.parser.add_option(
|
|
'-e',
|
|
'--extravalues',
|
|
action='append',
|
|
type='choice',
|
|
choices=library.Item.all_keys() +
|
|
library.Album.all_keys(),
|
|
help='include specified field *values* in completions')
|
|
return [cmd]
|
|
|
|
def run(self, lib, opts, args):
|
|
# Gather the commands from Beets core and its plugins.
|
|
# Collect the album and track fields.
|
|
# If specified, also collect the values for these fields.
|
|
# Make a giant string of all the above, formatted in a way that
|
|
# allows Fish to do tab completion for the `beet` command.
|
|
home_dir = os.path.expanduser("~")
|
|
completion_dir = os.path.join(home_dir, '.config/fish/completions')
|
|
try:
|
|
os.makedirs(completion_dir)
|
|
except OSError:
|
|
if not os.path.isdir(completion_dir):
|
|
raise
|
|
completion_file_path = os.path.join(completion_dir, 'beet.fish')
|
|
nobasicfields = opts.noFields # Do not complete for album/track fields
|
|
extravalues = opts.extravalues # e.g., Also complete artists names
|
|
beetcmds = sorted(
|
|
(commands.default_commands +
|
|
commands.plugins.commands()),
|
|
key=attrgetter('name'))
|
|
fields = sorted(set(
|
|
library.Album.all_keys() + library.Item.all_keys()))
|
|
# Collect commands, their aliases, and their help text
|
|
cmd_names_help = []
|
|
for cmd in beetcmds:
|
|
names = list(cmd.aliases)
|
|
names.append(cmd.name)
|
|
for name in names:
|
|
cmd_names_help.append((name, cmd.help))
|
|
# Concatenate the string
|
|
totstring = HEAD + "\n"
|
|
totstring += get_cmds_list([name[0] for name in cmd_names_help])
|
|
totstring += '' if nobasicfields else get_standard_fields(fields)
|
|
totstring += get_extravalues(lib, extravalues) if extravalues else ''
|
|
totstring += "\n" + "# ====== {} =====".format(
|
|
"setup basic beet completion") + "\n" * 2
|
|
totstring += get_basic_beet_options()
|
|
totstring += "\n" + "# ====== {} =====".format(
|
|
"setup field completion for subcommands") + "\n"
|
|
totstring += get_subcommands(
|
|
cmd_names_help, nobasicfields, extravalues)
|
|
# Set up completion for all the command options
|
|
totstring += get_all_commands(beetcmds)
|
|
|
|
with open(completion_file_path, 'w') as fish_file:
|
|
fish_file.write(totstring)
|
|
|
|
|
|
def _escape(name):
|
|
# Escape ? in fish
|
|
if name == "?":
|
|
name = "\\" + name
|
|
return name
|
|
|
|
|
|
def get_cmds_list(cmds_names):
|
|
# Make a list of all Beets core & plugin commands
|
|
substr = ''
|
|
substr += (
|
|
"set CMDS " + " ".join(cmds_names) + ("\n" * 2)
|
|
)
|
|
return substr
|
|
|
|
|
|
def get_standard_fields(fields):
|
|
# Make a list of album/track fields and append with ':'
|
|
fields = (field + ":" for field in fields)
|
|
substr = ''
|
|
substr += (
|
|
"set FIELDS " + " ".join(fields) + ("\n" * 2)
|
|
)
|
|
return substr
|
|
|
|
|
|
def get_extravalues(lib, extravalues):
|
|
# Make a list of all values from an album/track field.
|
|
# 'beet ls albumartist: <TAB>' yields completions for ABBA, Beatles, etc.
|
|
word = ''
|
|
values_set = get_set_of_values_for_field(lib, extravalues)
|
|
for fld in extravalues:
|
|
extraname = fld.upper() + 'S'
|
|
word += (
|
|
"set " + extraname + " " + " ".join(sorted(values_set[fld]))
|
|
+ ("\n" * 2)
|
|
)
|
|
return word
|
|
|
|
|
|
def get_set_of_values_for_field(lib, fields):
|
|
# Get unique values from a specified album/track field
|
|
fields_dict = {}
|
|
for each in fields:
|
|
fields_dict[each] = set()
|
|
for item in lib.items():
|
|
for field in fields:
|
|
fields_dict[field].add(wrap(item[field]))
|
|
return fields_dict
|
|
|
|
|
|
def get_basic_beet_options():
|
|
word = (
|
|
BL_NEED2.format("-l format-item",
|
|
"-f -d 'print with custom format'") +
|
|
BL_NEED2.format("-l format-album",
|
|
"-f -d 'print with custom format'") +
|
|
BL_NEED2.format("-s l -l library",
|
|
"-f -r -d 'library database file to use'") +
|
|
BL_NEED2.format("-s d -l directory",
|
|
"-f -r -d 'destination music directory'") +
|
|
BL_NEED2.format("-s v -l verbose",
|
|
"-f -d 'print debugging information'") +
|
|
|
|
BL_NEED2.format("-s c -l config",
|
|
"-f -r -d 'path to configuration file'") +
|
|
BL_NEED2.format("-s h -l help",
|
|
"-f -d 'print this help message and exit'"))
|
|
return word
|
|
|
|
|
|
def get_subcommands(cmd_name_and_help, nobasicfields, extravalues):
|
|
# Formatting for Fish to complete our fields/values
|
|
word = ""
|
|
for cmdname, cmdhelp in cmd_name_and_help:
|
|
cmdname = _escape(cmdname)
|
|
|
|
word += "\n" + "# ------ {} -------".format(
|
|
"fieldsetups for " + cmdname) + "\n"
|
|
word += (
|
|
BL_NEED2.format(
|
|
("-a " + cmdname),
|
|
("-f " + "-d " + wrap(clean_whitespace(cmdhelp)))))
|
|
|
|
if nobasicfields is False:
|
|
word += (
|
|
BL_USE3.format(
|
|
cmdname,
|
|
("-a " + wrap("$FIELDS")),
|
|
("-f " + "-d " + wrap("fieldname"))))
|
|
|
|
if extravalues:
|
|
for f in extravalues:
|
|
setvar = wrap("$" + f.upper() + "S")
|
|
word += " ".join(BL_EXTRA3.format(
|
|
(cmdname + " " + f + ":"),
|
|
('-f ' + '-A ' + '-a ' + setvar),
|
|
('-d ' + wrap(f))).split()) + "\n"
|
|
return word
|
|
|
|
|
|
def get_all_commands(beetcmds):
|
|
# Formatting for Fish to complete command options
|
|
word = ""
|
|
for cmd in beetcmds:
|
|
names = list(cmd.aliases)
|
|
names.append(cmd.name)
|
|
for name in names:
|
|
name = _escape(name)
|
|
|
|
word += "\n"
|
|
word += ("\n" * 2) + "# ====== {} =====".format(
|
|
"completions for " + name) + "\n"
|
|
|
|
for option in cmd.parser._get_all_options()[1:]:
|
|
cmd_l = (" -l " + option._long_opts[0].replace('--', '')
|
|
)if option._long_opts else ''
|
|
cmd_s = (" -s " + option._short_opts[0].replace('-', '')
|
|
) if option._short_opts else ''
|
|
cmd_need_arg = ' -r ' if option.nargs in [1] else ''
|
|
cmd_helpstr = (" -d " + wrap(' '.join(option.help.split()))
|
|
) if option.help else ''
|
|
cmd_arglist = (' -a ' + wrap(" ".join(option.choices))
|
|
) if option.choices else ''
|
|
|
|
word += " ".join(BL_USE3.format(
|
|
name,
|
|
(cmd_need_arg + cmd_s + cmd_l + " -f " + cmd_arglist),
|
|
cmd_helpstr).split()) + "\n"
|
|
|
|
word = (word + " ".join(BL_USE3.format(
|
|
name,
|
|
("-s " + "h " + "-l " + "help" + " -f "),
|
|
('-d ' + wrap("print help") + "\n")
|
|
).split()))
|
|
return word
|
|
|
|
|
|
def clean_whitespace(word):
|
|
# Remove excess whitespace and tabs in a string
|
|
return " ".join(word.split())
|
|
|
|
|
|
def wrap(word):
|
|
# Need " or ' around strings but watch out if they're in the string
|
|
sptoken = '\"'
|
|
if ('"') in word and ("'") in word:
|
|
word.replace('"', sptoken)
|
|
return '"' + word + '"'
|
|
|
|
tok = '"' if "'" in word else "'"
|
|
return tok + word + tok
|