mirror of
https://github.com/keanuplayz/dotfiles.git
synced 2024-08-15 02:33:12 +00:00
Merge pull request #277 from dmitmel/master
[pull] master from dmitmel:master
This commit is contained in:
commit
043d991aff
23 changed files with 197 additions and 141 deletions
|
@ -3,8 +3,7 @@
|
|||
import json
|
||||
import os
|
||||
from abc import abstractmethod
|
||||
from typing import Dict, Iterable, List, Protocol, TextIO, runtime_checkable
|
||||
|
||||
from typing import Dict, Iterator, List, Protocol, TextIO, runtime_checkable
|
||||
|
||||
__dir__ = os.path.dirname(__file__)
|
||||
|
||||
|
@ -12,16 +11,20 @@ __dir__ = os.path.dirname(__file__)
|
|||
class Color:
|
||||
|
||||
def __init__(self, r: int, g: int, b: int) -> None:
|
||||
assert 0 <= r <= 0xff
|
||||
assert 0 <= g <= 0xff
|
||||
assert 0 <= b <= 0xff
|
||||
if not (0 <= r <= 0xff):
|
||||
raise Exception("r component out of range")
|
||||
if not (0 <= g <= 0xff):
|
||||
raise Exception("g component out of range")
|
||||
if not (0 <= b <= 0xff):
|
||||
raise Exception("b component out of range")
|
||||
self.r = r
|
||||
self.g = g
|
||||
self.b = b
|
||||
|
||||
@classmethod
|
||||
def from_hex(cls, s: str) -> "Color":
|
||||
assert len(s) == 6
|
||||
if len(s) != 6:
|
||||
raise Exception("hex color string must be 6 characters long")
|
||||
return Color(int(s[0:2], 16), int(s[2:4], 16), int(s[4:6], 16))
|
||||
|
||||
@property
|
||||
|
@ -42,7 +45,7 @@ class Color:
|
|||
else:
|
||||
raise IndexError("color component index out of range")
|
||||
|
||||
def __iter__(self) -> Iterable[int]:
|
||||
def __iter__(self) -> Iterator[int]:
|
||||
yield self.r
|
||||
yield self.g
|
||||
yield self.b
|
||||
|
@ -296,10 +299,6 @@ class ThemeGeneratorXfceTerminal(ThemeGenerator):
|
|||
|
||||
class ThemeGeneratorVscode(ThemeGenerator):
|
||||
|
||||
def file_name(self) -> str:
|
||||
return "vscode-colorCustomizations.json"
|
||||
|
||||
def generate(self, theme: Theme, output: TextIO) -> None:
|
||||
ANSI_COLOR_NAMES = [
|
||||
"Black",
|
||||
"Red",
|
||||
|
@ -311,6 +310,11 @@ class ThemeGeneratorVscode(ThemeGenerator):
|
|||
"White",
|
||||
]
|
||||
|
||||
def file_name(self) -> str:
|
||||
return "vscode-colorCustomizations.json"
|
||||
|
||||
def generate(self, theme: Theme, output: TextIO) -> None:
|
||||
|
||||
colors: Dict[str, str] = {
|
||||
"terminal.background": theme.bg.css_hex,
|
||||
"terminal.foreground": theme.fg.css_hex,
|
||||
|
@ -320,8 +324,8 @@ class ThemeGeneratorVscode(ThemeGenerator):
|
|||
}
|
||||
|
||||
for is_bright in [False, True]:
|
||||
for color_index, color_name in enumerate(ANSI_COLOR_NAMES):
|
||||
color = theme.ansi_colors[color_index + int(is_bright) * len(ANSI_COLOR_NAMES)]
|
||||
for color_index, color_name in enumerate(self.ANSI_COLOR_NAMES):
|
||||
color = theme.ansi_colors[color_index + int(is_bright) * len(self.ANSI_COLOR_NAMES)]
|
||||
colors["terminal.ansi" + ("Bright" if is_bright else "") + color_name] = color.css_hex
|
||||
|
||||
json.dump(colors, output, ensure_ascii=False, indent=2)
|
||||
|
@ -341,7 +345,7 @@ class ThemeGeneratorIterm(ThemeGenerator):
|
|||
output.write('<plist version="1.0">\n')
|
||||
output.write("<dict>\n")
|
||||
|
||||
def write_color(key_name, color):
|
||||
def write_color(key_name: str, color: Color) -> None:
|
||||
r, g, b = (float(component) / 0xff for component in color)
|
||||
output.write(" <key>{} Color</key>\n".format(key_name))
|
||||
output.write(" <dict>\n")
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"root": "scripts",
|
||||
"extraPaths": ["script-resources"]
|
||||
},
|
||||
{
|
||||
"root": "script-resources/welcome",
|
||||
"extraPaths": ["script-resources/welcome"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,27 @@
|
|||
[flake8]
|
||||
|
||||
select =
|
||||
# <https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes>
|
||||
E W
|
||||
# <https://flake8.pycqa.org/en/latest/user/error-codes.html#error-violation-codes>
|
||||
F
|
||||
# <https://github.com/zheller/flake8-quotes#warnings>
|
||||
Q0
|
||||
# <https://github.com/sco1/flake8-annotations#table-of-warnings>
|
||||
ANN
|
||||
# <https://github.com/PyCQA/pep8-naming#error-codes>
|
||||
N8
|
||||
# <https://github.com/gforcada/flake8-isort#error-codes>
|
||||
I0
|
||||
# <https://github.com/PyCQA/flake8-commas/>
|
||||
C8
|
||||
# <https://bandit.readthedocs.io/en/latest/plugins/index.html#complete-test-plugin-listing>
|
||||
S
|
||||
|
||||
# Also see this:
|
||||
# <https://github.com/wemake-services/wemake-python-styleguide>
|
||||
# <https://wemake-python-stylegui.de/en/latest/pages/usage/violations/index.html>
|
||||
|
||||
ignore =
|
||||
# Indent is not a multiple of 4
|
||||
E111
|
||||
|
@ -13,8 +36,17 @@ ignore =
|
|||
# Line too long
|
||||
E501
|
||||
# `except` without an exception type
|
||||
E722
|
||||
# NOTE: write `except Exception` (or `except BaseException` if absolutely
|
||||
# necessary) instead
|
||||
# E722
|
||||
# Newline before a binary operator
|
||||
W503
|
||||
# Newline after a binary operator
|
||||
W504
|
||||
|
||||
# Missing type annotations for `self` and `cls` respectively
|
||||
ANN101 ANN102
|
||||
|
||||
inline-quotes = "
|
||||
multiline-quotes = "
|
||||
docstring-quotes = "
|
||||
|
|
|
@ -3,7 +3,6 @@ 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Iterable, NoReturn
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# <https://www.devdungeon.com/content/working-binary-data-python>
|
||||
|
||||
import struct
|
||||
from typing import Any, IO
|
||||
from typing import IO, Any
|
||||
|
||||
|
||||
def read_bool(buf: IO[bytes]) -> bool:
|
||||
|
|
|
@ -2,7 +2,7 @@ from math import *
|
|||
from fractions import Fraction
|
||||
|
||||
|
||||
def factors(n):
|
||||
def factors(n: int) -> "set[int]":
|
||||
result = set()
|
||||
for i in range(1, int(sqrt(n)) + 1):
|
||||
if n % i == 0:
|
||||
|
@ -11,7 +11,7 @@ def factors(n):
|
|||
return result
|
||||
|
||||
|
||||
def solve_quadratic(a, b, c):
|
||||
def solve_quadratic(a: int, b: int, c: int) -> None:
|
||||
if a == 0:
|
||||
raise Exception("not a quadratic equation")
|
||||
else:
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
from typing import List
|
||||
|
||||
from colorama import Fore, Style, ansi
|
||||
|
||||
|
||||
COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
|
||||
COLORS: List[str] = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
|
||||
|
||||
|
||||
def colored(string, *colors):
|
||||
def colored(string: str, *colors: str) -> str:
|
||||
return "".join(colors + (string, Style.RESET_ALL))
|
||||
|
||||
|
||||
def bright_colored(string, *colors):
|
||||
def bright_colored(string: str, *colors: str) -> str:
|
||||
return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL))
|
||||
|
||||
|
||||
def colorize_percent(percent, warning, critical, inverse=False):
|
||||
COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED]
|
||||
def colorize_percent(
|
||||
percent: float, warning: float, critical: float, inverse: bool = False
|
||||
) -> str:
|
||||
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
|
||||
|
||||
return colored("%.2f%%" % percent, COLORS[color_index])
|
||||
return colored("%.2f%%" % percent, colors[color_index])
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
def humanize_timedelta(timedelta):
|
||||
result = []
|
||||
from datetime import timedelta
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
def humanize_timedelta(timedelta: timedelta) -> str:
|
||||
result: List[str] = []
|
||||
|
||||
days = timedelta.days
|
||||
mm, ss = divmod(timedelta.seconds, 60)
|
||||
hh, mm = divmod(mm, 60)
|
||||
|
||||
def plural(n):
|
||||
def plural(n: int) -> Tuple[int, str]:
|
||||
return n, "s" if abs(n) != 1 else ""
|
||||
|
||||
if days > 0:
|
||||
|
@ -20,7 +24,7 @@ def humanize_timedelta(timedelta):
|
|||
return ", ".join(result)
|
||||
|
||||
|
||||
def humanize_bytes(bytes):
|
||||
def humanize_bytes(bytes: int) -> str:
|
||||
units = ["B", "kB", "MB", "GB"]
|
||||
|
||||
factor = 1
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -3,17 +3,17 @@ import platform
|
|||
import socket
|
||||
from datetime import datetime, timedelta
|
||||
from getpass import getuser
|
||||
from typing import Dict, List, Optional, Tuple, cast
|
||||
|
||||
import psutil
|
||||
|
||||
from colors import Fore, Style, bright_colored, colored, colorize_percent
|
||||
from humanize import humanize_bytes, humanize_timedelta
|
||||
|
||||
|
||||
def get_system_info():
|
||||
info_lines = []
|
||||
def get_system_info() -> Tuple[List[str], List[str]]:
|
||||
info_lines: List[str] = []
|
||||
|
||||
def info(name, value, *format_args):
|
||||
def info(name: str, value: str, *format_args) -> None:
|
||||
line = bright_colored(name + ":", Fore.YELLOW) + " " + value
|
||||
if format_args:
|
||||
line = line % format_args
|
||||
|
@ -66,27 +66,27 @@ def get_system_info():
|
|||
return logo_lines, info_lines
|
||||
|
||||
|
||||
def _get_hostname():
|
||||
def _get_hostname() -> str:
|
||||
hostname = socket.gethostname()
|
||||
return hostname
|
||||
|
||||
|
||||
def _get_uptime():
|
||||
def _get_uptime() -> timedelta:
|
||||
return datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
||||
|
||||
|
||||
def _get_users():
|
||||
users = {}
|
||||
def _get_users() -> str:
|
||||
users: Dict[str, List[str]] = {}
|
||||
|
||||
for user in psutil.users():
|
||||
name = user.name
|
||||
terminal = user.terminal
|
||||
name: str = user.name
|
||||
terminal: str = user.terminal
|
||||
if name in users:
|
||||
users[name].append(terminal)
|
||||
else:
|
||||
users[name] = [terminal]
|
||||
|
||||
result = []
|
||||
result: List[str] = []
|
||||
|
||||
for name in users:
|
||||
terminals = users[name]
|
||||
|
@ -102,13 +102,13 @@ def _get_users():
|
|||
return ", ".join(result)
|
||||
|
||||
|
||||
def _get_shell():
|
||||
def _get_shell() -> Optional[str]:
|
||||
return os.environ.get("SHELL")
|
||||
|
||||
|
||||
def _get_cpu_usage():
|
||||
def _get_cpu_usage() -> Optional[str]:
|
||||
try:
|
||||
percent = psutil.cpu_percent()
|
||||
percent = cast(float, psutil.cpu_percent())
|
||||
except Exception as e:
|
||||
print("Error in _get_cpu_usage:", e)
|
||||
return None
|
||||
|
@ -116,7 +116,7 @@ def _get_cpu_usage():
|
|||
return colorize_percent(percent, warning=60, critical=80)
|
||||
|
||||
|
||||
def _get_memory():
|
||||
def _get_memory() -> Tuple[str, str, str]:
|
||||
memory = psutil.virtual_memory()
|
||||
return (
|
||||
humanize_bytes(memory.used),
|
||||
|
@ -125,8 +125,8 @@ def _get_memory():
|
|||
)
|
||||
|
||||
|
||||
def _get_disks():
|
||||
result = []
|
||||
def _get_disks() -> List[Tuple[str, str, str, str]]:
|
||||
result: List[Tuple[str, str, str, str]] = []
|
||||
|
||||
for disk in psutil.disk_partitions(all=False):
|
||||
if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""):
|
||||
|
@ -146,7 +146,7 @@ def _get_disks():
|
|||
return result
|
||||
|
||||
|
||||
def _get_battery():
|
||||
def _get_battery() -> Optional[Tuple[str, str]]:
|
||||
if not hasattr(psutil, "sensors_battery"):
|
||||
return None
|
||||
|
||||
|
@ -167,8 +167,8 @@ def _get_battery():
|
|||
return colorize_percent(percent, critical=10, warning=20, inverse=True), status
|
||||
|
||||
|
||||
def _get_local_ipv4_addresses():
|
||||
result = []
|
||||
def _get_local_ipv4_addresses() -> List[Tuple[str, str]]:
|
||||
result: List[Tuple[str, str]] = []
|
||||
|
||||
for interface, addresses in psutil.net_if_addrs().items():
|
||||
for address in addresses:
|
||||
|
@ -184,7 +184,7 @@ def _get_local_ipv4_addresses():
|
|||
return result
|
||||
|
||||
|
||||
def _get_distro_info():
|
||||
def _get_distro_info() -> Tuple[str, str, str, str]:
|
||||
if psutil.WINDOWS:
|
||||
return "windows", platform.system(), platform.release(), ""
|
||||
elif psutil.OSX:
|
||||
|
@ -194,9 +194,13 @@ def _get_distro_info():
|
|||
sw_vers = plistlib.load(f)
|
||||
return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], ""
|
||||
elif _is_android():
|
||||
from subprocess import check_output
|
||||
import subprocess
|
||||
|
||||
android_version = check_output(["getprop", "ro.build.version.release"])
|
||||
android_version = subprocess.run(
|
||||
["getprop", "ro.build.version.release"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout
|
||||
return "android", "Android", android_version.decode().strip(), ""
|
||||
elif psutil.LINUX:
|
||||
import distro
|
||||
|
@ -206,5 +210,5 @@ def _get_distro_info():
|
|||
raise NotImplementedError("unsupported OS")
|
||||
|
||||
|
||||
def _is_android():
|
||||
def _is_android() -> bool:
|
||||
return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app")
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from configparser import ConfigParser
|
||||
import json
|
||||
from typing import Any, Generator, Optional, Union
|
||||
import os
|
||||
import sys
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
from configparser import ConfigParser
|
||||
from pathlib import Path
|
||||
from typing import Any, Generator, Optional, Union
|
||||
|
||||
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":
|
||||
|
@ -49,7 +47,8 @@ def emote_downloader_and_iterator() -> Generator[str, None, None]:
|
|||
with urllib.request.urlopen(registry_dump_url, timeout=10) as response:
|
||||
emote_registry_data = json.load(response)
|
||||
|
||||
assert emote_registry_data["version"] == 1
|
||||
if emote_registry_data["version"] != 1:
|
||||
raise Exception("unsupported emote registry version")
|
||||
|
||||
allow_nsfw = config.getboolean("default", "allow_nsfw", fallback=False)
|
||||
emotes = [emote for emote in emote_registry_data["list"] if emote["safe"] or allow_nsfw]
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import base64
|
||||
import argparse
|
||||
import base64
|
||||
import sys
|
||||
from hashlib import md5
|
||||
from typing import IO
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto import Random
|
||||
import sys
|
||||
|
||||
from Crypto import Random
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
CC_ENCRYPTION_MARKER_BYTES = b"[-!_0_!-]"
|
||||
CC_ENCRYPTION_PASSPHRASE = b":_.NaN0"
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
# NOTE: Empty help strings are necessary for subparsers to show up in help.
|
||||
subparsers = parser.add_subparsers(required=True, metavar="COMMAND")
|
||||
|
@ -34,14 +34,15 @@ def main():
|
|||
|
||||
def cmd_pipe_decrypt(args: argparse.Namespace) -> None:
|
||||
input_file: IO[bytes] = (
|
||||
sys.stdin.buffer if args.input_file == "-" else open(args.input_file, 'rb')
|
||||
sys.stdin.buffer if args.input_file == "-" else open(args.input_file, "rb")
|
||||
)
|
||||
output_file: IO[bytes] = (
|
||||
sys.stdout.buffer if args.output_file == "-" else open(args.output_file, 'wb')
|
||||
sys.stdout.buffer if args.output_file == "-" else open(args.output_file, "wb")
|
||||
)
|
||||
|
||||
encrypted = input_file.read()
|
||||
assert encrypted.startswith(CC_ENCRYPTION_MARKER_BYTES)
|
||||
if not encrypted.startswith(CC_ENCRYPTION_MARKER_BYTES):
|
||||
raise Exception()
|
||||
encrypted = encrypted[len(CC_ENCRYPTION_MARKER_BYTES):]
|
||||
decrypted = CryptoJsBridge.decrypt(encrypted, CC_ENCRYPTION_PASSPHRASE)
|
||||
output_file.write(decrypted)
|
||||
|
@ -49,10 +50,10 @@ def cmd_pipe_decrypt(args: argparse.Namespace) -> None:
|
|||
|
||||
def cmd_pipe_encrypt(args: argparse.Namespace) -> None:
|
||||
input_file: IO[bytes] = (
|
||||
sys.stdin.buffer if args.input_file == "-" else open(args.input_file, 'rb')
|
||||
sys.stdin.buffer if args.input_file == "-" else open(args.input_file, "rb")
|
||||
)
|
||||
output_file: IO[bytes] = (
|
||||
sys.stdout.buffer if args.output_file == "-" else open(args.output_file, 'wb')
|
||||
sys.stdout.buffer if args.output_file == "-" else open(args.output_file, "wb")
|
||||
)
|
||||
|
||||
decrypted = input_file.read()
|
||||
|
@ -87,7 +88,8 @@ class CryptoJsBridge:
|
|||
"""
|
||||
Extended from <https://gist.github.com/gsakkis/4546068/1d65cea035562e36da2cc160d6a9e4821b553fa8#file-aes-py-L49-L57>.
|
||||
"""
|
||||
assert len(salt) == cls.SALT_SIZE
|
||||
if len(salt) != cls.SALT_SIZE:
|
||||
raise Exception("invalid salt length")
|
||||
data += salt
|
||||
key = md5(data).digest()
|
||||
final_key = key
|
||||
|
@ -114,7 +116,8 @@ class CryptoJsBridge:
|
|||
Equivalent to `CryptoJS.AES.decrypt(encrypted, passphrase).toString(CryptoJS.enc.Utf8)`.
|
||||
"""
|
||||
encrypted = base64.b64decode(encrypted)
|
||||
assert encrypted.startswith(cls.SALTED_MARKER)
|
||||
if not encrypted.startswith(cls.SALTED_MARKER):
|
||||
raise Exception("expected salt marker")
|
||||
encrypted = encrypted[len(cls.SALTED_MARKER):]
|
||||
salt, ciphertext = encrypted[:cls.SALT_SIZE], encrypted[cls.SALT_SIZE:]
|
||||
key_iv = cls.bytes_to_key(passphrase, salt, cls.KEY_SIZE + cls.IV_SIZE)
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
# https://discord.com/developers/docs/reference#snowflakes
|
||||
|
||||
import sys
|
||||
import colorama
|
||||
import time
|
||||
|
||||
import colorama
|
||||
|
||||
DISCORD_EPOCH = 1420070400000 # milliseconds
|
||||
|
||||
user_snowflake = int(sys.argv[1])
|
||||
|
||||
|
||||
def print_field(name, value):
|
||||
def print_field(name: str, value: object) -> None:
|
||||
print(
|
||||
"{}{}:{} {}".format(colorama.Style.BRIGHT, name.rjust(21), colorama.Style.RESET_ALL, value)
|
||||
)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import discord
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional, cast
|
||||
|
||||
import discord
|
||||
|
||||
guild_id = int(sys.argv[1])
|
||||
voice_channel_id = int(sys.argv[2])
|
||||
|
@ -16,17 +17,17 @@ bot = discord.Client()
|
|||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
async def on_ready() -> None:
|
||||
print("logged in as {0} ({0.id})".format(bot.user))
|
||||
|
||||
guild: discord.Guild = bot.get_guild(guild_id)
|
||||
guild: Optional[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)
|
||||
voice_channel: Optional[discord.VoiceChannel] = guild.get_channel(voice_channel_id)
|
||||
if voice_channel is None:
|
||||
raise Exception("channel not found")
|
||||
|
||||
voice_client = await voice_channel.connect()
|
||||
voice_client = cast(discord.voice_client.VoiceClient, 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")
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
# <https://discord.com/developers/docs/resources/user#user-object#get-user>
|
||||
# <https://discord.com/developers/docs/reference>
|
||||
|
||||
import sys
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import colorama
|
||||
import time
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import colorama
|
||||
|
||||
DISCORD_EPOCH = 1420070400000 # milliseconds
|
||||
# https://discord.com/developers/docs/resources/user#user-object-user-flags
|
||||
|
@ -37,17 +38,17 @@ parser.add_argument("user_snowflake", type=int)
|
|||
parser.add_argument("--bot-token", type=str)
|
||||
parser.add_argument("--image-size", type=int)
|
||||
parser.add_argument("--get-prop", type=str)
|
||||
parser.add_argument("--api-response", action='store_true')
|
||||
parser.add_argument("--api-response", action="store_true")
|
||||
cli_args = parser.parse_args()
|
||||
|
||||
user_snowflake = cli_args.user_snowflake
|
||||
user_snowflake: int = cli_args.user_snowflake
|
||||
|
||||
bot_token = cli_args.bot_token
|
||||
bot_token: Optional[str] = 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()
|
||||
|
||||
image_size = cli_args.image_size
|
||||
image_size: Optional[int] = 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")
|
||||
|
||||
|
@ -70,10 +71,10 @@ except urllib.error.HTTPError as err:
|
|||
|
||||
if cli_args.api_response:
|
||||
json.dump(raw_data, sys.stdout, ensure_ascii=False, indent=2)
|
||||
sys.stdout.write('\n')
|
||||
sys.stdout.write("\n")
|
||||
sys.exit()
|
||||
|
||||
data = {}
|
||||
data: Dict[str, str] = {}
|
||||
|
||||
data["ID"] = raw_data["id"]
|
||||
data["Name"] = "{}#{}".format(raw_data["username"], raw_data["discriminator"])
|
||||
|
@ -108,7 +109,7 @@ user_flags = raw_data["public_flags"]
|
|||
if user_flags == 0:
|
||||
data["Flags"] = "<none>"
|
||||
else:
|
||||
user_flag_names = []
|
||||
user_flag_names: List[str] = []
|
||||
for flag_name, bitmask in DISCORD_FLAGS.items():
|
||||
if user_flags & bitmask:
|
||||
user_flag_names.append(flag_name)
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
# <https://www.dropbox.com/sh/uscmj9y3cjfwpsr/AAD35_ZZu64EBi0awLA07fxga?dl=0>
|
||||
# <https://github.com/credomane/factoriomodsettings/blob/master/src/FactorioModSettings.js>
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import json
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
||||
import factorio.property_tree
|
||||
|
@ -23,7 +22,8 @@ with open(Path.home() / ".factorio" / "mods" / "mod-settings.dat", "rb") as f:
|
|||
version_main, version_major, version_minor, version_developer = struct.unpack("<HHHH", f.read(8))
|
||||
|
||||
always_false_flag = factorio.property_tree.read_bool(f)
|
||||
assert not always_false_flag
|
||||
if always_false_flag:
|
||||
raise Exception("the always-False-flag is True for some reason")
|
||||
|
||||
deserialized_data = {
|
||||
"factorio_version": {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
import plyvel
|
||||
import json
|
||||
from sys import stdout
|
||||
import base64
|
||||
import json
|
||||
from pathlib import Path
|
||||
from sys import stdout
|
||||
from typing import Union
|
||||
|
||||
import plyvel
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
encoding_names = ["utf8", "base16", "base32", "base64", "base85"]
|
||||
|
@ -32,7 +32,7 @@ def bytes_to_json(b: bytes, encoding: str) -> Union[str, list[int]]:
|
|||
elif encoding == "base85":
|
||||
return base64.b85encode(b).decode("ascii")
|
||||
else:
|
||||
assert False
|
||||
raise Exception("unreachable")
|
||||
|
||||
|
||||
key_encoding: str = cli_args.key_encoding or cli_args.encoding
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
# Taken from <https://unix.stackexchange.com/a/509417/411555>
|
||||
|
||||
import gi
|
||||
import sys
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Gio, GLib
|
||||
|
||||
from gi.repository import Gio, GLib, Gtk
|
||||
|
||||
rec_mgr = Gtk.RecentManager.get_default()
|
||||
for arg in sys.argv[1:]:
|
||||
|
|
|
@ -39,12 +39,13 @@
|
|||
# created by this script.
|
||||
|
||||
import argparse
|
||||
import mwclient
|
||||
import json
|
||||
from urllib.parse import urlencode
|
||||
import html
|
||||
import json
|
||||
import re
|
||||
from typing import Dict, List, cast
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import mwclient
|
||||
|
||||
LANG = "en"
|
||||
LANG_TEXT_DIRECTION = "ltr"
|
||||
|
@ -116,7 +117,7 @@ MODULES_PRELOAD_SCRIPTS = {
|
|||
|
||||
|
||||
# ported from <https://github.com/wikimedia/mediawiki/blob/c15ded31a6ca79fa65c00d151a7220632ad90b6d/includes/parser/Sanitizer.php#L1205-L1222>
|
||||
def escape_css_class(class_str):
|
||||
def escape_css_class(class_str: str) -> str:
|
||||
class_str = re.sub(
|
||||
r"""(^[0-9\-])|[\x00-\x20!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~]|\xA0""",
|
||||
"_",
|
||||
|
@ -127,8 +128,8 @@ def escape_css_class(class_str):
|
|||
return class_str
|
||||
|
||||
|
||||
def json_dumps_compact(data):
|
||||
return json.dumps(data, indent=None, separators=(",", ":"))
|
||||
def json_dumps_compact(data: object) -> str:
|
||||
return json.dumps(data, indent=None, separators=(",", ":"), ensure_ascii=False)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
@ -147,7 +148,7 @@ cli_args = parser.parse_args()
|
|||
site = mwclient.Site(cli_args.site, scheme=cli_args.scheme)
|
||||
|
||||
|
||||
def get_load_script_url(**args):
|
||||
def get_load_script_url(**args: object) -> str:
|
||||
return "{path}load{ext}?{args}".format(
|
||||
path=site.path,
|
||||
ext=site.ext,
|
||||
|
@ -177,7 +178,11 @@ result = site.post(
|
|||
)["parse"]
|
||||
|
||||
|
||||
def get_modules(page_modules, added_modules_dict, blocked_modules_dict={}):
|
||||
def get_modules(
|
||||
page_modules: List[str],
|
||||
added_modules_dict: Dict[str, List[str]],
|
||||
blocked_modules_dict: Dict[str, List[str]] = {}
|
||||
) -> List[str]:
|
||||
modules = page_modules + added_modules_dict[cli_args.skin]
|
||||
for blocked_module in blocked_modules_dict.get(cli_args.skin, []):
|
||||
try:
|
||||
|
@ -272,7 +277,7 @@ rendered_html = """\
|
|||
),
|
||||
skin=html.escape(cli_args.skin),
|
||||
page_class=html.escape(escape_css_class(result["displaytitle"])),
|
||||
title=html.escape(result["displaytitle"]),
|
||||
title=html.escape(cast(str, result["displaytitle"])),
|
||||
indicators_html="\n".join([
|
||||
'<div id="mw-indicator-{}" class="mw-indicator">{}</div>'.format(
|
||||
indicator["name"], indicator["*"]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
import gi
|
||||
import argparse
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Gdk, Pango
|
||||
|
||||
gi.require_version("Gdk", "3.0")
|
||||
from gi.repository import Gdk, Gtk, Pango
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("message", type=str, nargs="+")
|
||||
|
@ -24,13 +24,13 @@ scrolled_window.add(label)
|
|||
window.add(scrolled_window)
|
||||
|
||||
|
||||
def on_key_release(target, event):
|
||||
def on_key_release(_target, event) -> None:
|
||||
key = event.keyval
|
||||
if key in [Gdk.KEY_Escape, Gdk.KEY_q, Gdk.KEY_Q]:
|
||||
window.close()
|
||||
|
||||
|
||||
def on_configure(target, event):
|
||||
def on_configure(target, event) -> None:
|
||||
if target != window or event.type != Gdk.EventType.CONFIGURE:
|
||||
return
|
||||
font_desc = Pango.FontDescription()
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
# TODO: Update the menu on player status changes.
|
||||
|
||||
import math
|
||||
import gi
|
||||
import sys
|
||||
|
||||
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 Gdk, GLib, Gtk, Pango, Playerctl
|
||||
|
||||
# Larger priority values will make the player with this name appear higher in
|
||||
# the menu. The default priority is 0.
|
||||
|
@ -39,7 +39,7 @@ PLAYER_PLAYBACK_STATUS_EMOJIS = {
|
|||
}
|
||||
|
||||
|
||||
def humanize_duration(duration):
|
||||
def humanize_duration(duration: float) -> str:
|
||||
minutes, seconds = divmod(math.floor(duration), 60)
|
||||
hours, minutes = divmod(minutes, 60)
|
||||
text = "{:02}:{:02}".format(minutes, seconds)
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
# <https://stackoverflow.com/a/740183/12005228>
|
||||
# <https://wiki.mozilla.org/Places:BookmarksComments>
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from configparser import ConfigParser
|
||||
import tempfile
|
||||
import shutil
|
||||
import sqlite3
|
||||
from typing import Optional, Tuple, Generator
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
from configparser import ConfigParser
|
||||
from pathlib import Path
|
||||
from typing import Generator, Optional, Tuple
|
||||
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "script-resources"))
|
||||
import common_script_utils
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue