1
Fork 0

Rewrite scripts in Deno and move to $BAUKE_DIR.

This commit is contained in:
Bauke 2022-12-09 12:26:08 +01:00
parent d6f25a266d
commit a081f0b4e3
Signed by: Bauke
GPG Key ID: C1C0F29952BCF558
17 changed files with 307 additions and 283 deletions

6
.bauke/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"deno.enable": true,
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
}
}

10
.bauke/bin/codium-extensions Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env zsh
codium_extensions_file="$BAUKE_DIR/data/codium-extensions.txt"
deno run \
--allow-read="$codium_extensions_file" \
--allow-run="codium" \
--allow-write="$codium_extensions_file" \
"$BAUKE_DIR/scripts/codium-extensions.ts" \
"$@"

8
.bauke/bin/project-avatar Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env zsh
deno run \
--allow-run="convert,gegl,mat2" \
--allow-read \
--allow-write \
"$BAUKE_DIR/scripts/project-avatar.ts" \
"$@"

6
.bauke/bin/simple-git-push Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env zsh
deno run \
--allow-run="git" \
"$BAUKE_DIR/scripts/simple-git-push.ts" \
"$@"

6
.bauke/bin/tauon-controls Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env zsh
deno run \
--allow-net="127.0.0.1:7813,127.0.0.1:7814" \
"$BAUKE_DIR/scripts/tauon-controls.ts" \
"$@"

View File

@ -1,4 +1,5 @@
brunnerh.insert-unicode
denoland.vscode-deno
Holllo.love
jock.svg
ritwickdey.LiveServer

View File

@ -0,0 +1,65 @@
import { Command } from "https://deno.land/x/cliffy@v0.25.5/command/mod.ts";
import { runAndReturnStdout } from "./utilities.ts";
async function main(): Promise<void> {
const { options } = await new Command()
.name("codium-extensions")
.description("Small managing utility for VS Codium extensions!")
.option(
"-f, --file <file:file>",
"The file to use for storing data.",
{
default:
new URL("../data/codium-extensions.txt", import.meta.url).pathname,
},
)
.option("--install", "Install saved extensions.")
.option("--list", "List installed extensions.")
.option("--list-saved", "List saved extensions.")
.option("--save", "Save installed extensions.")
.parse(Deno.args);
if (options.install) {
const extensions = await getSavedExtensions(options.file);
const process = Deno.run({
cmd: [
"codium",
...extensions.flatMap((id) => ["--install-extension", id]),
],
});
await process.status();
}
if (options.list) {
const extensions = await getInstalledExtensions();
console.log(extensions.join("\n"));
}
if (options.listSaved) {
const extensions = await getSavedExtensions(options.file);
console.log(extensions.join("\n"));
}
if (options.save) {
const extensions = await getInstalledExtensions();
await Deno.writeTextFile(options.file, extensions.join("\n") + "\n");
console.log(`Wrote ${extensions.length} extensions to ${options.file}`);
}
}
async function getInstalledExtensions(): Promise<string[]> {
const extensions = await runAndReturnStdout({
cmd: ["codium", "--list-extensions"],
});
return extensions.trim().split("\n");
}
async function getSavedExtensions(file: string): Promise<string[]> {
const extensions = await Deno.readTextFile(file);
return extensions.trim().split("\n");
}
if (import.meta.main) {
void main();
}

View File

@ -0,0 +1,107 @@
import { Command } from "https://deno.land/x/cliffy@v0.25.5/command/mod.ts";
import { existsSync } from "https://deno.land/std@0.167.0/node/fs.ts";
async function main(): Promise<void> {
const { args, options } = await new Command()
.name("project-avatar")
.description("Project Avatar Generator")
.arguments("<file:file> <text:string>")
.option("--width <width:number>", "The width of the image.", {
default: 256,
})
.option("--height <height:number>", "The height of the image.", {
default: 256,
})
.option("--font-size <font-size:number>", "Font size for the text.", {
default: 150,
})
.option("--overwrite", "Overwrite an existing image.")
.option("--clean", "Use MAT2 to clean the image.")
.parse(Deno.args);
const [file, text] = args;
if (existsSync(file)) {
if (options.overwrite) {
await Deno.remove(file);
} else {
console.log("File exists, use --overwrite to overwrite.");
Deno.exit(1);
}
}
await Deno.run({
cmd: [
"gegl",
"-o",
file,
"--",
...geglGraph({
fontSize: options.fontSize,
height: options.height,
text,
width: options.width,
}),
],
}).status();
if (!existsSync(file)) {
console.log("Something went wrong with GEGL.");
Deno.exit(1);
}
await Deno.run({
cmd: [
"convert",
file,
"-background",
"transparent",
"-gravity",
"center",
"-extent",
`${options.width}x${options.height}`,
file,
],
}).status();
if (options.clean) {
await Deno.run({ cmd: ["mat2", "--inplace", file] }).status();
}
}
type GraphOptions = {
fontSize: number;
height: number;
text: string;
width: number;
};
function geglGraph({ fontSize, height, text, width }: GraphOptions): string[] {
const graph = `
gegl:text
string=${text}
width=${width}
height=${height}
color=white
font=Inter Heavy
size=${fontSize}
alignment=1
vertical-alignment=1
gegl:dropshadow
x=0
y=0
color=black
opacity=1
grow-radius=4
radius=0
gegl:long-shadow
angle=90
color=black
length=20`;
return graph.replace(/\s\s+/g, "\n").trim().split("\n");
}
if (import.meta.main) {
void main();
}

View File

@ -0,0 +1,46 @@
import { Command } from "https://deno.land/x/cliffy@v0.25.5/command/mod.ts";
import { runAndReturnStdout } from "./utilities.ts";
async function main(): Promise<void> {
const { args } = await new Command()
.name("simple-git-push")
.description("Git push with some extra semantics.")
.arguments("[...args:string]")
.parse(Deno.args);
const availableRemotes = await gitRemote();
if (availableRemotes.length === 0) {
console.log("No remotes found");
Deno.exit(0);
}
const remotesToPush = ["origin", "github"];
for (const remote of availableRemotes) {
if (remotesToPush.includes(remote)) {
await gitPush(remote, args);
}
}
}
async function gitPush(remote: string, args: string[]): Promise<void> {
await Deno.run({
cmd: [
"git",
"push",
"--follow-tags",
remote,
...args,
],
}).status();
}
async function gitRemote(): Promise<string[]> {
const output = await runAndReturnStdout({ cmd: ["git", "remote"] });
return output.trim().split("\n").filter((remote) => remote.length > 0);
}
if (import.meta.main) {
void main();
}

View File

@ -0,0 +1,38 @@
import { Command } from "https://deno.land/x/cliffy@v0.25.5/command/mod.ts";
const hiddenApi = "http://127.0.0.1:7813";
const remoteApi = "http://127.0.0.1:7814/api1";
async function main(): Promise<void> {
const { options } = await new Command()
.name("tauon-controls")
.description("Small remote control CLI for Tauon Music Box!")
.option("--next-song", "Play the next song.")
.option("--play-pause", "Toggle play or pause.")
.option("--previous-song", "Play the previous song.")
.option(
"--volume <volume:number>",
"Change the volume by a relative amount",
)
.parse(Deno.args);
if (options.nextSong) {
await fetch(`${remoteApi}/next`);
}
if (options.playPause) {
await fetch(`${hiddenApi}/playpause/`);
}
if (options.previousSong) {
await fetch(`${remoteApi}/back`);
}
if (options.volume !== undefined) {
await fetch(`${remoteApi}/setvolumerel/${options.volume}`);
}
}
if (import.meta.main) {
void main();
}

View File

@ -0,0 +1,8 @@
import { TextDecoder } from "https://deno.land/std@0.167.0/node/util.ts";
export async function runAndReturnStdout(
options: Deno.RunOptions,
): Promise<string> {
const process = Deno.run({ stdout: "piped", ...options });
return new TextDecoder().decode(await process.output());
}

View File

@ -1,62 +0,0 @@
#!/usr/bin/env python3
import argparse
import pathlib
import subprocess
import typing
def main() -> None:
parser = argparse.ArgumentParser(description="Small Tauon remote control CLI")
parser.add_argument(
"action",
choices=["install", "list", "list-saved", "save"],
help="Which action should be performed.",
)
parser.add_argument(
"-f",
"--file",
help="Use a different file than $HOME/.config/codium-extensions.txt.",
default=pathlib.Path.home().joinpath(".config/codium-extensions.txt"),
)
args = parser.parse_args()
if args.action == "install":
print("Installing saved extensions")
for extension in get_saved_extensions(args.file):
subprocess.run(["codium", "--install-extension", extension])
elif args.action == "list":
print("Listing installed extensions")
print("\n".join(get_installed_extensions()))
elif args.action == "list-saved":
with open(args.file, "r") as file:
print("Listing saved extensions")
print(file.read())
elif args.action == "save":
with open(args.file, "w") as file:
extensions = get_installed_extensions()
file.writelines("\n".join(extensions))
file.write("\n")
print(f"Wrote {len(extensions)} extensions to {args.file}")
def get_installed_extensions() -> typing.List[str]:
extensions = subprocess.run(
[
"codium",
"--list-extensions",
],
capture_output=True,
check=True,
encoding="utf8",
)
return extensions.stdout.splitlines()
def get_saved_extensions(path: str) -> typing.List[str]:
with open(path, "r") as file:
return file.read().splitlines()
if __name__ == "__main__":
main()

View File

@ -1,132 +0,0 @@
#!/usr/bin/env python3
import argparse
import os
import re
import subprocess
import sys
import typing
def main() -> None:
parser = create_parser()
args = parser.parse_args()
if os.path.isfile(args.filename):
if args.overwrite:
os.remove(args.filename)
else:
print("Target file already exists, use --overwrite to overwrite.")
sys.exit(1)
subprocess.run(
[
"gegl",
"-o",
args.filename,
"--",
*gegl_graph(args.height, args.width, args.text, args.font_size),
],
check=True,
)
if not os.path.isfile(args.filename):
print("Something went wrong with GEGL")
sys.exit(1)
subprocess.run(
[
"convert",
args.filename,
"-background",
"transparent",
"-gravity",
"center",
"-extent",
f"{args.width}x{args.height}",
args.filename,
],
check=True,
)
if args.clean:
subprocess.run(
[
"mat2",
"--inplace",
args.filename,
],
check=True,
)
def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Project Avatar Generator")
parser.add_argument(
"filename",
help="The image filename to write to.",
)
parser.add_argument(
"text",
help="The text for the project avatar.",
)
parser.add_argument(
"--width",
help="The width of the image.",
type=int,
default=256,
)
parser.add_argument(
"--height",
help="The height of the image.",
type=int,
default=256,
)
parser.add_argument(
"--overwrite",
help="Overwrite an existing image.",
action="store_true",
)
parser.add_argument(
"--clean",
help="Use MAT2 to clean the image.",
action="store_true",
)
parser.add_argument(
"--font-size",
help="The font size to use for the text.",
type=int,
default=150,
)
return parser
def gegl_graph(height: int, width: int, text: str, font_size: int) -> typing.List[str]:
graph = f"""
gegl:text
string={text}
width={width}
height={height}
color=white
font=Heavitas
size={font_size}
alignment=1
vertical-alignment=1
gegl:dropshadow
x=0
y=0
color=black
opacity=1
grow-radius=4
radius=0
gegl:long-shadow
angle=90
color=black
length=20
"""
return re.sub("\s\s+", "\n", graph).strip().splitlines()
if __name__ == "__main__":
main()

View File

@ -1,43 +0,0 @@
#!/usr/bin/env python3
import argparse
import subprocess
import sys
import typing
def main() -> None:
available_remotes = git_remote()
if len(available_remotes) == 0:
print("No remotes found")
sys.exit(0)
# Parse any extra arguments passed to use them in git_push, this way
# simple-git-push acts like an aliased command.
extra_args = argparse.ArgumentParser(add_help=False).parse_known_args()[1]
remotes_to_push = ["origin", "github"]
for remote in available_remotes:
if remote in remotes_to_push:
git_push(remote, extra_args)
def git_remote() -> typing.List[str]:
"""Run `git remote` and return found remote names."""
command = ["git", "remote"]
output = subprocess.run(command, capture_output=True, encoding="utf8")
return output.stdout.splitlines()
def git_push(remote: str, extra_args: typing.List[str]) -> None:
"""Run `git push` for the given remote."""
command = ["git", "push", "--follow-tags", remote, *extra_args]
print(f"""Pushing: {" ".join(command)}""")
subprocess.run(command)
if __name__ == "__main__":
main()

View File

@ -1,35 +0,0 @@
#!/usr/bin/env python3
import argparse
import requests
HIDDEN_API = "http://0.0.0.0:7813"
REMOTE_API = "http://0.0.0.0:7814/api1"
def main() -> None:
parser = argparse.ArgumentParser(description="Small Tauon remote control CLI")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--next-song", action="store_true")
group.add_argument("--play-pause", action="store_true")
group.add_argument("--previous-song", action="store_true")
group.add_argument("--volume", type=int)
args = parser.parse_args()
if args.next_song:
call_api(f"{REMOTE_API}/next")
if args.play_pause:
call_api(f"{HIDDEN_API}/playpause/")
if args.previous_song:
call_api(f"{REMOTE_API}/back")
if args.volume is not None:
call_api(f"{REMOTE_API}/setvolumerel/{args.volume}")
def call_api(endpoint: str) -> None:
response = requests.get(endpoint)
print(f"HTTP {response.status_code} ({endpoint})")
if __name__ == "__main__":
main()

View File

@ -1 +1,3 @@
export BAUKE_DIR="$HOME/.bauke"
export PATH="$PATH:$BAUKE_DIR/bin"
export PATH="$PATH:$HOME/.local/bin"

15
.zshrc
View File

@ -1,26 +1,19 @@
source "$HOME/.oh-my-zsh/oh-my-zsh.sh"
export EDITOR=nano
export EDITOR="nano"
export LESS="-F -X $LESS"
export BAUKE_DIR="$HOME/.bauke"
export CARGO_BIN="$HOME/.cargo/bin"
export LOCAL_BIN="$HOME/.local/bin"
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$PATH:$CARGO_BIN"
export PATH="$PATH:$LOCAL_BIN"
export PATH="$PATH:$PNPM_HOME"
source "$HOME/.aliases.zsh"
source "$HOME/.functions.zsh"
source "$HOME/.zle.zsh"
export NVS_HOME="$HOME/.local/share/nvs"
source "$NVS_HOME/nvs.sh"
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$PATH:$PNPM_HOME"
export DENO_INSTALL="$HOME/.deno"
export PATH="$PATH:$DENO_INSTALL/bin"
eval "$(register-python-argcomplete pipx)"
eval "$(starship init zsh)"