diff --git a/colorschemes/_theme.py b/colorschemes/_theme.py index 644f440..a467d1e 100644 --- a/colorschemes/_theme.py +++ b/colorschemes/_theme.py @@ -4,22 +4,22 @@ base16_name = "eighties" name = "base16-" + base16_name base16_colors = [ - "#2d2d2d", # 0 - "#393939", # 1 - "#515151", # 2 - "#747369", # 3 - "#a09f93", # 4 - "#d3d0c8", # 5 - "#e8e6df", # 6 - "#f2f0ec", # 7 - "#f2777a", # 8 - "#f99157", # 9 - "#ffcc66", # a - "#99cc99", # b - "#66cccc", # c - "#6699cc", # d - "#cc99cc", # e - "#d27b53", # f + "#2d2d2d", # 0 + "#393939", # 1 + "#515151", # 2 + "#747369", # 3 + "#a09f93", # 4 + "#d3d0c8", # 5 + "#e8e6df", # 6 + "#f2f0ec", # 7 + "#f2777a", # 8 + "#f99157", # 9 + "#ffcc66", # a + "#99cc99", # b + "#66cccc", # c + "#6699cc", # d + "#cc99cc", # e + "#d27b53", # f ] bg = base16_colors[0x0] @@ -32,18 +32,19 @@ selection_bg = base16_colors[0x2] selection_fg = fg ansi_colors = [ - base16_colors[int(i, 16)] for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split() + base16_colors[int(i, 16)] + for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split() ] link_color = ansi_colors[0xC] css_variables_prefix = "dotfiles-colorscheme-" css_variables = { - "bg": bg, - "fg": fg, - "selection-bg": selection_bg, - "selection-fg": selection_fg, - "cursor-bg": cursor_bg, - "cursor-fg": cursor_fg, - **{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)}, + "bg": bg, + "fg": fg, + "selection-bg": selection_bg, + "selection-fg": selection_fg, + "cursor-bg": cursor_bg, + "cursor-fg": cursor_fg, + **{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)}, } diff --git a/colorschemes/iterm.itermcolors.py b/colorschemes/iterm.itermcolors.py index 8cd59e5..5594ff5 100755 --- a/colorschemes/iterm.itermcolors.py +++ b/colorschemes/iterm.itermcolors.py @@ -2,9 +2,8 @@ import _theme as theme - print( - """\ + """\ @@ -14,9 +13,9 @@ print( def print_color(key_name, color): - r, g, b = [float(int(color[2 * i + 1:2 * i + 3], 16)) / 255 for i in range(3)] - print( - """\ + r, g, b = [float(int(color[2 * i + 1 : 2 * i + 3], 16)) / 255 for i in range(3)] + print( + """\ {} Color Color Space @@ -28,8 +27,10 @@ def print_color(key_name, color): Blue Component {} \ -""".format(key_name, r, g, b) - ) +""".format( + key_name, r, g, b + ) + ) print_color("Background", theme.bg) @@ -40,10 +41,12 @@ print_color("Cursor Text", theme.cursor_fg) print_color("Selection Color", theme.selection_bg) print_color("Selected Text Color", theme.selection_fg) for index, color in enumerate(theme.ansi_colors[:16]): - print_color("Ansi " + str(index), color) + print_color("Ansi " + str(index), color) print_color("Link", theme.link_color) -print("""\ +print( + """\ \ -""") +""" +) diff --git a/colorschemes/kitty.conf.py b/colorschemes/kitty.conf.py index 81544aa..a82df90 100755 --- a/colorschemes/kitty.conf.py +++ b/colorschemes/kitty.conf.py @@ -4,7 +4,7 @@ import _theme as theme def print_color(key_name, color): - print("{} {}".format(key_name, color)) + print("{} {}".format(key_name, color)) print_color("background", theme.bg) @@ -14,7 +14,7 @@ print_color("cursor_text_color", theme.cursor_fg) print_color("selection_background", theme.selection_bg) print_color("selection_foreground", theme.selection_fg) for index, color in enumerate(theme.ansi_colors[:16]): - print_color("color" + str(index), color) + print_color("color" + str(index), color) print_color("url_color", theme.link_color) print_color("active_border_color", theme.ansi_colors[2]) diff --git a/colorschemes/prismjs-theme.css.py b/colorschemes/prismjs-theme.css.py index 924f81d..42b62b8 100755 --- a/colorschemes/prismjs-theme.css.py +++ b/colorschemes/prismjs-theme.css.py @@ -4,9 +4,11 @@ import _theme as theme import os with open(os.path.join(os.path.dirname(__file__), "prismjs-theme-src.css")) as f: - css_src = f.read() + css_src = f.read() for var_name, color in theme.css_variables.items(): - css_src = css_src.replace("var(--{}{})".format(theme.css_variables_prefix, var_name), color) + css_src = css_src.replace( + "var(--{}{})".format(theme.css_variables_prefix, var_name), color + ) print(css_src) diff --git a/colorschemes/setvtrgb.txt.py b/colorschemes/setvtrgb.txt.py index 9dfb27f..8a8f117 100755 --- a/colorschemes/setvtrgb.txt.py +++ b/colorschemes/setvtrgb.txt.py @@ -8,4 +8,11 @@ import _theme as theme # 0,0,0,0,170,170,170,170,85,85,85,85,255,255,255,255 for i in range(3): - print(",".join([str(int(color[2 * i + 1:2 * i + 3], 16)) for color in theme.ansi_colors[:16]])) + print( + ",".join( + [ + str(int(color[2 * i + 1 : 2 * i + 3], 16)) + for color in theme.ansi_colors[:16] + ] + ) + ) diff --git a/colorschemes/termux.properties.py b/colorschemes/termux.properties.py index e6843ff..164df7a 100755 --- a/colorschemes/termux.properties.py +++ b/colorschemes/termux.properties.py @@ -4,11 +4,11 @@ import _theme as theme def print_color(key_name, color): - print("{}={}".format(key_name, color)) + print("{}={}".format(key_name, color)) print_color("background", theme.bg) print_color("foreground", theme.fg) print_color("cursor", theme.cursor_bg) for index, color in enumerate(theme.ansi_colors[:16]): - print_color("color" + str(index), color) + print_color("color" + str(index), color) diff --git a/colorschemes/variables.css.py b/colorschemes/variables.css.py index 2338a6f..64c4609 100755 --- a/colorschemes/variables.css.py +++ b/colorschemes/variables.css.py @@ -2,8 +2,7 @@ import _theme as theme - print(":root {") for var_name, color in theme.css_variables.items(): - print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color)) + print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color)) print("}") diff --git a/colorschemes/vim.vim.py b/colorschemes/vim.vim.py index 38dfed0..bba2493 100755 --- a/colorschemes/vim.vim.py +++ b/colorschemes/vim.vim.py @@ -2,21 +2,20 @@ import _theme as theme - print("let dotfiles_colorscheme_name = '{}'".format(theme.name)) print("let dotfiles_colorscheme_base16_name = '{}'".format(theme.base16_name)) print("let dotfiles_colorscheme_base16_colors = [") gui_to_cterm_mapping = [0, 18, 19, 8, 20, 7, 21, 15, 1, 16, 3, 2, 6, 4, 5, 17] for colors_pair in zip(theme.base16_colors[:16], gui_to_cterm_mapping): - print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair)) + print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair)) print("\\ ]") def print_terminal_color(key_name, color): - print("let terminal_color_{} = '{}'".format(key_name, color)) + print("let terminal_color_{} = '{}'".format(key_name, color)) print_terminal_color("background", theme.bg) print_terminal_color("foreground", theme.fg) for index, color in enumerate(theme.ansi_colors[:16]): - print_terminal_color(str(index), color) + print_terminal_color(str(index), color) diff --git a/colorschemes/vscode-colorCustomizations.json.py b/colorschemes/vscode-colorCustomizations.json.py index ed1b1dc..d139834 100755 --- a/colorschemes/vscode-colorCustomizations.json.py +++ b/colorschemes/vscode-colorCustomizations.json.py @@ -5,27 +5,31 @@ import json ANSI_COLOR_NAMES = [ - "Black", - "Red", - "Green", - "Yellow", - "Blue", - "Magenta", - "Cyan", - "White", + "Black", + "Red", + "Green", + "Yellow", + "Blue", + "Magenta", + "Cyan", + "White", ] colors = { - "terminal.background": theme.bg, - "terminal.foreground": theme.fg, - "terminal.selectionBackground": theme.selection_bg, - "terminalCursor.background": theme.cursor_fg, - "terminalCursor.foreground": theme.cursor_bg, + "terminal.background": theme.bg, + "terminal.foreground": theme.fg, + "terminal.selectionBackground": theme.selection_bg, + "terminalCursor.background": theme.cursor_fg, + "terminalCursor.foreground": theme.cursor_bg, } for color_brightness in [False, True]: - for color_index, color_name in enumerate(ANSI_COLOR_NAMES): - color = theme.ansi_colors[color_index + int(color_brightness) * len(ANSI_COLOR_NAMES)] - colors["terminal.ansi" + ("Bright" if color_brightness else "") + color_name] = color + for color_index, color_name in enumerate(ANSI_COLOR_NAMES): + color = theme.ansi_colors[ + color_index + int(color_brightness) * len(ANSI_COLOR_NAMES) + ] + colors[ + "terminal.ansi" + ("Bright" if color_brightness else "") + color_name + ] = color print(json.dumps(colors, ensure_ascii=False, indent=2)) diff --git a/colorschemes/xfce4-terminal.theme.py b/colorschemes/xfce4-terminal.theme.py index 3b5f71e..5775160 100755 --- a/colorschemes/xfce4-terminal.theme.py +++ b/colorschemes/xfce4-terminal.theme.py @@ -2,7 +2,6 @@ import _theme as theme - print("[Scheme]") print("Name=dmitmel's dotfiles colorscheme") print("ColorForeground={}".format(theme.fg)) diff --git a/colorschemes/zsh.zsh.py b/colorschemes/zsh.zsh.py index 5a32295..96c73af 100755 --- a/colorschemes/zsh.zsh.py +++ b/colorschemes/zsh.zsh.py @@ -2,18 +2,19 @@ import _theme as theme + for attr in [ - "bg", - "fg", - "cursor_bg", - "cursor_fg", - "selection_bg", - "selection_fg", - "link_color", + "bg", + "fg", + "cursor_bg", + "cursor_fg", + "selection_bg", + "selection_fg", + "link_color", ]: - color = getattr(theme, attr) - print("colorscheme_{}={}".format(attr, color[1:])) + color = getattr(theme, attr) + print("colorscheme_{}={}".format(attr, color[1:])) print("colorscheme_ansi_colors=(") for color in theme.ansi_colors: - print(" {}".format(color[1:])) + print(" {}".format(color[1:])) print(")") diff --git a/nvim/coc-languages/python.vim b/nvim/coc-languages/python.vim index 20b80e1..ff6cd12 100644 --- a/nvim/coc-languages/python.vim +++ b/nvim/coc-languages/python.vim @@ -1,15 +1,12 @@ let g:coc_global_extensions += ['coc-pyright'] let g:coc_filetypes += ['python'] - +" let g:coc_user_config['pyls.plugins.pycodestyle.ignore'] = ['E501'] " let g:coc_user_config['python.autocomplete.showAdvancedMembers'] = v:false let g:coc_user_config['python'] = { -\ 'formatting': { -\ 'provider': 'yapf', -\ 'yapfArgs': ['--style=' . simplify(g:nvim_dotfiles_dir.'/../python/yapf.ini')] -\ }, +\ 'formatting': { 'provider': 'black' }, \ 'linting': { \ 'pylintEnabled': v:false, \ 'flake8Enabled': v:true, -\ 'flake8Args': ['--config=' . simplify(g:nvim_dotfiles_dir.'/../python/flake8.ini')], +\ 'flake8Args': ['--ignore', 'E501'], \ }, \ } diff --git a/python/flake8.ini b/python/flake8.ini deleted file mode 100644 index b0c0191..0000000 --- a/python/flake8.ini +++ /dev/null @@ -1,12 +0,0 @@ -[flake8] -ignore = - # Indent is not a multiple of 4 - E111 - # Indent is not a multiple of 4 for comments - E114 - # Indent for continuation lines is smaller than expected - E121 - # Import not at the top of the file - E402 - # Line too long - E501 diff --git a/python/yapf.ini b/python/yapf.ini deleted file mode 100644 index e4ceea7..0000000 --- a/python/yapf.ini +++ /dev/null @@ -1,9 +0,0 @@ -[style] -based_on_style = google -column_limit = 99 -indent_width = 2 -continuation_indent_width = 2 -blank_lines_between_top_level_imports_and_variables = 2 -dedent_closing_brackets = true -coalesce_brackets = true -spaces_around_power_operator = true diff --git a/script-resources/common_script_utils.py b/script-resources/common_script_utils.py index 239eb11..fa23b02 100644 --- a/script-resources/common_script_utils.py +++ b/script-resources/common_script_utils.py @@ -4,90 +4,95 @@ import subprocess from pathlib import Path from typing import Iterable, NoReturn + if os.name == "posix": - DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles" - DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles" + DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles" + DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles" def platform_not_supported_error() -> NoReturn: - raise Exception("platform '{}' is not supported!".format(sys.platform)) + raise Exception("platform '{}' is not supported!".format(sys.platform)) -def run_chooser(choices: Iterable[str], prompt: str = None, async_read: bool = False) -> int: - supports_result_index = True - if os.isatty(sys.stderr.fileno()): - process_args = [ - "fzf", - "--with-nth=2..", - "--height=50%", - "--reverse", - "--tiebreak=index", - ] - supports_result_index = False - elif sys.platform == "darwin": - process_args = ["choose", "-i"] - elif os.name == "posix": - process_args = ["rofi", "-dmenu", "-i", "-format", "i"] - if prompt is not None: - process_args += ["-p", prompt] - if async_read: - process_args += ["-async-pre-read", "0"] - else: - platform_not_supported_error() +def run_chooser( + choices: Iterable[str], prompt: str = None, async_read: bool = False +) -> int: + supports_result_index = True + if os.isatty(sys.stderr.fileno()): + process_args = [ + "fzf", + "--with-nth=2..", + "--height=50%", + "--reverse", + "--tiebreak=index", + ] + supports_result_index = False + elif sys.platform == "darwin": + process_args = ["choose", "-i"] + elif os.name == "posix": + process_args = ["rofi", "-dmenu", "-i", "-format", "i"] + if prompt is not None: + process_args += ["-p", prompt] + if async_read: + process_args += ["-async-pre-read", "0"] + else: + platform_not_supported_error() - chooser_process = subprocess.Popen(process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + chooser_process = subprocess.Popen( + process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) - with chooser_process.stdin as pipe: - for index, choice in enumerate(choices): - assert "\n" not in choice - if not supports_result_index: - pipe.write(str(index).encode()) - pipe.write(b" ") - pipe.write(choice.encode()) - pipe.write(b"\n") + with chooser_process.stdin as pipe: + for index, choice in enumerate(choices): + assert "\n" not in choice + if not supports_result_index: + pipe.write(str(index).encode()) + pipe.write(b" ") + pipe.write(choice.encode()) + pipe.write(b"\n") - exit_code: int = chooser_process.wait() - if exit_code != 0: - raise Exception("chooser process failed with exit code {}".format(exit_code)) + exit_code: int = chooser_process.wait() + if exit_code != 0: + raise Exception("chooser process failed with exit code {}".format(exit_code)) - chosen_index = int(chooser_process.stdout.read().strip().split()[0]) - return chosen_index + chosen_index = int(chooser_process.stdout.read().strip().split()[0]) + return chosen_index def send_notification(title: str, message: str, url: str = None) -> None: - if sys.platform == "darwin": - process_args = [ - "terminal-notifier", - "-title", - title, - "-message", - message, - "-open", - ] - if url is not None: - process_args += [url] - elif os.name == "posix": - process_args = [ - "notify-send", - "--icon=utilities-terminal", - "--expire-time=3000", - title, - message, - ] - else: - platform_not_supported_error() + if sys.platform == "darwin": + process_args = [ + "terminal-notifier", + "-title", + title, + "-message", + message, + "-open", + ] + if url is not None: + process_args += [url] + elif os.name == "posix": + process_args = [ + "notify-send", + "--icon=utilities-terminal", + "--expire-time=3000", + title, + message, + ] + else: + platform_not_supported_error() - subprocess.run(process_args, check=True) + subprocess.run(process_args, check=True) def set_clipboard(text: str) -> None: - # TODO: somehow merge program selection with the logic in `zsh/functions.zsh` - if sys.platform == "darwin": - process_args = ["pbcopy"] - elif os.name == "posix": - process_args = ["xsel", "--clipboard", "--input"] - # process_args = ["xclip", "-in", "-selection", "clipboard"] - else: - platform_not_supported_error() + # TODO: somehow merge program selection with the logic in `zsh/functions.zsh` + if sys.platform == "darwin": + process_args = ["pbcopy"] + elif os.name == "posix": + process_args = ["xsel", "--clipboard", "--input"] + # process_args = ["xclip", "-in", "-selection", "clipboard"] + else: + platform_not_supported_error() - subprocess.run(process_args, input=text.encode(), check=True) + subprocess.run(process_args, input=text.encode(), check=True) diff --git a/script-resources/factorio/property_tree.py b/script-resources/factorio/property_tree.py index 24f921c..9275ff4 100644 --- a/script-resources/factorio/property_tree.py +++ b/script-resources/factorio/property_tree.py @@ -9,58 +9,58 @@ from typing import Any, IO def read_bool(buf: IO[bytes]) -> bool: - return buf.read(1)[0] == 1 + return buf.read(1)[0] == 1 def read_number(buf: IO[bytes]) -> float: - return struct.unpack(" int: - return struct.unpack(" str: - is_empty = read_bool(buf) - if is_empty: - return "" - len_ = buf.read(1)[0] - if len_ == 0xFF: - len_ = _read_length(buf) - return buf.read(len_).decode("utf8") + is_empty = read_bool(buf) + if is_empty: + return "" + len_ = buf.read(1)[0] + if len_ == 0xFF: + len_ = _read_length(buf) + return buf.read(len_).decode("utf8") def read_dictionary(buf: IO[bytes]) -> dict[str, Any]: - len_ = _read_length(buf) - value: dict[str, Any] = {} - for _ in range(len_): - key = read_string(buf) - value[key] = read(buf) - return value + len_ = _read_length(buf) + value: dict[str, Any] = {} + for _ in range(len_): + key = read_string(buf) + value[key] = read(buf) + return value def read_list(buf: IO[bytes]) -> list[Any]: - len_ = _read_length(buf) - value: list[Any] = [] - for _ in range(len_): - read_string(buf) - value.append(read(buf)) - return value + len_ = _read_length(buf) + value: list[Any] = [] + for _ in range(len_): + read_string(buf) + value.append(read(buf)) + return value def read(buf: IO[bytes]) -> Any: - type_, _any_type_flag = buf.read(2) - if type_ == 0: - return None - elif type_ == 1: - return read_bool(buf) - elif type_ == 2: - return read_number(buf) - elif type_ == 3: - return read_string(buf) - elif type_ == 4: - return read_list(buf) - elif type_ == 5: - return read_dictionary(buf) - else: - raise Exception("unknown property tree type 0x{:02x}".format(type_)) + type_, _any_type_flag = buf.read(2) + if type_ == 0: + return None + elif type_ == 1: + return read_bool(buf) + elif type_ == 2: + return read_number(buf) + elif type_ == 3: + return read_string(buf) + elif type_ == 4: + return read_list(buf) + elif type_ == 5: + return read_dictionary(buf) + else: + raise Exception("unknown property tree type 0x{:02x}".format(type_)) diff --git a/script-resources/pycalc_startup.py b/script-resources/pycalc_startup.py index 1ffb1b2..6aab338 100644 --- a/script-resources/pycalc_startup.py +++ b/script-resources/pycalc_startup.py @@ -3,29 +3,29 @@ from fractions import Fraction def factors(n): - result = set() - for i in range(1, int(sqrt(n)) + 1): - if n % i == 0: - result.add(i) - result.add(n // i) - return result + result = set() + for i in range(1, int(sqrt(n)) + 1): + if n % i == 0: + result.add(i) + result.add(n // i) + return result def solve_quadratic(a, b, c): - if a == 0: - raise Exception("not a quadratic equation") - else: - d = b ** 2 - 4 * a * c - print("D = " + str(d)) - if d < 0: - print("no solutions") - elif d > 0: - sd = sqrt(d) - print("sqrt(D) = " + str(sd)) - print("x1 = " + str((-b + sd) / (2 * a))) - print("x2 = " + str((-b - sd) / (2 * a))) + if a == 0: + raise Exception("not a quadratic equation") else: - print("x = " + str(-b / (2 * a))) + d = b ** 2 - 4 * a * c + print("D = " + str(d)) + if d < 0: + print("no solutions") + elif d > 0: + sd = sqrt(d) + print("sqrt(D) = " + str(sd)) + print("x1 = " + str((-b + sd) / (2 * a))) + print("x2 = " + str((-b - sd) / (2 * a))) + else: + print("x = " + str(-b / (2 * a))) print("loaded Python calculator") diff --git a/script-resources/welcome/colors.py b/script-resources/welcome/colors.py index a835612..b32d782 100644 --- a/script-resources/welcome/colors.py +++ b/script-resources/welcome/colors.py @@ -1,22 +1,21 @@ from colorama import Fore, Style, ansi - COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)] def colored(string, *colors): - return "".join(colors + (string, Style.RESET_ALL)) + return "".join(colors + (string, Style.RESET_ALL)) def bright_colored(string, *colors): - return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL)) + return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL)) def colorize_percent(percent, warning, critical, inverse=False): - COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED] + COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED] - color_index = 0 if percent < warning else 1 if percent < critical else 2 - if inverse: - color_index = 2 - color_index + color_index = 0 if percent < warning else 1 if percent < critical else 2 + if inverse: + color_index = 2 - color_index - return colored("%.2f%%" % percent, COLORS[color_index]) + return colored("%.2f%%" % percent, COLORS[color_index]) diff --git a/script-resources/welcome/humanize.py b/script-resources/welcome/humanize.py index 9631a9c..ac7c7fb 100644 --- a/script-resources/welcome/humanize.py +++ b/script-resources/welcome/humanize.py @@ -1,34 +1,34 @@ def humanize_timedelta(timedelta): - result = [] + result = [] - days = timedelta.days - mm, ss = divmod(timedelta.seconds, 60) - hh, mm = divmod(mm, 60) + days = timedelta.days + mm, ss = divmod(timedelta.seconds, 60) + hh, mm = divmod(mm, 60) - def plural(n): - return n, "s" if abs(n) != 1 else "" + def plural(n): + return n, "s" if abs(n) != 1 else "" - if days > 0: - result.append("%d day%s" % plural(days)) - if hh > 0 or result: - result.append("%d hour%s" % plural(hh)) - if mm > 0 or result: - result.append("%d min%s" % plural(mm)) - if len(result) <= 1: - result.append("%d sec%s" % plural(ss)) + if days > 0: + result.append("%d day%s" % plural(days)) + if hh > 0 or result: + result.append("%d hour%s" % plural(hh)) + if mm > 0 or result: + result.append("%d min%s" % plural(mm)) + if len(result) <= 1: + result.append("%d sec%s" % plural(ss)) - return ", ".join(result) + return ", ".join(result) def humanize_bytes(bytes): - units = ["B", "kB", "MB", "GB"] + units = ["B", "kB", "MB", "GB"] - factor = 1 - unit = "" - for unit in units: - next_factor = factor << 10 - if bytes < next_factor: - break - factor = next_factor + factor = 1 + unit = "" + for unit in units: + next_factor = factor << 10 + if bytes < next_factor: + break + factor = next_factor - return "%.2f %s" % (float(bytes) / factor, unit) + return "%.2f %s" % (float(bytes) / factor, unit) diff --git a/script-resources/welcome/main.py b/script-resources/welcome/main.py index 6eb37f7..40e9c42 100755 --- a/script-resources/welcome/main.py +++ b/script-resources/welcome/main.py @@ -5,7 +5,6 @@ import re from colors import COLORS, Style from system_info import get_system_info - print("") logo_lines, info_lines = get_system_info() @@ -13,24 +12,24 @@ logo_line_widths = [len(re.sub(r"{\d}", "", line)) for line in logo_lines] logo_width = max(logo_line_widths) for line_index in range(0, max(len(logo_lines), len(info_lines))): - line = "" + line = "" - logo_line_width = 0 + logo_line_width = 0 - if line_index < len(logo_lines): - logo_line = logo_lines[line_index] - logo_line_width = logo_line_widths[line_index] + if line_index < len(logo_lines): + logo_line = logo_lines[line_index] + logo_line_width = logo_line_widths[line_index] - line += Style.BRIGHT - line += logo_line.format(*COLORS) - line += Style.RESET_ALL + line += Style.BRIGHT + line += logo_line.format(*COLORS) + line += Style.RESET_ALL - line += " " * (logo_width - logo_line_width + 3) + line += " " * (logo_width - logo_line_width + 3) - if line_index < len(info_lines): - info_line = info_lines[line_index] - line += info_line + if line_index < len(info_lines): + info_line = info_lines[line_index] + line += info_line - print(line) + print(line) print("") diff --git a/script-resources/welcome/system_info.py b/script-resources/welcome/system_info.py index 9d72ded..d840055 100644 --- a/script-resources/welcome/system_info.py +++ b/script-resources/welcome/system_info.py @@ -11,200 +11,206 @@ from humanize import humanize_bytes, humanize_timedelta def get_system_info(): - info_lines = [] + info_lines = [] - def info(name, value, *format_args): - line = bright_colored(name + ":", Fore.YELLOW) + " " + value - if format_args: - line = line % format_args - info_lines.append(line) + def info(name, value, *format_args): + line = bright_colored(name + ":", Fore.YELLOW) + " " + value + if format_args: + line = line % format_args + info_lines.append(line) - username = getuser() - hostname = _get_hostname() + username = getuser() + hostname = _get_hostname() - info_lines.append(bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED)) - info_lines.append("") + info_lines.append( + bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED) + ) + info_lines.append("") - distro_id, distro_name, distro_version, distro_codename = _get_distro_info() - info("OS", " ".join([distro_name, distro_version, distro_codename])) + distro_id, distro_name, distro_version, distro_codename = _get_distro_info() + info("OS", " ".join([distro_name, distro_version, distro_codename])) - logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id) - with open(logo_path) as logo_file: - logo_lines = logo_file.read().splitlines() + logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id) + with open(logo_path) as logo_file: + logo_lines = logo_file.read().splitlines() - info("Kernel", "%s %s", platform.system(), platform.release()) + info("Kernel", "%s %s", platform.system(), platform.release()) - info("Uptime", humanize_timedelta(_get_uptime())) + info("Uptime", humanize_timedelta(_get_uptime())) - users_info = _get_users() - if users_info: - info("Users", users_info) + users_info = _get_users() + if users_info: + info("Users", users_info) - shell = _get_shell() - if shell is not None: - info("Shell", shell) + shell = _get_shell() + if shell is not None: + info("Shell", shell) - info_lines.append("") + info_lines.append("") - cpu_usage_info = _get_cpu_usage() - if cpu_usage_info is not None: - info("CPU Usage", "%s", cpu_usage_info) - info("Memory", "%s / %s (%s)", *_get_memory()) + cpu_usage_info = _get_cpu_usage() + if cpu_usage_info is not None: + info("CPU Usage", "%s", cpu_usage_info) + info("Memory", "%s / %s (%s)", *_get_memory()) - for disk_info in _get_disks(): - info("Disk (%s)", "%s / %s (%s)", *disk_info) + for disk_info in _get_disks(): + info("Disk (%s)", "%s / %s (%s)", *disk_info) - battery_info = _get_battery() - if battery_info is not None: - info("Battery", "%s (%s)", *battery_info) + battery_info = _get_battery() + if battery_info is not None: + info("Battery", "%s (%s)", *battery_info) - info_lines.append("") + info_lines.append("") - for local_ip_address in _get_local_ipv4_addresses(): - info("Local IPv4 Address (%s)", "%s", *local_ip_address) + for local_ip_address in _get_local_ipv4_addresses(): + info("Local IPv4 Address (%s)", "%s", *local_ip_address) - return logo_lines, info_lines + return logo_lines, info_lines def _get_hostname(): - hostname = socket.gethostname() - return hostname + hostname = socket.gethostname() + return hostname def _get_uptime(): - return datetime.now() - datetime.fromtimestamp(psutil.boot_time()) + return datetime.now() - datetime.fromtimestamp(psutil.boot_time()) def _get_users(): - users = {} + users = {} - for user in psutil.users(): - name = user.name - terminal = user.terminal - if name in users: - users[name].append(terminal) - else: - users[name] = [terminal] + for user in psutil.users(): + name = user.name + terminal = user.terminal + if name in users: + users[name].append(terminal) + else: + users[name] = [terminal] - result = [] + result = [] - for name in users: - terminals = users[name] + for name in users: + terminals = users[name] - colored_name = bright_colored(name, Fore.BLUE) - colored_terminals = [colored(str(term), Style.DIM, Fore.WHITE) for term in terminals] + colored_name = bright_colored(name, Fore.BLUE) + colored_terminals = [ + colored(str(term), Style.DIM, Fore.WHITE) for term in terminals + ] - terminals_str = ", ".join(colored_terminals) - if len(colored_terminals) > 1: - terminals_str = "(%s)" % terminals_str - result.append(colored_name + "@" + terminals_str) + terminals_str = ", ".join(colored_terminals) + if len(colored_terminals) > 1: + terminals_str = "(%s)" % terminals_str + result.append(colored_name + "@" + terminals_str) - return ", ".join(result) + return ", ".join(result) def _get_shell(): - return os.environ.get("SHELL") + return os.environ.get("SHELL") def _get_cpu_usage(): - try: - percent = psutil.cpu_percent() - except Exception as e: - print("Error in _get_cpu_usage:", e) - return None + try: + percent = psutil.cpu_percent() + except Exception as e: + print("Error in _get_cpu_usage:", e) + return None - return colorize_percent(percent, warning=60, critical=80) + return colorize_percent(percent, warning=60, critical=80) def _get_memory(): - memory = psutil.virtual_memory() - return ( - humanize_bytes(memory.used), - humanize_bytes(memory.total), - colorize_percent(memory.percent, warning=60, critical=80), - ) + memory = psutil.virtual_memory() + return ( + humanize_bytes(memory.used), + humanize_bytes(memory.total), + colorize_percent(memory.percent, warning=60, critical=80), + ) def _get_disks(): - result = [] + result = [] - for disk in psutil.disk_partitions(all=False): - if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""): - # skip cd-rom drives with no disk in it on Windows; they may raise - # ENOENT, pop-up a Windows GUI error for a non-ready partition or - # just hang - continue + for disk in psutil.disk_partitions(all=False): + if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""): + # skip cd-rom drives with no disk in it on Windows; they may raise + # ENOENT, pop-up a Windows GUI error for a non-ready partition or + # just hang + continue - usage = psutil.disk_usage(disk.mountpoint) - result.append(( - disk.mountpoint, - humanize_bytes(usage.used), - humanize_bytes(usage.total), - colorize_percent(usage.percent, warning=70, critical=85), - )) + usage = psutil.disk_usage(disk.mountpoint) + result.append( + ( + disk.mountpoint, + humanize_bytes(usage.used), + humanize_bytes(usage.total), + colorize_percent(usage.percent, warning=70, critical=85), + ) + ) - return result + return result def _get_battery(): - if not hasattr(psutil, "sensors_battery"): - return None + if not hasattr(psutil, "sensors_battery"): + return None - try: - battery = psutil.sensors_battery() - except Exception as e: - print("Error in _get_battery:", e) - return None + try: + battery = psutil.sensors_battery() + except Exception as e: + print("Error in _get_battery:", e) + return None - if battery is None: - return None + if battery is None: + return None - percent = battery.percent - if battery.power_plugged: - status = "charging" if percent < 100 else "fully charged" - else: - status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft)) - return colorize_percent(percent, critical=10, warning=20, inverse=True), status + percent = battery.percent + if battery.power_plugged: + status = "charging" if percent < 100 else "fully charged" + else: + status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft)) + return colorize_percent(percent, critical=10, warning=20, inverse=True), status def _get_local_ipv4_addresses(): - result = [] + result = [] - for interface, addresses in psutil.net_if_addrs().items(): - for address in addresses: - if address.family != socket.AF_INET: - # allow only IPv4 addresses (skip IPv6 and MAC, for example) - continue - if interface.startswith("lo"): - # skip loopback interfaces - continue + for interface, addresses in psutil.net_if_addrs().items(): + for address in addresses: + if address.family != socket.AF_INET: + # allow only IPv4 addresses (skip IPv6 and MAC, for example) + continue + if interface.startswith("lo"): + # skip loopback interfaces + continue - result.append((interface, address.address)) + result.append((interface, address.address)) - return result + return result def _get_distro_info(): - if psutil.WINDOWS: - return "windows", platform.system(), platform.release(), "" - elif psutil.OSX: - import plistlib + if psutil.WINDOWS: + return "windows", platform.system(), platform.release(), "" + elif psutil.OSX: + import plistlib - with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f: - sw_vers = plistlib.load(f) - return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], "" - elif _is_android(): - from subprocess import check_output + with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f: + sw_vers = plistlib.load(f) + return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], "" + elif _is_android(): + from subprocess import check_output - android_version = check_output(["getprop", "ro.build.version.release"]) - return "android", "Android", android_version.decode().strip(), "" - elif psutil.LINUX: - import distro + android_version = check_output(["getprop", "ro.build.version.release"]) + return "android", "Android", android_version.decode().strip(), "" + elif psutil.LINUX: + import distro - return distro.id(), distro.name(), distro.version(), distro.codename() + return distro.id(), distro.name(), distro.version(), distro.codename() - raise NotImplementedError("unsupported OS") + raise NotImplementedError("unsupported OS") def _is_android(): - return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app") + return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app") diff --git a/scripts/copy-crosscode-emoji-url b/scripts/copy-crosscode-emoji-url index f5516a9..1fcbdc4 100755 --- a/scripts/copy-crosscode-emoji-url +++ b/scripts/copy-crosscode-emoji-url @@ -9,76 +9,88 @@ from typing import Any, Generator, Optional, Union import urllib.parse import urllib.request - sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources")) import common_script_utils DEFAULT_REGISTRY_DUMP_URL = "https://stronghold.crosscode.ru/~ccbot/emote-registry.json" + if os.name == "posix": - config_path: Path = (common_script_utils.DOTFILES_CONFIG_DIR / "copy-crosscode-emoji-url.ini") - default_registry_dump_file: Path = (common_script_utils.DOTFILES_CACHE_DIR / "dotfiles") + config_path: Path = ( + common_script_utils.DOTFILES_CONFIG_DIR / "copy-crosscode-emoji-url.ini" + ) + default_registry_dump_file: Path = ( + common_script_utils.DOTFILES_CACHE_DIR / "dotfiles" + ) else: - common_script_utils.platform_not_supported_error() + common_script_utils.platform_not_supported_error() config = ConfigParser(interpolation=None) config.read(config_path) + emotes: list[dict[str, Any]] = [] def emote_downloader_and_iterator() -> Generator[str, None, None]: - global emotes + global emotes - registry_dump_file: Optional[Union[ - str, Path]] = config.get("default", "ccbot_emote_registry_dump_file", fallback=None) - if registry_dump_file is not None: - registry_dump_file = os.path.expanduser(registry_dump_file) - else: - registry_dump_file = default_registry_dump_file + registry_dump_file: Optional[Union[str, Path]] = config.get( + "default", "ccbot_emote_registry_dump_file", fallback=None + ) + if registry_dump_file is not None: + registry_dump_file = os.path.expanduser(registry_dump_file) + else: + registry_dump_file = default_registry_dump_file - registry_dump_url = config.get( - "default", "ccbot_emote_registry_dump_url", fallback=DEFAULT_REGISTRY_DUMP_URL - ) + registry_dump_url = config.get( + "default", "ccbot_emote_registry_dump_url", fallback=DEFAULT_REGISTRY_DUMP_URL + ) - emote_registry_data: dict[str, Any] - try: - with open(registry_dump_file, "r") as f: - emote_registry_data = json.load(f) - except FileNotFoundError: - with urllib.request.urlopen(registry_dump_url, timeout=10) as response: - emote_registry_data = json.load(response) + emote_registry_data: dict[str, Any] + try: + with open(registry_dump_file, "r") as f: + emote_registry_data = json.load(f) + except FileNotFoundError: + with urllib.request.urlopen(registry_dump_url, timeout=10) as response: + emote_registry_data = json.load(response) - assert emote_registry_data["version"] == 1 + assert emote_registry_data["version"] == 1 - emotes = [emote for emote in emote_registry_data["list"]] + emotes = [emote for emote in emote_registry_data["list"] + # if emote["safe"] + ] - for emote in emotes: - yield "{emote[ref]} [{emote[guild_name]}]".format(emote=emote) + for emote in emotes: + yield "{emote[ref]} [{emote[guild_name]}]".format(emote=emote) chosen_index = common_script_utils.run_chooser( - emote_downloader_and_iterator(), prompt="emote", async_read=True + emote_downloader_and_iterator(), prompt="emote", async_read=True ) if chosen_index >= 0: - chosen_emote = emotes[chosen_index] + chosen_emote = emotes[chosen_index] - emote_url: urllib.parse.ParseResult = urllib.parse.urlparse(chosen_emote["url"]) - emote_url_query: dict[str, list[str]] = urllib.parse.parse_qs(emote_url.query) + emote_url: urllib.parse.ParseResult = urllib.parse.urlparse(chosen_emote["url"]) + emote_url_query: dict[str, list[str]] = urllib.parse.parse_qs(emote_url.query) - if config.getboolean("default", "add_emote_name_to_url", fallback=False): - emote_url_query["name"] = [chosen_emote["name"]] + if config.getboolean("default", "add_emote_name_to_url", fallback=False): + emote_url_query["name"] = [chosen_emote["name"]] - default_emote_image_size = config.getint("default", "default_emote_image_size", fallback=None) - if default_emote_image_size is not None: - emote_url_query["size"] = [str(default_emote_image_size)] + default_emote_image_size = config.getint( + "default", "default_emote_image_size", fallback=None + ) + if default_emote_image_size is not None: + emote_url_query["size"] = [str(default_emote_image_size)] - emote_url_query_str = urllib.parse.urlencode(emote_url_query, doseq=True) - emote_url_str = urllib.parse.urlunparse(emote_url._replace(query=emote_url_query_str)) + emote_url_query_str = urllib.parse.urlencode(emote_url_query, doseq=True) + emote_url_str = urllib.parse.urlunparse( + emote_url._replace(query=emote_url_query_str) + ) - common_script_utils.set_clipboard(emote_url_str) + common_script_utils.set_clipboard(emote_url_str) - common_script_utils.send_notification( - os.path.basename(__file__), - "copied URL of {} to clipboard!".format(chosen_emote["ref"]), - ) + common_script_utils.send_notification( + os.path.basename(__file__), + "copied URL of {} to clipboard!".format(chosen_emote["ref"]), + ) diff --git a/scripts/discord-snowflake b/scripts/discord-snowflake index 85343ba..25380b9 100755 --- a/scripts/discord-snowflake +++ b/scripts/discord-snowflake @@ -6,16 +6,17 @@ import sys import colorama import time - DISCORD_EPOCH = 1420070400000 # milliseconds user_snowflake = int(sys.argv[1]) def print_field(name, value): - print( - "{}{}:{} {}".format(colorama.Style.BRIGHT, name.rjust(21), colorama.Style.RESET_ALL, value) - ) + print( + "{}{}:{} {}".format( + colorama.Style.BRIGHT, name.rjust(21), colorama.Style.RESET_ALL, value + ) + ) creation_time = (user_snowflake >> 22) + DISCORD_EPOCH @@ -24,11 +25,11 @@ internal_process_id = (user_snowflake >> 12) & 0x1F increment = user_snowflake & 0xFFF print_field( - "Created at", - "{}.{}".format( - time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(creation_time // 1000)), - creation_time % 1000, - ), + "Created at", + "{}.{}".format( + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(creation_time // 1000)), + creation_time % 1000, + ), ) print_field("Internal worker ID", internal_worker_id) print_field("Internal process ID", internal_process_id) diff --git a/scripts/discord-stream-desktop-audio b/scripts/discord-stream-desktop-audio index 1812557..0161def 100755 --- a/scripts/discord-stream-desktop-audio +++ b/scripts/discord-stream-desktop-audio @@ -4,33 +4,35 @@ import discord import sys import os - guild_id = int(sys.argv[1]) voice_channel_id = int(sys.argv[2]) pulseaudio_device = sys.argv[3] with open(os.path.expanduser("~/.config/dotfiles/discord-tools-user-token.txt")) as f: - bot_token = f.read().strip() + bot_token = f.read().strip() + bot = discord.Client() @bot.event async def on_ready(): - print("logged in as {0} ({0.id})".format(bot.user)) + print("logged in as {0} ({0.id})".format(bot.user)) - guild: discord.Guild = bot.get_guild(guild_id) - if guild is None: - raise Exception("guild not found") - voice_channel: discord.VoiceChannel = guild.get_channel(voice_channel_id) - if voice_channel is None: - raise Exception("channel not found") + guild: discord.Guild = bot.get_guild(guild_id) + if guild is None: + raise Exception("guild not found") + voice_channel: discord.VoiceChannel = guild.get_channel(voice_channel_id) + if voice_channel is None: + raise Exception("channel not found") - voice_client = await voice_channel.connect() - print("connected to {0} ({0.id}) in {1} ({1.id})".format(voice_channel, guild)) + voice_client = await voice_channel.connect() + print("connected to {0} ({0.id}) in {1} ({1.id})".format(voice_channel, guild)) - source = discord.FFmpegPCMAudio(pulseaudio_device, before_options="-f pulse") - voice_client.play(source, after=lambda e: print("Player error: %s" % e) if e else None) + source = discord.FFmpegPCMAudio(pulseaudio_device, before_options="-f pulse") + voice_client.play( + source, after=lambda e: print("Player error: %s" % e) if e else None + ) bot.run(bot_token, bot=False) diff --git a/scripts/discord-whois b/scripts/discord-whois index 0598fed..91fd346 100755 --- a/scripts/discord-whois +++ b/scripts/discord-whois @@ -18,21 +18,22 @@ import typing DISCORD_EPOCH = 1420070400000 # milliseconds # https://discord.com/developers/docs/resources/user#user-object-user-flags DISCORD_FLAGS = { - "Discord Employee": 1 << 0, - "Discord Partner": 1 << 1, - "HypeSquad Events": 1 << 2, - "Bug Hunter Level 1": 1 << 3, - "House of Bravery": 1 << 6, - "House of Brilliance": 1 << 7, - "House of Balance": 1 << 8, - "Early Supporter": 1 << 9, - "Team User": 1 << 10, - "System": 1 << 12, - "Bug Hunter Level 2": 1 << 14, - "Verified Bot": 1 << 16, - "Verified Bot Developer": 1 << 17, + "Discord Employee": 1 << 0, + "Discord Partner": 1 << 1, + "HypeSquad Events": 1 << 2, + "Bug Hunter Level 1": 1 << 3, + "House of Bravery": 1 << 6, + "House of Brilliance": 1 << 7, + "House of Balance": 1 << 8, + "Early Supporter": 1 << 9, + "Team User": 1 << 10, + "System": 1 << 12, + "Bug Hunter Level 2": 1 << 14, + "Verified Bot": 1 << 16, + "Verified Bot Developer": 1 << 17, } + parser = argparse.ArgumentParser() parser.add_argument("user_snowflake", type=int) parser.add_argument("--bot-token", type=str) @@ -44,29 +45,32 @@ user_snowflake = cli_args.user_snowflake bot_token = cli_args.bot_token if bot_token is None: - with open(os.path.expanduser("~/.config/dotfiles/discord-tools-bot-token.txt")) as f: - bot_token = f.read().strip() + with open( + os.path.expanduser("~/.config/dotfiles/discord-tools-bot-token.txt") + ) as f: + bot_token = f.read().strip() image_size = cli_args.image_size if not (image_size is None or (image_size > 0 and image_size & (image_size - 1)) == 0): - parser.error("image_size must be greater than zero and a power of two") + parser.error("image_size must be greater than zero and a power of two") + try: - opener = urllib.request.build_opener() - # Don't send the User-Agent header, Discord blocks the default one - opener.addheaders = [] - with opener.open( - urllib.request.Request( - "http://discord.com/api/users/{}".format(user_snowflake), - headers={"Authorization": "Bot {}".format(bot_token)}, - ), - timeout=10, - ) as response: - raw_data = json.load(response) + opener = urllib.request.build_opener() + # Don't send the User-Agent header, Discord blocks the default one + opener.addheaders = [] + with opener.open( + urllib.request.Request( + "http://discord.com/api/users/{}".format(user_snowflake), + headers={"Authorization": "Bot {}".format(bot_token)}, + ), + timeout=10, + ) as response: + raw_data = json.load(response) except urllib.error.HTTPError as err: - print(err, file=sys.stderr) - print(err.read(), file=sys.stderr) - raise err + print(err, file=sys.stderr) + print(err.read(), file=sys.stderr) + raise err data = {} @@ -74,17 +78,19 @@ data["ID"] = raw_data["id"] data["Name"] = "{}#{}".format(raw_data["username"], raw_data["discriminator"]) default_avatar_url = "https://cdn.discordapp.com/embed/avatars/{}.png".format( - int(raw_data["discriminator"], 10) % 5 + int(raw_data["discriminator"], 10) % 5 ) avatar_url = ( - "https://cdn.discordapp.com/avatars/{}/{}.{}".format( - raw_data["id"], - raw_data["avatar"], - "gif" if raw_data["avatar"].startswith("a_") else "png", - ) if raw_data["avatar"] is not None else default_avatar_url + "https://cdn.discordapp.com/avatars/{}/{}.{}".format( + raw_data["id"], + raw_data["avatar"], + "gif" if raw_data["avatar"].startswith("a_") else "png", + ) + if raw_data["avatar"] is not None + else default_avatar_url ) if image_size is not None: - avatar_url += "?size={}".format(image_size) + avatar_url += "?size={}".format(image_size) data["Avatar"] = avatar_url data["Default avatar"] = default_avatar_url @@ -95,37 +101,38 @@ data["System user"] = raw_data.get("system", False) # https://discord.com/developers/docs/reference#convert-snowflake-to-datetime snowflake_creation_time = (user_snowflake >> 22) + DISCORD_EPOCH data["Created at"] = "{}.{} UTC".format( - time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(snowflake_creation_time // 1000)), - snowflake_creation_time % 1000, + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(snowflake_creation_time // 1000)), + snowflake_creation_time % 1000, ) user_flags = raw_data["public_flags"] if user_flags == 0: - data["Flags"] = "" + data["Flags"] = "" else: - user_flag_names = [] - for flag_name, bitmask in DISCORD_FLAGS.items(): - if user_flags & bitmask: - user_flag_names.append(flag_name) - data["Flags"] = ", ".join(user_flag_names) + user_flag_names = [] + for flag_name, bitmask in DISCORD_FLAGS.items(): + if user_flags & bitmask: + user_flag_names.append(flag_name) + data["Flags"] = ", ".join(user_flag_names) + if cli_args.get_prop is None: - max_name_length = max(map(len, data.keys())) - for name, value in data.items(): + max_name_length = max(map(len, data.keys())) + for name, value in data.items(): - if value is True: - value = "yes" - elif value is False: - value = "no" + if value is True: + value = "yes" + elif value is False: + value = "no" - print( - "{}{:>{}}:{} {}".format( - colorama.Style.BRIGHT, - name, - max_name_length + 1, - colorama.Style.RESET_ALL, - value, - ) - ) + print( + "{}{:>{}}:{} {}".format( + colorama.Style.BRIGHT, + name, + max_name_length + 1, + colorama.Style.RESET_ALL, + value, + ) + ) else: - print(data[cli_args.get_prop]) + print(data[cli_args.get_prop]) diff --git a/scripts/factorio-dump-mod-settings b/scripts/factorio-dump-mod-settings index 8530465..5f04b2e 100755 --- a/scripts/factorio-dump-mod-settings +++ b/scripts/factorio-dump-mod-settings @@ -10,29 +10,31 @@ from pathlib import Path import struct import json - sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources")) import factorio.property_tree + with open(Path.home() / ".factorio" / "mods" / "mod-settings.dat", "rb") as f: - version_main: int - version_major: int - version_minor: int - version_developer: int - version_main, version_major, version_minor, version_developer = struct.unpack(" Union[str, list[int]]: - if encoding == "utf8": - try: - return b.decode("utf8") - except UnicodeDecodeError: - return list(b) - elif encoding == "base16": - return base64.b16encode(b).decode("ascii") - elif encoding == "base32": - return base64.b32encode(b).decode("ascii") - elif encoding == "base64": - return base64.b64encode(b).decode("ascii") - elif encoding == "base85": - return base64.b85encode(b).decode("ascii") - else: - assert False + if encoding == "utf8": + try: + return b.decode("utf8") + except UnicodeDecodeError: + return list(b) + elif encoding == "base16": + return base64.b16encode(b).decode("ascii") + elif encoding == "base32": + return base64.b32encode(b).decode("ascii") + elif encoding == "base64": + return base64.b64encode(b).decode("ascii") + elif encoding == "base85": + return base64.b85encode(b).decode("ascii") + else: + assert False key_encoding: str = cli_args.key_encoding or cli_args.encoding value_encoding: str = cli_args.value_encoding or cli_args.encoding db = plyvel.DB(str(cli_args.db_path), create_if_missing=False) with db.iterator() as iterator: - for key, value in iterator: - json.dump( - { - "key": bytes_to_json(key, key_encoding), - "value": bytes_to_json(value, value_encoding), - }, - stdout, - ) - stdout.write("\n") + for key, value in iterator: + json.dump( + { + "key": bytes_to_json(key, key_encoding), + "value": bytes_to_json(value, value_encoding), + }, + stdout, + ) + stdout.write("\n") diff --git a/scripts/mark-as-recently-used b/scripts/mark-as-recently-used index c35e763..63475cd 100755 --- a/scripts/mark-as-recently-used +++ b/scripts/mark-as-recently-used @@ -1,16 +1,14 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # Taken from import gi import sys - gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gio, GLib - +from gi.repository import Gtk, Gio, GLib # noqa E402 rec_mgr = Gtk.RecentManager.get_default() for arg in sys.argv[1:]: - rec_mgr.add_item(Gio.File.new_for_path(arg).get_uri()) + rec_mgr.add_item(Gio.File.new_for_path(arg).get_uri()) GLib.idle_add(Gtk.main_quit) Gtk.main() diff --git a/scripts/mediawiki-preview b/scripts/mediawiki-preview index b2d978b..c1cfc68 100755 --- a/scripts/mediawiki-preview +++ b/scripts/mediawiki-preview @@ -38,6 +38,7 @@ # - The module `skins.citizen.scripts` references search inputs which aren't # created by this script. + import argparse import mwclient import json @@ -50,85 +51,85 @@ LANG = "en" LANG_TEXT_DIRECTION = "ltr" MODULES_POST_LOAD = { - "vector": [ - "site", - "mediawiki.page.startup", - "mediawiki.page.ready", - "mediawiki.toc", - # "mediawiki.searchSuggest", - # "mediawiki.page.watch.ajax", - "skins.vector.js", - ], - "citizen": [ - # "site", - # "mediawiki.page.startup", - # "mediawiki.page.ready", - # "mediawiki.toc", - # "skins.citizen.scripts.toc", - # "skins.citizen.scripts.search", - # "skins.citizen.styles.search", - # "skins.citizen.icons.search", - # "skins.citizen.scripts", - ], + "vector": [ + "site", + "mediawiki.page.startup", + "mediawiki.page.ready", + "mediawiki.toc", + # "mediawiki.searchSuggest", + # "mediawiki.page.watch.ajax", + "skins.vector.js", + ], + "citizen": [ + # "site", + # "mediawiki.page.startup", + # "mediawiki.page.ready", + # "mediawiki.toc", + # "skins.citizen.scripts.toc", + # "skins.citizen.scripts.search", + # "skins.citizen.styles.search", + # "skins.citizen.icons.search", + # "skins.citizen.scripts", + ], } MODULES_POST_LOAD_BLOCKED = { - "citizen": [ - "skins.citizen.scripts.toc", - "skins.citizen.scripts.search", - "skins.citizen.styles.search", - "skins.citizen.icons.search", - ], + "citizen": [ + "skins.citizen.scripts.toc", + "skins.citizen.scripts.search", + "skins.citizen.styles.search", + "skins.citizen.icons.search", + ], } MODULES_PRELOAD_STYLES = { - "vector": [ - "mediawiki.legacy.commonPrint", - "mediawiki.legacy.shared", - "mediawiki.skinning.interface", - "mediawiki.toc.styles", - "skins.vector.styles", - "site.styles", - ], - "citizen": [ - # "mediawiki.legacy.commonPrint", - # "mediawiki.legacy.shared", - "mediawiki.skinning.content.externallinks", - # "mediawiki.toc.styles", - "skins.citizen.icons", - "skins.citizen.styles", - "skins.citizen.icons.ca", - "skins.citizen.icons.es", - "skins.citizen.icons.footer", - "skins.citizen.icons.n", - "skins.citizen.icons.pt", - "skins.citizen.icons.t", - "skins.citizen.styles.fonts", - "skins.citizen.styles.toc", - "site.styles", - ], + "vector": [ + "mediawiki.legacy.commonPrint", + "mediawiki.legacy.shared", + "mediawiki.skinning.interface", + "mediawiki.toc.styles", + "skins.vector.styles", + "site.styles", + ], + "citizen": [ + # "mediawiki.legacy.commonPrint", + # "mediawiki.legacy.shared", + "mediawiki.skinning.content.externallinks", + # "mediawiki.toc.styles", + "skins.citizen.icons", + "skins.citizen.styles", + "skins.citizen.icons.ca", + "skins.citizen.icons.es", + "skins.citizen.icons.footer", + "skins.citizen.icons.n", + "skins.citizen.icons.pt", + "skins.citizen.icons.t", + "skins.citizen.styles.fonts", + "skins.citizen.styles.toc", + "site.styles", + ], } MODULES_PRELOAD_SCRIPTS = { - "vector": ["startup"], - "citizen": ["startup"], + "vector": ["startup"], + "citizen": ["startup"], } # ported from def escape_css_class(class_str): - class_str = re.sub( - r"""(^[0-9\-])|[\x00-\x20!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~]|\xA0""", - "_", - class_str, - ) - class_str = re.sub(r"_+", "_", class_str) - class_str = class_str.rstrip("_") - return class_str + class_str = re.sub( + r"""(^[0-9\-])|[\x00-\x20!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~]|\xA0""", + "_", + class_str, + ) + class_str = re.sub(r"_+", "_", class_str) + class_str = class_str.rstrip("_") + return class_str def json_dumps_compact(data): - return json.dumps(data, indent=None, separators=(",", ":")) + return json.dumps(data, indent=None, separators=(",", ":")) parser = argparse.ArgumentParser() @@ -136,55 +137,50 @@ parser.add_argument("--site", type=str, required=True) parser.add_argument("--scheme", type=str, default="https") parser.add_argument("--skin", type=str, default="vector") parser.add_argument( - "--input", - type=str, - required=True, + "--input", type=str, required=True, ) parser.add_argument("--title", type=str) parser.add_argument("--output", type=str, required=True) cli_args = parser.parse_args() + site = mwclient.Site(cli_args.site, scheme=cli_args.scheme) def get_load_script_url(**args): - return "{path}load{ext}?{args}".format( - path=site.path, - ext=site.ext, - args=urlencode({ - "lang": LANG, - "skin": cli_args.skin, - **args - }), - ) + return "{path}load{ext}?{args}".format( + path=site.path, + ext=site.ext, + args=urlencode({"lang": LANG, "skin": cli_args.skin, **args}), + ) with open(cli_args.input, "r") as f: - wikitext_str = f.read() + wikitext_str = f.read() result = site.post( - "parse", - title=cli_args.title, - text=wikitext_str, - contentmodel="wikitext", - prop="text|indicators|displaytitle|modules|jsconfigvars|categorieshtml", - preview=True, - pst=True, # pre-save transforms - sectionpreview=False, - disableeditsection=True, # disables "[edit]" links next to headers - useskin=cli_args.skin, - uselang=LANG, + "parse", + title=cli_args.title, + text=wikitext_str, + contentmodel="wikitext", + prop="text|indicators|displaytitle|modules|jsconfigvars|categorieshtml", + preview=True, + pst=True, # pre-save transforms + sectionpreview=False, + disableeditsection=True, # disables "[edit]" links next to headers + useskin=cli_args.skin, + uselang=LANG, )["parse"] def get_modules(page_modules, added_modules_dict, blocked_modules_dict={}): - modules = page_modules + added_modules_dict[cli_args.skin] - for blocked_module in blocked_modules_dict.get(cli_args.skin, []): - try: - modules.remove(blocked_module) - except ValueError: - pass - return modules + modules = page_modules + added_modules_dict[cli_args.skin] + for blocked_module in blocked_modules_dict.get(cli_args.skin, []): + try: + modules.remove(blocked_module) + except ValueError: + pass + return modules rendered_html = """\ @@ -244,43 +240,53 @@ rendered_html = """\ """.format( - lang=html.escape(LANG), - text_dir=html.escape(LANG_TEXT_DIRECTION), - base_url=html.escape("{}://{}".format(site.scheme, site.host)), - page_modules_state_json=json_dumps_compact({ - "noscript": "ready", - "user.options": "ready", - "user.tokens": "loading", - **{name: "ready" for name in MODULES_PRELOAD_STYLES[cli_args.skin]}, - }), - page_config_json=json_dumps_compact(result["jsconfigvars"]), - page_modules_json=json_dumps_compact( - get_modules(result["modules"], MODULES_POST_LOAD, MODULES_POST_LOAD_BLOCKED) - ), - style_url=html.escape( - get_load_script_url( - only="styles", - modules="|".join(get_modules(result["modulestyles"], MODULES_PRELOAD_STYLES)), - ) - ), - script_url=html.escape( - get_load_script_url( - only="scripts", - modules="|".join(get_modules(result["modulescripts"], MODULES_PRELOAD_SCRIPTS)), - raw="1", - ) - ), - skin=html.escape(cli_args.skin), - page_class=html.escape(escape_css_class(result["displaytitle"])), - title=html.escape(result["displaytitle"]), - indicators_html="\n".join([ - '
{}
'.format( - indicator["name"], indicator["*"] - ) for indicator in result["indicators"] - ]), - content_html=result["text"]["*"], - categories_html=result["categorieshtml"]["*"], + lang=html.escape(LANG), + text_dir=html.escape(LANG_TEXT_DIRECTION), + base_url=html.escape("{}://{}".format(site.scheme, site.host)), + page_modules_state_json=json_dumps_compact( + { + "noscript": "ready", + "user.options": "ready", + "user.tokens": "loading", + **{name: "ready" for name in MODULES_PRELOAD_STYLES[cli_args.skin]}, + } + ), + page_config_json=json_dumps_compact(result["jsconfigvars"]), + page_modules_json=json_dumps_compact( + get_modules(result["modules"], MODULES_POST_LOAD, MODULES_POST_LOAD_BLOCKED) + ), + style_url=html.escape( + get_load_script_url( + only="styles", + modules="|".join( + get_modules(result["modulestyles"], MODULES_PRELOAD_STYLES) + ), + ) + ), + script_url=html.escape( + get_load_script_url( + only="scripts", + modules="|".join( + get_modules(result["modulescripts"], MODULES_PRELOAD_SCRIPTS) + ), + raw="1", + ) + ), + skin=html.escape(cli_args.skin), + page_class=html.escape(escape_css_class(result["displaytitle"])), + title=html.escape(result["displaytitle"]), + indicators_html="\n".join( + [ + '
{}
'.format( + indicator["name"], indicator["*"] + ) + for indicator in result["indicators"] + ] + ), + content_html=result["text"]["*"], + categories_html=result["categorieshtml"]["*"], ) + with open(cli_args.output, "w") as f: - f.write(rendered_html) + f.write(rendered_html) diff --git a/scripts/onscreen-message b/scripts/onscreen-message index 32c3b5a..3ca6694 100755 --- a/scripts/onscreen-message +++ b/scripts/onscreen-message @@ -2,9 +2,8 @@ import gi import argparse - gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, Pango +from gi.repository import Gtk, Gdk, Pango # noqa: E402 parser = argparse.ArgumentParser() @@ -13,6 +12,7 @@ args = parser.parse_args() message = " ".join(args.message) + window = Gtk.ApplicationWindow() window.set_keep_above(True) window.set_decorated(False) @@ -25,17 +25,17 @@ window.add(scrolled_window) def on_key_release(target, event): - key = event.keyval - if key in [Gdk.KEY_Escape, Gdk.KEY_q, Gdk.KEY_Q]: - window.close() + key = event.keyval + if key in [Gdk.KEY_Escape, Gdk.KEY_q, Gdk.KEY_Q]: + window.close() def on_configure(target, event): - if target != window or event.type != Gdk.EventType.CONFIGURE: - return - font_desc = Pango.FontDescription() - font_desc.set_size(Pango.SCALE * event.height * 2 / 3) - label.override_font(font_desc) + if target != window or event.type != Gdk.EventType.CONFIGURE: + return + font_desc = Pango.FontDescription() + font_desc.set_size(Pango.SCALE * event.height * 2 / 3) + label.override_font(font_desc) window.connect("configure-event", on_configure) diff --git a/scripts/playerctl-simple-menu b/scripts/playerctl-simple-menu index f351bb4..3072017 100755 --- a/scripts/playerctl-simple-menu +++ b/scripts/playerctl-simple-menu @@ -9,162 +9,162 @@ import math import gi - gi.require_version("Playerctl", "2.0") gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") gi.require_version("Pango", "1.0") -from gi.repository import Playerctl, Gtk, Gdk, GLib, Pango +from gi.repository import Playerctl, Gtk, Gdk, GLib, Pango # noqa: E402 + # Larger priority values will make the player with this name appear higher in # the menu. The default priority is 0. PLAYER_NAME_PRIORITIES = { - "audacious": 2, - "mpv": 1, - "vlc": 1, - "firefox": -1, - "chrome": -2, - "chromium": -2, + "audacious": 2, + "mpv": 1, + "vlc": 1, + "firefox": -1, + "chrome": -2, + "chromium": -2, } PLAYER_ICON_NAME_FIXES = { - "chrome": "google-chrome", + "chrome": "google-chrome", } PLAYER_PLAYBACK_STATUS_EMOJIS = { - Playerctl.PlaybackStatus.PLAYING: "\u25B6", - Playerctl.PlaybackStatus.PAUSED: "\u23F8", - Playerctl.PlaybackStatus.STOPPED: "\u23F9", + Playerctl.PlaybackStatus.PLAYING: "\u25B6", + Playerctl.PlaybackStatus.PAUSED: "\u23F8", + Playerctl.PlaybackStatus.STOPPED: "\u23F9", } def humanize_duration(duration): - minutes, seconds = divmod(math.floor(duration), 60) - hours, minutes = divmod(minutes, 60) - text = "{:02}:{:02}".format(minutes, seconds) - if hours > 0: - text = "{}:{}".format(hours, text) - return text + minutes, seconds = divmod(math.floor(duration), 60) + hours, minutes = divmod(minutes, 60) + text = "{:02}:{:02}".format(minutes, seconds) + if hours > 0: + text = "{}:{}".format(hours, text) + return text def iter_metadata_entries_for_player(player): - metadata = player.props.metadata + metadata = player.props.metadata - title = metadata.lookup_value("xesam:title") - if title: - yield title.get_string() + title = metadata.lookup_value("xesam:title") + if title: + yield title.get_string() - album = metadata.lookup_value("xesam:album") - if album: - yield album.get_string() + album = metadata.lookup_value("xesam:album") + if album: + yield album.get_string() - if player.props.can_seek: - position_secs = player.props.position / 1e6 - duration = metadata.lookup_value("mpris:length") - if duration is not None and duration.is_of_type(GLib.VariantType.new("x")): - duration_secs = duration.get_int64() / 1e6 - yield "Time: {} / {}".format( - humanize_duration(position_secs), humanize_duration(duration_secs) - ) + if player.props.can_seek: + position_secs = player.props.position / 1e6 + duration = metadata.lookup_value("mpris:length") + if duration is not None and duration.is_of_type(GLib.VariantType.new("x")): + duration_secs = duration.get_int64() / 1e6 + yield "Time: {} / {}".format( + humanize_duration(position_secs), humanize_duration(duration_secs) + ) def iter_actions_for_player(player): - if not player.props.can_control: - yield ("This player can't be controlled!", None, False, None) - return + if not player.props.can_control: + yield ("This player can't be controlled!", None, False, None) + return - playback_status = player.props.playback_status - if playback_status == Playerctl.PlaybackStatus.PLAYING: + playback_status = player.props.playback_status + if playback_status == Playerctl.PlaybackStatus.PLAYING: + yield ( + "_Pause", + "media-playback-pause", + player.props.can_pause, + player.pause, + ) + elif playback_status == Playerctl.PlaybackStatus.PAUSED: + yield ( + "Resume (_P)", + "media-playback-start", + player.props.can_play, + player.play, + ) + elif playback_status == Playerctl.PlaybackStatus.STOPPED: + yield ( + "_Play", + "media-playback-start", + player.props.can_play, + player.play, + ) + + # See yield ( - "_Pause", - "media-playback-pause", - player.props.can_pause, - player.pause, - ) - elif playback_status == Playerctl.PlaybackStatus.PAUSED: - yield ( - "Resume (_P)", - "media-playback-start", - player.props.can_play, - player.play, - ) - elif playback_status == Playerctl.PlaybackStatus.STOPPED: - yield ( - "_Play", - "media-playback-start", - player.props.can_play, - player.play, + "_Stop", + "media-playback-stop", + player.props.can_play and playback_status != Playerctl.PlaybackStatus.STOPPED, + player.stop, ) - # See - yield ( - "_Stop", - "media-playback-stop", - player.props.can_play and playback_status != Playerctl.PlaybackStatus.STOPPED, - player.stop, - ) - - yield ( - "_Mute" if player.props.volume != 0.0 else "Nor_mal volume", - "audio-volume-muted" if player.props.volume != 0.0 else "audio-volume-high", - True, - lambda volume: player.set_volume(volume), - 0.0 if player.props.volume != 0.0 else 1.0, - ) - yield ( - "Volume +10%", - "audio-volume-medium", - True, - lambda: player.set_volume(min(player.props.volume + 0.1, 1.0)), - ) - yield ( - "Volume -10%", - "audio-volume-low", - True, - lambda: player.set_volume(max(player.props.volume - 0.1, 0.0)), - ) - - yield ( - "_Next", - "media-skip-forward", - player.props.can_go_next, - player.next, - ) - yield ( - "Previous (_B)", - "media-skip-backward", - player.props.can_go_previous, - player.previous, - ) - - shuffle = player.props.shuffle - yield ( - "Don't shuffle (_R)" if shuffle else "Shuffle (_R)", - "media-playlist-shuffle", - True, - lambda: player.set_shuffle(not shuffle), - ) - - loop_status = player.props.loop_status - for loop_action_name, loop_action_status in [ - ("Don't _loop", Playerctl.LoopStatus.NONE), - ("Loop _one", Playerctl.LoopStatus.TRACK), - ("Loop _all", Playerctl.LoopStatus.PLAYLIST), - ]: yield ( - loop_action_name, - "media-playlist-repeat", - loop_action_status != loop_status, - lambda loop_action_status: player.set_loop_status(loop_action_status), - loop_action_status, + "_Mute" if player.props.volume != 0.0 else "Nor_mal volume", + "audio-volume-muted" if player.props.volume != 0.0 else "audio-volume-high", + True, + lambda volume: player.set_volume(volume), + 0.0 if player.props.volume != 0.0 else 1.0, + ) + yield ( + "Volume +10%", + "audio-volume-medium", + True, + lambda: player.set_volume(min(player.props.volume + 0.1, 1.0)), + ) + yield ( + "Volume -10%", + "audio-volume-low", + True, + lambda: player.set_volume(max(player.props.volume - 0.1, 0.0)), ) - yield ( - "Play a_gain", - "go-first", - player.props.can_seek, - lambda: player.set_position(0), - ) + yield ( + "_Next", + "media-skip-forward", + player.props.can_go_next, + player.next, + ) + yield ( + "Previous (_B)", + "media-skip-backward", + player.props.can_go_previous, + player.previous, + ) + + shuffle = player.props.shuffle + yield ( + "Don't shuffle (_R)" if shuffle else "Shuffle (_R)", + "media-playlist-shuffle", + True, + lambda: player.set_shuffle(not shuffle), + ) + + loop_status = player.props.loop_status + for loop_action_name, loop_action_status in [ + ("Don't _loop", Playerctl.LoopStatus.NONE), + ("Loop _one", Playerctl.LoopStatus.TRACK), + ("Loop _all", Playerctl.LoopStatus.PLAYLIST), + ]: + yield ( + loop_action_name, + "media-playlist-repeat", + loop_action_status != loop_status, + lambda loop_action_status: player.set_loop_status(loop_action_status), + loop_action_status, + ) + + yield ( + "Play a_gain", + "go-first", + player.props.can_seek, + lambda: player.set_position(0), + ) root_menu = Gtk.Menu() @@ -172,84 +172,93 @@ root_menu = Gtk.Menu() player_names = Playerctl.list_players() if len(player_names) > 0: - players = [] - for player_name in player_names: - player = Playerctl.Player.new_from_name(player_name) - players.append({ - "player": - player, - "player_name": - player_name, - "sorting_key": ( - player.props.playback_status != Playerctl.PlaybackStatus.PLAYING, - -PLAYER_NAME_PRIORITIES.get(player_name.name, 0), - player_name.instance, - ), - }) - players = sorted(players, key=lambda player_and_meta: player_and_meta["sorting_key"]) - - for player_and_meta in players: - player_name = player_and_meta["player_name"] - player = player_and_meta["player"] - - player_menu_item = Gtk.ImageMenuItem.new_with_label( - "{} [{}]".format( - player_name.instance, - PLAYER_PLAYBACK_STATUS_EMOJIS[player.props.playback_status], - ) + players = [] + for player_name in player_names: + player = Playerctl.Player.new_from_name(player_name) + players.append( + { + "player": player, + "player_name": player_name, + "sorting_key": ( + player.props.playback_status != Playerctl.PlaybackStatus.PLAYING, + -PLAYER_NAME_PRIORITIES.get(player_name.name, 0), + player_name.instance, + ), + } + ) + players = sorted( + players, key=lambda player_and_meta: player_and_meta["sorting_key"] ) - player_icon_name = PLAYER_ICON_NAME_FIXES.get(player_name.name, player_name.name) - player_icon = Gtk.Image.new_from_icon_name(player_icon_name, Gtk.IconSize.MENU) - player_menu_item.set_image(player_icon) + for player_and_meta in players: + player_name = player_and_meta["player_name"] + player = player_and_meta["player"] - actions_menu = Gtk.Menu() - - track_metadata = player.props.metadata - any_metadata_was_added = False - for meta_entry_text in iter_metadata_entries_for_player(player): - meta_menu_item = Gtk.MenuItem.new_with_label(meta_entry_text) - meta_menu_item.set_sensitive(False) - meta_menu_item_label = meta_menu_item.get_child() - meta_menu_item_label.set_ellipsize(Pango.EllipsizeMode.END) - meta_menu_item_label.set_max_width_chars(20) - - actions_menu.append(meta_menu_item) - any_metadata_was_added = True - - if any_metadata_was_added: - actions_menu.append(Gtk.SeparatorMenuItem.new()) - - for ( - action_name, - action_icon_name, - action_enabled, - action_fn, - *action_fn_args, - ) in iter_actions_for_player(player): - action_menu_item = Gtk.ImageMenuItem.new_with_mnemonic(action_name) - - if action_icon_name is not None: - action_icon = Gtk.Image.new_from_icon_name(action_icon_name, Gtk.IconSize.MENU) - action_menu_item.set_image(action_icon) - - action_menu_item.set_sensitive(action_enabled) - if action_fn is not None: - action_menu_item.connect( - "activate", - lambda _menu_item, action_fn, action_fn_args: action_fn(*action_fn_args), - action_fn, - action_fn_args, + player_menu_item = Gtk.ImageMenuItem.new_with_label( + "{} [{}]".format( + player_name.instance, + PLAYER_PLAYBACK_STATUS_EMOJIS[player.props.playback_status], + ) ) - actions_menu.append(action_menu_item) + player_icon_name = PLAYER_ICON_NAME_FIXES.get( + player_name.name, player_name.name + ) + player_icon = Gtk.Image.new_from_icon_name(player_icon_name, Gtk.IconSize.MENU) + player_menu_item.set_image(player_icon) - player_menu_item.set_submenu(actions_menu) - root_menu.append(player_menu_item) + actions_menu = Gtk.Menu() + + track_metadata = player.props.metadata + any_metadata_was_added = False + for meta_entry_text in iter_metadata_entries_for_player(player): + meta_menu_item = Gtk.MenuItem.new_with_label(meta_entry_text) + meta_menu_item.set_sensitive(False) + meta_menu_item_label = meta_menu_item.get_child() + meta_menu_item_label.set_ellipsize(Pango.EllipsizeMode.END) + meta_menu_item_label.set_max_width_chars(20) + + actions_menu.append(meta_menu_item) + any_metadata_was_added = True + + if any_metadata_was_added: + actions_menu.append(Gtk.SeparatorMenuItem.new()) + + for ( + action_name, + action_icon_name, + action_enabled, + action_fn, + *action_fn_args, + ) in iter_actions_for_player(player): + action_menu_item = Gtk.ImageMenuItem.new_with_mnemonic(action_name) + + if action_icon_name is not None: + action_icon = Gtk.Image.new_from_icon_name( + action_icon_name, Gtk.IconSize.MENU + ) + action_menu_item.set_image(action_icon) + + action_menu_item.set_sensitive(action_enabled) + if action_fn is not None: + action_menu_item.connect( + "activate", + lambda _menu_item, action_fn, action_fn_args: action_fn( + *action_fn_args + ), + action_fn, + action_fn_args, + ) + + actions_menu.append(action_menu_item) + + player_menu_item.set_submenu(actions_menu) + root_menu.append(player_menu_item) else: - menu_item = Gtk.MenuItem.new_with_label("No players were detected!") - menu_item.set_sensitive(False) - root_menu.append(menu_item) + menu_item = Gtk.MenuItem.new_with_label("No players were detected!") + menu_item.set_sensitive(False) + root_menu.append(menu_item) + root_menu.connect("selection-done", Gtk.main_quit) root_menu.connect("deactivate", Gtk.main_quit) diff --git a/scripts/query-bookmarks b/scripts/query-bookmarks index fa3867f..1e8db42 100755 --- a/scripts/query-bookmarks +++ b/scripts/query-bookmarks @@ -16,31 +16,35 @@ import shutil import sqlite3 from typing import Optional, Tuple, Generator - sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources")) import common_script_utils + if sys.platform == "darwin": - firefox_home: Path = Path.home() / "Library" / "Application Support" / "Firefox" + firefox_home: Path = Path.home() / "Library" / "Application Support" / "Firefox" elif os.name == "posix": - firefox_home: Path = Path.home() / ".mozilla" / "firefox" + firefox_home: Path = Path.home() / ".mozilla" / "firefox" else: - common_script_utils.platform_not_supported_error() + common_script_utils.platform_not_supported_error() + profiles_config = ConfigParser(interpolation=None) profiles_config.read(firefox_home / "profiles.ini") -installs_sections: list[str] = [s for s in profiles_config.sections() if s.startswith("Install")] +installs_sections: list[str] = [ + s for s in profiles_config.sections() if s.startswith("Install") +] if not installs_sections: - raise Exception("no Firefox installations detected!") + raise Exception("no Firefox installations detected!") if len(installs_sections) > 1: - raise Exception("multiple Firefox installations are not supported!") + raise Exception("multiple Firefox installations are not supported!") profile_dir: Path = firefox_home / profiles_config.get(installs_sections[0], "Default") # should places.sqlite be used instead? db_path: Path = profile_dir / "weave" / "bookmarks.sqlite" if not db_path.is_file(): - raise Exception("'{}' is not a file".format(db_path)) + raise Exception("'{}' is not a file".format(db_path)) + # Firefox holds a lock over the database file, so I can't connect to it even # in the readonly mode: https://stackoverflow.com/a/7857866/12005228 @@ -51,74 +55,78 @@ os.close(db_copy_fd) chooser_entries: list[Tuple[str, str, Optional[str]]] = [] try: - shutil.copyfile(db_path, db_copy_path) - db = sqlite3.connect(db_copy_path) + shutil.copyfile(db_path, db_copy_path) + db = sqlite3.connect(db_copy_path) - urls: dict[int, str] = {} - url_id: int - url: str - for url_id, url in db.execute("SELECT id, url FROM urls"): - urls[url_id] = url + urls: dict[int, str] = {} + url_id: int + url: str + for url_id, url in db.execute("SELECT id, url FROM urls"): + urls[url_id] = url - folders: dict[str, Tuple[Optional[str], str]] = {} - folder_id: str - parent_folder_id: str - folder_title: str - for folder_id, parent_folder_id, folder_title in db.execute( - "SELECT guid, parentGuid, title FROM items WHERE kind = 3 AND validity AND NOT isDeleted" - ): - folders[folder_id] = ( - parent_folder_id if parent_folder_id != folder_id else None, - folder_title, - ) + folders: dict[str, Tuple[Optional[str], str]] = {} + folder_id: str + parent_folder_id: str + folder_title: str + for folder_id, parent_folder_id, folder_title in db.execute( + "SELECT guid, parentGuid, title FROM items WHERE kind = 3 AND validity AND NOT isDeleted" + ): + folders[folder_id] = ( + parent_folder_id if parent_folder_id != folder_id else None, + folder_title, + ) - url_title: str - url_id: int - url_keyword: str - parent_folder_id: str - for url_title, url_id, url_keyword, parent_folder_id in db.execute( - "SELECT title, urlId, keyword, parentGuid FROM items WHERE kind = 1 AND validity AND NOT isDeleted" - ): - url = urls[url_id] + url_title: str + url_id: int + url_keyword: str + parent_folder_id: str + for url_title, url_id, url_keyword, parent_folder_id in db.execute( + "SELECT title, urlId, keyword, parentGuid FROM items WHERE kind = 1 AND validity AND NOT isDeleted" + ): + url = urls[url_id] - folder_path = list[str]() - parent_folder_id_2: Optional[str] = parent_folder_id - while parent_folder_id_2 is not None: - folder = folders.get(parent_folder_id_2, None) - if folder is None: - # broken folder structure? - folder_path.clear() - break - parent_folder_id_2, folder_title = folder - if folder_title is not None: - folder_path.append(folder_title) + folder_path = list[str]() + parent_folder_id_2: Optional[str] = parent_folder_id + while parent_folder_id_2 is not None: + folder = folders.get(parent_folder_id_2, None) + if folder is None: + # broken folder structure? + folder_path.clear() + break + parent_folder_id_2, folder_title = folder + if folder_title is not None: + folder_path.append(folder_title) - folder_path_str = (("/" + "/".join(reversed(folder_path))) if len(folder_path) > 0 else None) + folder_path_str = ( + ("/" + "/".join(reversed(folder_path))) if len(folder_path) > 0 else None + ) - chooser_entries.append((url_title, url, folder_path_str)) - if url_keyword is not None: - chooser_entries.append((url_keyword, url, folder_path_str)) + chooser_entries.append((url_title, url, folder_path_str)) + if url_keyword is not None: + chooser_entries.append((url_keyword, url, folder_path_str)) finally: - os.remove(db_copy_path) + os.remove(db_copy_path) def chooser_entries_iter() -> Generator[str, None, None]: - for title, url, folder_path_str in chooser_entries: - entry_items = [title, url] - if folder_path_str is not None: - entry_items.append(folder_path_str) - entry = " \u2014\u2014 ".join(entry_items) - yield entry + for title, url, folder_path_str in chooser_entries: + entry_items = [title, url] + if folder_path_str is not None: + entry_items.append(folder_path_str) + entry = " \u2014\u2014 ".join(entry_items) + yield entry -chosen_index = common_script_utils.run_chooser(chooser_entries_iter(), prompt="bookmark") +chosen_index = common_script_utils.run_chooser( + chooser_entries_iter(), prompt="bookmark" +) if chosen_index >= 0: - _title, url, _folder_path_str = chooser_entries[chosen_index] - print(url) + _title, url, _folder_path_str = chooser_entries[chosen_index] + print(url) - common_script_utils.set_clipboard(url) - common_script_utils.send_notification( - os.path.basename(__file__), "bookmark URL copied to clipboard!", url - ) + common_script_utils.set_clipboard(url) + common_script_utils.send_notification( + os.path.basename(__file__), "bookmark URL copied to clipboard!", url + ) diff --git a/scripts/random-local-ipv4 b/scripts/random-local-ipv4 index a72180c..dbf02a4 100755 --- a/scripts/random-local-ipv4 +++ b/scripts/random-local-ipv4 @@ -1,10 +1,10 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python import random def randbyte() -> int: - return random.randrange(0, 256) + return random.randrange(0, 256) print("127.{}.{}.{}".format(randbyte(), randbyte(), randbyte())) diff --git a/zsh/completions/_keybase b/zsh/completions/_keybase deleted file mode 100644 index 7ab54f5..0000000 --- a/zsh/completions/_keybase +++ /dev/null @@ -1,359 +0,0 @@ -#compdef keybase -#autoload - -# keybase completion, based on cli help text -# https://github.com/fnoris/keybase-zsh-completion - -# The MIT License (MIT) -# -# Copyright (c) 2014 David Tiersch -# -# 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. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - - -local curcontext="$curcontext" state line ret=1 -local -a _command_args -local -a _global_args -local -a _subcommands - -local IFS=$'\n' -_global_args=($(keybase advanced | grep '^\s*--' | sed -r 's/^[\t ]*(--[^\t ,]+)( [^\t ,]*)?,? ?(--?[^\t ]+)?[\t ]*(.*)$/(\3)\1[\4]/')) - -_arguments -C -A "-v" -A "--version"\ - '(- 1 *)'{-v,--version}'[display version information]' \ - '1: :->cmds' \ - $_global_args \ - '*:: :->args' && ret=0 - -case $state in - cmds) - _subcommands=( - "base62:base62 operations" - "cert:print the CA cert for api.keybase.io" - "chat:chat securely with keybase users" - "ctl:control the background keybase service" - "currency:manage cyrptocurrency address" - "decrypt:decrypt messages or files for keybase users" - "deprovision:revoke the current device, log out, and delete local state" - "device:manage your devices" - "dump-keyfamily:print out a user's current key family" - "encrypt:encrypt messages or files for keybase users" - "follow:verify a user's authenticity and optionally follow them" - "track:verify a user's authenticity and optionally follow them" - "fs:perform filesystem operations" - "id:identify a user and check their signature chain" - "list-followers:list thost who follow you" - "list-following:list who you or the given user is following" - "log:manage keybase log" - "login:establish a session with the keybase server" - "logout:logout and remove session information" - "paperkey:generate paper keys for recovering your account" - "passphrase:change or recover your keybase passphrase" - "pgp:manage keybase PGP keys" - "ping:ping the keybase API server" - "prove:generate a new proof" - "rekey:rekey status and actions" - "search:search for keybase users" - "sign:sign a document" - "signup:signup for a new account" - "sigs:manage signatures" - "status:show information about current user" - "unfollow:unfollow a user" - "untrack:unfollow a user" - "update:the updater" - "verify:verify message or file signatures for keybase users" - "version:print out version and build information" - "help, h:shows a list fo commands or help for one command" - ) - _describe -t subcommands 'Keybase subcommands' _subcommands && ret=0 - ;; - args) - case $line[1] in - help) - _values 'commands' \ - 'base62' \ - 'cert' \ - 'chat' \ - 'ctl' \ - 'currency' \ - 'decrypt' \ - 'deprovision' \ - 'device' \ - 'dump-keyfamily' \ - 'encrypt' \ - 'follow' \ - 'track' \ - 'fs' \ - 'id' \ - 'list-followers' \ - 'list-following' \ - 'log' \ - 'login' \ - 'logout' \ - 'paperkey' \ - 'pasphrase' \ - 'pgp' \ - 'ping' \ - 'prove' \ - 'rekey' \ - 'search' \ - 'sign' \ - 'signup' \ - 'sigs' \ - 'status' \ - 'unfollow' \ - 'untrack' \ - 'update' \ - 'verify' \ - 'version' \ - 'help, h' && ret=0 - ;; - base62) - _values "command" \ - 'decode[base62 decode]' \ - 'encode[base62 encode]' \ - 'help[Shows a list of commands or help for one command]' - ;; - chat) - _values "command" \ - 'api[JSON api]' \ - 'download[Download an attachment from a conversation]' \ - 'hide[Hide or block a conversation]' \ - 'list[List conversations, sorted by activity]' \ - 'ls[List conversations, sorted by activity]' \ - "list-unread[List conversations, with unread messages at the top]" \ - "lsur[List conversations, with unread messages at the top]" \ - 'mute[Mute or unmute a conversation]' \ - 'read[Show new messages in a conversation and mark them as read]' \ - 'report[Report a conversation (also blocks it)]' \ - 'send[Send a message to a conversation]' \ - 'upload[Upload an attachment to a conversation]' \ - 'help[Shows a list of commands or help for one command]' - ;; - ctl) - _values "command" \ - 'start[Start the backgroung keybase service]' \ - 'stop[Stop the backgroung keybase service]' \ - 'reload[Reload config file]' \ - 'restart[Restart the background keybase service]' \ - "log-rotate[Close and open the keybase service's log file]" \ - 'watchdog[Start, watch and prop up the backgound service]' \ - 'watchdog2[Start and monitor background services]' \ - 'app-exit[Exit the Keybase app]' \ - 'help[Shows a list of commands or help for one command]' - ;; - currency) - _values "command" \ - 'add[Sign a cryptocurrency (bitcoin or zcash) address into your identity]' \ - 'help[Shows a list of commands or help for one command]' - ;; - decrypt) - _command_args=( - '(--infile)--infile[Specify an input file]' \ - '(--message)--message[Provide the message on the command line]' \ - '(--outfile)--outfile[Specify an outfile (stdout by default)]' \ - '(--interactive)--interactive[Interactive prompt for decryption after sender verification]' \ - '(--force)--force[Force unprompted decryption, even on an indentify failure]' \ - '(--paperkey)--paperkey[Use a paper key for decryption]' \ - '(--encryptor-outfile)--encryptor-outfile[Write the Keybase name of the encryptor to this file]' - ) - ;; - device) - _values "command" \ - 'remove[Remove a device]' \ - 'list[List devices]' \ - 'add[Authorize a new device]' \ - 'help[Shows a list of commands or help for one command]' - ;; - encrypt) - _command_args=( - '(--binary)--binary[Output in binary (rather than ASCII/armored)]' \ - '(--infile)--infile[Specify an input file]' \ - '(message)--message[Provide the message on the command line]' \ - '(--outfile)--outfile[Specify an outfile (stdout by default)]' \ - "(--hide-recipients)--hide-recipients[Don't include recipients in metadata]" \ - "(--anonymous)--anonymous[Don't include sender or recipients in metadata. Implies --hide-recipients]" \ - "(--no-self)--no-self[Don't encrypt for yourself]" - ) - ;; - follow) - _command_args=( - "(--local)--local[Only follow locally, don't send a public statement to the server]" \ - '(-y)-y[Approve remote following without prompting]' \ - '(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]' - ) - ;; - track) - _command_args=( - "(--local)--local[Only follow locally, don't send a public statement to the server]" \ - '(-y)-y[Approve remote following without prompting]' \ - '(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]' - ) - ;; - fs) - _values "command" \ - 'ls[list directory contents]' \ - 'cp[copy one or more directory elements to dest]' \ - 'mv[move one or more directory elements to dest]' \ - 'read[output file contents to standard output]' \ - 'rm[remove one or more directory elements]' \ - 'mkdir[create directory]' \ - 'stat[stat directory element]' \ - 'get-status[get status of pending operation]' \ - 'kill[kill operation]' \ - 'ps[list running operations]' \ - 'write[write input to file]' \ - 'help[Shows a list of commands or help for one command]' - ;; - id) - _command_args=( - '(--skip-proof-cache)--skip-proof-cache[Skip cached proofs, force re-check]' - ) - ;; - list-followers) - _command_args=( - '(--verbose)--verbose[A full dump, with more gory details]' - ) - ;; - list-following) - _command_args=( - '(--filter)--filter[Provide a regex filter]' \ - '(--headers)--headers[Show column headers]' \ - '(--json)--json[Output as JSON (default is text)]' \ - '(--verbose)--verbose[A full dump, with more gory details]' - ) - ;; - log) - _values "command" \ - 'send[Send recent debug logs to keybase]' \ - 'help[Shows a list of commands or help for one command]' - ;; - login) - _command_args=( - '(--provision-by-email)--provision-by-email[Use an email address associated with a keybase account to provision a device]' - ) - ;; - passphrase) - _values "command" \ - 'change[Change your keybase account passphrase]' \ - 'recover[Recover your keybase account passphrase]' \ - 'help[Shows a list of commands or help for one command]' - ;; - pgp) - _values "command" \ - 'gen[Generate a new PGP key and write to local secret keychain]' \ - 'pull[Download the latest PGP keys for people you track]' \ - 'update[Update your public PGP keys on keybase with those exported from the local GPG keyring]' \ - 'select[Select a key as your own and register the public half with the server]' \ - 'sign[PGP sign a document]' \ - 'encrypt[PGP encrypt messages or files for keybase users]' \ - 'decrypt[PGP decrypt messages or files for keybase users]' \ - 'verify[PGP verify message or file signatures for keybase users]' \ - 'export[Export a PGP key from keybase]' \ - 'import[Import a PGP key into keybase]' \ - 'drop[Drop Keybases use of a PGP key]' \ - 'list[List the active PGP keys in your account]' \ - 'purge[Purge all PGP keys from Keybase keyring]' \ - 'help[Shows a list of commands or help for one command]' - ;; - ping) - _command_args=( - '(--gregor)--gregor[Ping the Gregor server]' - ) - ;; - prove) - _command_args=( - '(--output)--output[Output proof text to file (rather than standard out)]' \ - "(--force)--force[Don't prompt]" \ - ) - _values "prove command" \ - 'service[Supported services are: coinbase, hackernews, reddit, dns, github, twitter, web, http, https]' \ - 'service username[Username or hostname at that service]' - ;; - rekey) - _values "command" \ - 'status[Get pending rekey status]' \ - 'paper[Submit a paper key to help rekeying]' \ - 'help[Shows a list of commands or help for one command]' - ;; - search) - _command_args=( - '(--json)--json[Output as JSON]' - ) - ;; - sign) - _command_args=( - '(--binary)--binary[Output binary message (default is armored)]' \ - '(--detached)--detached[Detached signature (default is attached)]' \ - '(--infile)--infile[Specify an input file]' \ - '(--message)--message[Provide the message to sign on the command line]' \ - '(--outfile)--outfile[Specify an outfile (default is STDOUT)]' - ) - ;; - signup) - _command_args=( - '(--invite-code)--invite-code[Specify an invite code]' \ - '(--email)--email[Specify an account email]' \ - '(--username)--username[Specify a username]' - ) - ;; - sigs) - _values "command" \ - 'list[List signatures]' \ - 'revoke[Revoke a signature by sig ID]' \ - 'help[Shows a list of commands or help for one command]' - ;; - status) - _command_args=( - '(--json)--json[Output status as JSON]' \ - ) - ;; - update) - _values "command" \ - 'check[Trigger an update check]' \ - 'run[Run the update with custom options]' \ - 'check-in-use[Check if we are in use (safe for restart)]' \ - 'notify[Notify the service about an update event]' - ;; - verify) - _command_args=( - '(--detached)--detached[Specify a detached signature file]' \ - '(--infile)--infile[Specify an input file]' \ - '(--message)--message[Provide the message to verify on the command line]' \ - "(--no-output)--no-output[Don't output the verified message]" \ - '(--outfile)--outfile[Specify an outfile (default is STDOUT)]' - '(--signed-by)--signed-by[Assert signed by the given user (can use user assertion fomat)]' \ - ) - ;; - version) - _command_args=( - "(--format)--format[Alternate format for version output. Specify 's' for simple (1.2.3) or 'v' for verbose. Default (blank) includes build number (1.2.3-400)]" \ - "(--no-service)--no-service[Don't report on the service's build information]" - ) - ;; - esac - ;; -esac - -_arguments \ - $_command_args \ - && ret=0 - -return ret -s