diff options
| author | coasteen <coasteen@proton.me> | 2026-07-09 10:42:28 +0330 |
|---|---|---|
| committer | coasteen <coasteen@proton.me> | 2026-07-09 10:42:28 +0330 |
| commit | 8cbadb61604667b407b53ee1258433994fa4765a (patch) | |
| tree | 97765fb29418fd6278fcb4cbb9760893afaf7a58 /local/bin | |
Diffstat (limited to 'local/bin')
72 files changed, 1693 insertions, 0 deletions
diff --git a/local/bin/README.md b/local/bin/README.md new file mode 100755 index 0000000..ea5b2c9 --- /dev/null +++ b/local/bin/README.md @@ -0,0 +1,3 @@ +Credits to *<u><a href="https://github.com/swindlesmccoop/">Swindles McCoop</a></u>* for **edsc**, **sb-liisten, sb-memory, sb-volume, sb-cputemp, sb-cpuusage, sb-network, and sb-battery**. Really useful tools. + +(same username on [https://git.cbps.xyz/swindlesmccoop](git.cbps.xyz) he's my daddy btw i love him)
\ No newline at end of file diff --git a/local/bin/Xrec b/local/bin/Xrec new file mode 100755 index 0000000..1d7e956 --- /dev/null +++ b/local/bin/Xrec @@ -0,0 +1,32 @@ +#!/usr/bin/env sh +VIDEO_SIZE="1920x1080" +DISPLAY_NUM=":0.0" +AUDIO_SOURCE="default" +FPS="60" +OUTPUT_FILE="recording_$(date +%Y%m%d_%H%M%S).mkv" +AUDIO_BITRATE="128k" +record() { + local out_file="${1:-$OUTPUT_FILE}" + echo "Starting screen + mic recording..." + echo "Resolution: $VIDEO_SIZE @ ${FPS}fps" + echo "Audio source: $AUDIO_SOURCE" + echo "Output: $out_file" + ffmpeg -y \ + -thread_queue_size 1024 \ + -f x11grab -framerate "$FPS" -video_size "$VIDEO_SIZE" -i "$DISPLAY_NUM" \ + -thread_queue_size 1024 \ + -f pulse -i "$AUDIO_SOURCE" \ + -c:v h264_nvenc -preset p1 -rc vbr -cq 23 \ + -pix_fmt yuv420p \ + -c:a aac -b:a "$AUDIO_BITRATE" \ + -vsync 1 \ + "$out_file" +} +show_help() { + echo "Usage: $0 record [output_file]" +} +if [ "$1" = "--record" ]; then + record "$2" +else + show_help +fi diff --git a/local/bin/aurtest.sh b/local/bin/aurtest.sh new file mode 100755 index 0000000..d26ca37 --- /dev/null +++ b/local/bin/aurtest.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +AUR_URL="https://aur.archlinux.org" +TIMEOUT=5 + +if curl -s --head --fail --max-time "$TIMEOUT" "$AUR_URL" > /dev/null; then + echo "Unfortunately, the AUR is up." +else + echo "AUR IS DOWN" +fi diff --git a/local/bin/bat-symbol b/local/bin/bat-symbol new file mode 100755 index 0000000..1ae28f8 --- /dev/null +++ b/local/bin/bat-symbol @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +def read_file(path): + try: + with open(path, "r") as f: + return f.read().strip() + except: + return None + +def get_battery_info(): + capacity = read_file("/sys/class/power_supply/BAT1/capacity") + status = read_file("/sys/class/power_supply/BAT1/status") + ac_online = read_file("/sys/class/power_supply/ACAD/online") + + try: + percent = int(capacity) + except (TypeError, ValueError): + percent = None + + charging = (status == "Charging") or (ac_online == "1") + return charging, percent + +def print_symbol(): + charging, percent = get_battery_info() + + if percent is None: + print("[?]") + return + + if charging and percent >= 90: + print("[++]") + elif charging and percent < 30: + print("[-+]") + elif charging: + print("[+]") + elif not charging and percent < 30: + print("[--]") + else: + print("[-]") + +if __name__ == "__main__": + print_symbol() diff --git a/local/bin/brwmenu b/local/bin/brwmenu new file mode 100755 index 0000000..11628eb --- /dev/null +++ b/local/bin/brwmenu @@ -0,0 +1,118 @@ +#!/bin/sh + +WMENU="wmenu" +DMENU="dmenu" +BROWSER="firefox-bin" +NOTIFY="notify-send" + +CHOICES="Paulgo +URL +Incognito URL +YouTube +Codeberg +Tildegit +IPLeak +Safebooru +Wikipedia" + +notify() { + "$NOTIFY" "$1" "$2" 2>/dev/null +} + +run_wmenu() { + printf '%s\n' "$1" | $WMENU -p "$2" +} + +run_dmenu() { + printf '' | $DMENU -p "$1" +} + +urlencode() { + python3 -c "import sys, urllib.parse as ul; print(ul.quote_plus(sys.argv[1]))" "$1" +} + +open_url() { + url="$1" + if pgrep -x "$BROWSER" >/dev/null; then + "$BROWSER" --new-tab "$url" & + else + "$BROWSER" "$url" & + fi +} + +main() { + choice=$(run_wmenu "$CHOICES" "Where to?") + [ -z "$choice" ] && notify "Error" "No selection made" && exit 1 + + case "$choice" in + Codeberg) + repo=$(run_dmenu "Username & repo (user/repo):") + [ -z "$repo" ] && notify "Error" "No input" && exit 1 + open_url "https://codeberg.org/$repo" + ;; + Tildegit) + repo=$(run_dmenu "Username & repo (user/repo):") + [ -z "$repo" ] && notify "Error" "No input" && exit 1 + open_url "https://tildegit.org/$repo" + ;; + IPLeak) + open_url "https://ipleak.net" + ;; + Paulgo) + query=$(run_dmenu "Search Paulgo:") + [ -z "$query" ] && notify "Error" "No input" && exit 1 + qenc=$(urlencode "$query") + open_url "https://paulgo.io/search?q=$qenc" + ;; + Wikipedia) + query=$(run_dmenu "Search Wikipedia:") + [ -z "$query" ] && notify "Error" "No input" && exit 1 + qenc=$(urlencode "$query") + open_url "https://en.wikipedia.org/wiki/Special:Search?search=$qenc" + ;; + URL) + url=$(run_dmenu "Enter URL:") + [ -z "$url" ] && notify "Error" "No URL entered" && exit 1 + case "$url" in + http*) ;; + *) url="https://$url" ;; + esac + open_url "$url" + ;; + "Incognito URL") + url=$(run_dmenu "Enter incognito URL:") + [ -z "$url" ] && notify "Error" "No URL entered" && exit 1 + case "$url" in + http*) ;; + *) url="https://$url" ;; + esac + "$BROWSER" --private-window "$url" & + ;; + YouTube) + query=$(run_dmenu "Search YouTube:") + [ -z "$query" ] && notify "Error" "No input" && exit 1 + qenc=$(urlencode "$query") + open_url "https://youtube.com/results?search_query=$qenc" + ;; + Safebooru) + query=$(run_dmenu "Search Safebooru:") + [ -z "$query" ] && notify "Error" "No input" && exit 1 + qenc=$(urlencode "$query") + open_url "https://safebooru.org/index.php?page=post&s=list&tags=$qenc" + ;; + *) + notify "Error" "Invalid selection: $choice" + exit 1 + ;; + esac +} + +for cmd in "$WMENU" "$DMENU" "$BROWSER" "$NOTIFY"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "Error: required command '$cmd' not found" >&2 + exit 1 + fi +done + +main + diff --git a/local/bin/cotray b/local/bin/cotray Binary files differnew file mode 100755 index 0000000..d9802c7 --- /dev/null +++ b/local/bin/cotray diff --git a/local/bin/define b/local/bin/define new file mode 100755 index 0000000..6d9b2dc --- /dev/null +++ b/local/bin/define @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +word=${1:-$(xclip -o -selection primary 2>/dev/null || wl-paste 2>/dev/null)} + +# Check for empty word or special characters +[[ -z "$word" || "$word" =~ [\/] ]] && notify-send -h string:bgcolor:#bf616a -t 3000 "Invalid input." && exit 0 + +query=$(curl -s --connect-timeout 5 --max-time 10 "https://api.dictionaryapi.dev/api/v2/entries/en_US/$word") + +# Check for connection error (curl exit status stored in $?) +[ $? -ne 0 ] && notify-send -h string:bgcolor:#bf616a -t 3000 "Connection error." && exit 1 + +# Check for invalid word response +[[ "$query" == *"No Definitions Found"* ]] && notify-send -h string:bgcolor:#bf616a -t 3000 "Invalid word." && exit 0 + +# Show only first 3 definitions +def=$(echo "$query" | jq -r '[.[].meanings[] | {pos: .partOfSpeech, def: .definitions[].definition}] | .[:3].[] | "\n\(.pos). \(.def)"') + +# Requires a notification daemon to be installed +notify-send "$word -" "$def" + + +### MORE OPTIONS :) + +# Show first definition for each part of speech (thanks @morgengabe1 on youtube) +# def=$(echo "$query" | jq -r '.[0].meanings[] | "\(.partOfSpeech): \(.definitions[0].definition)\n"') + +# Show all definitions +# def=$(echo "$query" | jq -r '.[].meanings[] | "\n\(.partOfSpeech). \(.definitions[].definition)"') + +# Regex + grep for just definition, if anyone prefers that to jq +# def=$(grep -Po '"definition":"\K(.*?)(?=")' <<< "$query") + +# bold=$(tput bold) # Print text bold with echo, for visual clarity +# normal=$(tput sgr0) # Reset text to normal +# echo "${bold}Definition of $word" +# echo "${normal}$def" diff --git a/local/bin/discord b/local/bin/discord new file mode 100755 index 0000000..324caf1 --- /dev/null +++ b/local/bin/discord @@ -0,0 +1,39 @@ +#!/bin/sh + +RUN_WITH_PROXY() { + BINARY=$1 + shift + if [ -n "$BINARY" ]; then + exec "$BINARY" --proxy-server="socks5://127.0.0.1:65000" "$@" + fi +} + +GET_VESKTOP() { + if command -v vesktop >/dev/null 2>&1; then + echo "$(command -v vesktop)" + elif command -v vesktop-bin >/dev/null 2>&1; then + echo "$(command -v vesktop-bin)" + elif command -v flatpak >/dev/null 2>&1 && flatpak list --ids | grep -q "dev.vencord.Vesktop"; then + echo "flatpak run dev.vencord.Vesktop" + fi +} + +GET_DISCORD() { + if command -v linux-discord >/dev/null 2>&1; then + echo "$(command -v linux-discord)" + elif command -v flatpak >/dev/null 2>&1 && flatpak list --ids | grep -q "com.discordapp.Discord"; then + echo "flatpak run com.discordapp.Discord" + fi +} + +OS=$(uname -s) + +if [ "$OS" = "FreeBSD" ]; then + CMD=$(GET_DISCORD) + RUN_WITH_PROXY $CMD "$@" +elif [ "$OS" = "Linux" ]; then + CMD=$(GET_VESKTOP) + RUN_WITH_PROXY $CMD "$@" +else + linux-discord --proxy-server="socks5://127.0.0.1:65000" "$@" +fi diff --git a/local/bin/dmenu.py b/local/bin/dmenu.py new file mode 100755 index 0000000..948dbd8 --- /dev/null +++ b/local/bin/dmenu.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +from pathlib import Path + + +DMENU_ARGS = [ + "dmenu", + "-i", + "-fn", "JetBrainsMono Nerd Font-10", + "-nb", "#121212", + "-nf", "#e0e0e0", + "-sb", "#222222", + "-sf", "#e0e0e0", + "-l", "10", + "-p", "Launch:", +] + +DESKTOP_DIRS = [ + Path.home() / ".local/share/applications", + Path.home() / ".local/share/flatpak/exports/share/applications", + Path("/var/lib/flatpak/exports/share/applications"), + Path("/usr/share/applications"), + Path("/usr/local/share/applications"), +] + +INVALID_EXEC_PREFIXES = ("wine", "wscript", "rundll32", "winhlp32", "hh ") + + +def parse_desktop_file(path: Path): + """ + Returns (name, exec_cmd) or (None, None) if the file should be skipped. + Handles: NoDisplay=true, Hidden=true, missing Name/Exec, field codes, env wrappers. + """ + props = {} + in_desktop_entry = False + + try: + with path.open(encoding="utf-8", errors="replace") as f: + for line in f: + line = line.rstrip("\n") + if line.startswith("["): + in_desktop_entry = line == "[Desktop Entry]" + continue + if not in_desktop_entry or "=" not in line: + continue + key, _, value = line.partition("=") + key = key.strip() + if key not in props: + props[key] = value.strip() + except OSError: + return None, None + + if props.get("NoDisplay", "").lower() == "true": + return None, None + if props.get("Hidden", "").lower() == "true": + return None, None + if props.get("Type", "") != "Application": + return None, None + + name = props.get("Name") + exec_raw = props.get("Exec") + + if not name or not exec_raw: + return None, None + + exec_cmd = clean_exec(exec_raw) + + if not exec_cmd: + return None, None + + lower = exec_cmd.lower() + if any(lower.startswith(p) for p in INVALID_EXEC_PREFIXES): + return None, None + + terminal = props.get("Terminal", "").lower() == "true" + if terminal: + term = os.environ.get("TERMINAL", "xterm") + exec_cmd = f"{term} -e {exec_cmd}" + + return name, exec_cmd + + +def clean_exec(exec_raw: str) -> str: + tokens = exec_raw.split() + cleaned = [] + for token in tokens: + if token.startswith("%") and len(token) == 2 and token[1].isalpha(): + continue + cleaned.append(token) + return " ".join(cleaned).strip() + + +def collect_apps(): + seen_stems = {} + for directory in DESKTOP_DIRS: + if not directory.is_dir(): + continue + for desktop_file in sorted(directory.glob("*.desktop")): + stem = desktop_file.stem.lower() + if stem not in seen_stems: + seen_stems[stem] = desktop_file + + apps = {} + for desktop_file in seen_stems.values(): + name, cmd = parse_desktop_file(desktop_file) + if name and cmd and name not in apps: + apps[name] = cmd + return apps + + +def run_dmenu(app_names: list[str]) -> str | None: + names_input = "\n".join(sorted(app_names, key=str.casefold)).encode() + try: + result = subprocess.run( + DMENU_ARGS, + input=names_input, + capture_output=True, + ) + except FileNotFoundError: + sys.exit("error: dmenu not found in PATH") + + if result.returncode != 0: + return None + + return result.stdout.decode().strip() + + +def launch(cmd: str): + subprocess.Popen( + cmd, + shell=True, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + start_new_session=True, + ) + + +def main(): + apps = collect_apps() + + if not apps: + sys.exit("error: no applications found") + + selected = run_dmenu(list(apps.keys())) + + if not selected: + return + + cmd = apps.get(selected) + if not cmd: + sys.exit(f"error: no command found for '{selected}'") + + launch(cmd) + + +if __name__ == "__main__": + main() diff --git a/local/bin/ecop b/local/bin/ecop new file mode 100755 index 0000000..6bdb7c3 --- /dev/null +++ b/local/bin/ecop @@ -0,0 +1,2 @@ +#!/bin/zsh +xclip -sel clipboard diff --git a/local/bin/edsc b/local/bin/edsc new file mode 100755 index 0000000..e25e94c --- /dev/null +++ b/local/bin/edsc @@ -0,0 +1,13 @@ +#!/bin/sh +if [ -z "$1" ]; then + SCRIPT=$(find . -type f | fzfse) +else + SCRIPT="$1" +fi + +if [ -z "$SCRIPT" ]; then + echo 'Usage: edsc [file]' + exit 1 +fi + +emacsclient -c -nw "$SCRIPT" diff --git a/local/bin/emacsd b/local/bin/emacsd new file mode 100755 index 0000000..34944c4 --- /dev/null +++ b/local/bin/emacsd @@ -0,0 +1,2 @@ +#!/bin/sh +kitty -e emacsclient -c $1 diff --git a/local/bin/emacsd~ b/local/bin/emacsd~ new file mode 100755 index 0000000..e29cb1d --- /dev/null +++ b/local/bin/emacsd~ @@ -0,0 +1,2 @@ +#!/bin/sh +emacsclient -c $1
\ No newline at end of file diff --git a/local/bin/f2py b/local/bin/f2py new file mode 100755 index 0000000..8eeab20 --- /dev/null +++ b/local/bin/f2py @@ -0,0 +1,8 @@ +#!/usr/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from numpy.f2py.f2py2e import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/firemenu b/local/bin/firemenu new file mode 100755 index 0000000..69b9b18 --- /dev/null +++ b/local/bin/firemenu @@ -0,0 +1,43 @@ +#!/bin/sh +# Credits to Swindles McCoop +# Coast's configuration of Firemenu +# ## Bravemenu +set -e +DMENU_CMD="dmenu -i -fn Cozette:size=13 -nb #151821 -nf #a9b1d6 -sb #414868 -sf #c0caf5" +CHOICES="URL +Google +YouTube +Spotify +Discord +Git.gay +Github +DeepSeek +ChatGPT +4chan +Proton Inbox +Proton Drive +Google Inbox +Ente Auth" + +CHOICE=$(printf "$CHOICES" | $DMENU_CMD -p "Bravemenu ") +SWALLOW= + +case $CHOICE in + "URL") printf '' | $DMENU_CMD -p 'Enter URL(s):' | xargs $SWALLOW brave > /dev/null ;; + "Discord") $SWALLOW brave https://discord.com/app/ > /dev/null ;; + "Spotify") $SWALLOW brave https://open.spotify.com/ > /dev/null ;; + "DeepSeek") $SWALLOW brave https://chat.deepseek.com/ > /dev/null ;; + "ChatGPT") $SWALLOW brave https://chatgpt.com/ > /dev/null ;; + #"Github") $SWALLOW brave https://github.com/ > /dev/null ;; + "Github") printf '' | $DMENU_CMD -p 'Repository:' | sed 's|^|https://github.com/|' | sed 's/ /%20/g' | xargs $SWALLOW brave > /dev/null ;; + "Git.gay") printf '' | $DMENU_CMD -p 'Repository:' | sed 's|^|https://git.gay/|' | sed 's/ /%20/g' | xargs $SWALLOW brave > /dev/null ;; + #"Git.gay") $SWALLOW brave https://git.gay/ > /dev/null ;; + "Google") printf '' | $DMENU_CMD -p 'Search:' | sed 's|^|https://google.com/search?q=|' | sed 's/ /%20/g' | xargs $SWALLOW brave > /dev/null ;; + "Link") printf '' | $DMENU_CMD -p 'Enter URL(s):' | xargs $SWALLOW brave > /dev/null ;; + "YouTube") printf '' | $DMENU_CMD -p 'Search:' | sed 's|^|https://youtube.com/results?search_query=|' | sed 's/ /%20/g' | xargs $SWALLOW brave > /dev/null ;; + "4chan") printf '3\na\naco\nadv\nan\nb\nbant\nbiz\nc\ncgl\nck\ncm\nco\nd\ndiy\ne\nf\nfa\nfit\ng\ngd\ngif\nh\nhc\nhis\nhm\nhr\ni\nic\nint\njp\nk\nlgbt\nlit\nm\nmlp\nmu\nn\nnews\no\nout\np\npo\npol\npw\nqa\nqst\nr\nr9k\ns\ns4s\nsci\nsoc\nsp\nt\ntg\ntoy\ntrv\ntv\nu\nv\nvg\nvip\nvm\nvmg\nvp\nvr\nvrpg\nvst\nvt\nw\nwg\nwsg\nwsr\nx\nxs\ny' | $DMENU_CMD -p 'Board letter:' | sed 's|^|https://4chan.org/|' | xargs $SWALLOW brave > /dev/null ;; + "Proton Inbox") printf '' | $SWALLOW brave https://mail.proton.me/u/0/inbox > /dev/null ;; + "Proton Drive") printf '' | $SWALLOW brave https://drive.proton.me/ > /dev/null ;; + "Google Inbox") printf '' | $SWALLOW brave https://mail.google.com/mail/u/0/ ;; + "Ente Auth") printf '' | $SWALLOW brave https://auth.ente.io/auth ;; +esac diff --git a/local/bin/fzfse b/local/bin/fzfse new file mode 100755 index 0000000..f580569 --- /dev/null +++ b/local/bin/fzfse @@ -0,0 +1,3 @@ +#!/bin/sh + +fzf --layout=reverse --height 40% diff --git a/local/bin/grubfk b/local/bin/grubfk new file mode 100755 index 0000000..06a87f5 --- /dev/null +++ b/local/bin/grubfk @@ -0,0 +1,29 @@ +#!/bin/zsh + +grub_screen() { + clear + echo -e "\n\n\t GNU GRUB 2.06" + echo -e "\n" + echo -e "\t Minimal BASH-like line editing is supported. For the first word, TAB" + echo -e "\t lists possible command completions. Anywhere else TAB lists possible" + echo -e "\t device or file completions." + echo -e "\n" +} + +grub_screen + +# Fake GRUB prompt +while true; do + echo -ne " grub> " + read -r command + case $command in + exit|quit) + clear + break + ;; + *) + echo -e "\t Unknown command. Press a key to continue..." + read -r dummy + ;; + esac +done diff --git a/local/bin/hyfetch b/local/bin/hyfetch new file mode 100755 index 0000000..75b46c2 --- /dev/null +++ b/local/bin/hyfetch @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +import sys +from hyfetch.__main__ import run_rust +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(run_rust()) diff --git a/local/bin/hyfetch.rs b/local/bin/hyfetch.rs new file mode 100755 index 0000000..75b46c2 --- /dev/null +++ b/local/bin/hyfetch.rs @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +import sys +from hyfetch.__main__ import run_rust +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(run_rust()) diff --git a/local/bin/hyfetch.v1 b/local/bin/hyfetch.v1 new file mode 100755 index 0000000..547f291 --- /dev/null +++ b/local/bin/hyfetch.v1 @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +import sys +from hyfetch.__main__ import run_py +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(run_py()) diff --git a/local/bin/killradio b/local/bin/killradio new file mode 100755 index 0000000..46e7d6e --- /dev/null +++ b/local/bin/killradio @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import subprocess +import sys +import signal + +try: + # Find PID(s) of running 'radio' process (matching name) + out = subprocess.check_output(["pgrep", "-f", "radio"]) + pids = [int(pid) for pid in out.decode().strip().split()] +except subprocess.CalledProcessError: + print("No running 'radio' process found.") + sys.exit(1) + +for pid in pids: + try: + # Send SIGKILL (kill -9) to each found pid + subprocess.run(["kill", "-9", str(pid)]) + print(f"Killed PID {pid}") + except Exception as e: + print(f"Failed to kill PID {pid}: {e}") diff --git a/local/bin/math b/local/bin/math new file mode 100755 index 0000000..a817382 --- /dev/null +++ b/local/bin/math @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +import ast +import operator +import math +import sys + +_OPERATORS = { + ast.Add: operator.add, + ast.Sub: operator.sub, + ast.Mult: operator.mul, + ast.Div: operator.truediv, + ast.Mod: operator.mod, + ast.Pow: operator.pow, + ast.USub: operator.neg, + ast.UAdd: operator.pos, + ast.FloorDiv: operator.floordiv, +} + +_MATH_FUNCS = {name: getattr(math, name) for name in dir(math) if not name.startswith("_") and callable(getattr(math, name))} +_MATH_FUNCS.update({ + "abs": abs, + "round": round, + "factorial": math.factorial, + "degrees": math.degrees, + "radians": math.radians, + "isclose": math.isclose, + "isfinite": math.isfinite, + "isinf": math.isinf, + "isnan": math.isnan, + "log2": math.log2, + "log10": math.log10, + "log": math.log, + "exp": math.exp, + "expm1": math.expm1, + "fsum": math.fsum, + "gamma": math.gamma, + "lgamma": math.lgamma, + "trunc": math.trunc, + "max": max, + "min": min, + "sum": sum, +}) + +_CONSTANTS = { + "pi": math.pi, + "e": math.e, + "tau": math.tau, + "inf": math.inf, + "nan": math.nan, +} + +class matheval(ast.NodeVisitor): + def visit(self, node): + if isinstance(node, ast.Expression): + return self.visit(node.body) + return super().visit(node) + + def visit_BinOp(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + op_type = type(node.op) + if op_type in _OPERATORS: + return _OPERATORS[op_type](left, right) + raise ValueError(f"Unsupported binary operator {op_type.__name__}") + + def visit_UnaryOp(self, node): + operand = self.visit(node.operand) + op_type = type(node.op) + if op_type in _OPERATORS: + return _OPERATORS[op_type](operand) + raise ValueError(f"Unsupported unary operator {op_type.__name__}") + + def visit_Call(self, node): + if not isinstance(node.func, ast.Name): + raise ValueError("Only simple function calls allowed") + func_name = node.func.id + if func_name not in _MATH_FUNCS: + raise ValueError(f"Unknown function '{func_name}'") + args = [self.visit(arg) for arg in node.args] + return _MATH_FUNCS[func_name](*args) + + def visit_Name(self, node): + if node.id in _CONSTANTS: + return _CONSTANTS[node.id] + raise ValueError(f"Unknown identifier '{node.id}'") + + def visit_Constant(self, node): + if isinstance(node.value, (int, float)): + return node.value + raise ValueError(f"Unsupported constant type: {type(node.value).__name__}") + + def visit_List(self, node): + return [self.visit(el) for el in node.elts] + + def visit_Tuple(self, node): + return tuple(self.visit(el) for el in node.elts) + + def generic_visit(self, node): + raise ValueError(f"Unsupported expression: {type(node).__name__}") + +def main(): + if len(sys.argv) < 2: + print("Usage: math '<expression>'") + print("Example: math 'sin(pi/2) + 2^3'") + sys.exit(1) + + expr = " ".join(sys.argv[1:]) + expr = expr.replace("^", "**") + expr = expr.replace("\n", "") + + try: + tree = ast.parse(expr, mode="eval") + evaluator = matheval() + result = evaluator.visit(tree) + if isinstance(result, float) and result.is_integer(): + print(int(result)) + else: + print(result) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/local/bin/mksymlink b/local/bin/mksymlink new file mode 100755 index 0000000..54ecd4c --- /dev/null +++ b/local/bin/mksymlink @@ -0,0 +1,57 @@ +#!/bin/sh + +CONFIG_FILE="${HOME}/.config/mksymlink.conf" +TARGET_BASE="${HOME}/.config" + +usage() { + echo "Usage: $0 [-c config_file] [-t target_base]" + exit 1 +} + +while getopts "c:t:h" opt; do + case "$opt" in + c) CONFIG_FILE="$OPTARG" ;; + t) TARGET_BASE="$OPTARG" ;; + h) usage ;; + *) usage ;; + esac +done + +if [ ! -f "$CONFIG_FILE" ]; then + echo "Error: config file '$CONFIG_FILE' does not exist" 1>&2 + exit 2 +fi + +. "$CONFIG_FILE" + +if [ -z "$MAIN" ]; then + echo "Error: MAIN is not set in config file" 1>&2 + exit 3 +fi + +mkdir -p "$TARGET_BASE" + +for entry in $list; do + TARGET=$(echo "$entry" | cut -d= -f1) + SRC_REL=$(echo "$entry" | cut -d= -f2) + SRC="$MAIN/$SRC_REL" + TARGET_PATH="$TARGET_BASE/$TARGET" + + if [ ! -e "$SRC" ]; then + echo "Warning: source '$SRC' does not exist, skipping" 1>&2 + continue + fi + + mkdir -p "$(dirname "$TARGET_PATH")" + + if [ -L "$TARGET_PATH" ]; then + rm "$TARGET_PATH" + elif [ -e "$TARGET_PATH" ]; then + echo "Warning: target '$TARGET_PATH' exists and is not a symlink, skipping" 1>&2 + continue + fi + + ln -s "$SRC" "$TARGET_PATH" + echo "Created symlink: $TARGET_PATH -> $SRC" +done + diff --git a/local/bin/mpc-shuf.sh b/local/bin/mpc-shuf.sh new file mode 100755 index 0000000..c0ebafe --- /dev/null +++ b/local/bin/mpc-shuf.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env lua + +local launcher = "dmenu" + +local dmenu_args = { + "-i", + "-fn", "JetBrainsMono Nerd Font-10", + "-nb", "#121212", + "-nf", "#e0e0e0", + "-sb", "#222222", + "-sf", "#e0e0e0", + "-l", "10", +} + +local music_dir = "/home/coast/Music" +local max_length = 30 +local default_icon = "/usr/share/icons/hicolor/48x48/apps/musical-note.png" + +local function build_menu(prompt) + if launcher == "rofi" then + return string.format("rofi -dmenu -i -p '%s'", prompt) + else + local args = "dmenu" + for _, v in ipairs(dmenu_args) do + args = args .. " '" .. v .. "'" + end + args = args .. string.format(" -p '%s'", prompt) + return args + end +end + +local function escape(str) + return str:gsub("'", "'\\''") +end + +local function capture(cmd) + local f = io.popen(cmd, 'r') + local s = f:read('*a') + f:close() + return s:gsub("^%s*(.-)%s*$", "%1") +end + +local function truncate(str, len) + if #str > len then + return str:sub(1, len) .. "..." + end + return str +end + +local function get_cover(song_file) + if not song_file or song_file == "" then return default_icon end + local full_path = music_dir .. "/" .. song_file + local dir = full_path:match("(.*[/\\])") or music_dir + local names = {"cover.jpg", "cover.png", "folder.jpg", "folder.png", "front.jpg", "front.png"} + for _, name in ipairs(names) do + local path = dir .. name + local f = io.open(path, "r") + if f then + f:close() + return path + end + end + return default_icon +end + +local action = arg[1] + +if action == "shuf" then + os.execute("mpc random on >/dev/null && notify-send 'Shuffle enabled'") + os.exit(0) +elseif action == "shufno" then + os.execute("mpc random off >/dev/null && notify-send 'Shuffle disabled'") + os.exit(0) +elseif action == "next" then + os.execute("mpc next >/dev/null") + os.exit(0) +elseif action == "prev" then + os.execute("mpc prev >/dev/null") + os.exit(0) +elseif action == "toggle" then + os.execute("mpc toggle >/dev/null") + os.exit(0) +elseif action == "current" then + local current = capture("mpc current") + if current ~= "" then io.write(current .. "\n") end + os.exit(0) +elseif action == "info" then + local file = capture("mpc --format '%file%' current") + local title = capture("mpc current") + local cover = get_cover(file) + os.execute(string.format("notify-send 'Currently Playing' '%s' -i '%s'", escape(title), cover)) + os.exit(0) +elseif action == "album" then + local album = capture("mpc list album | " .. build_menu("Select Album")) + if album ~= "" then + os.execute(string.format("mpc clear >/dev/null && mpc find album '%s' | mpc add && mpc play >/dev/null", escape(album))) + end + os.exit(0) +elseif action == "artist" then + local artist = capture("mpc list artist | " .. build_menu("Select Artist")) + if artist ~= "" then + os.execute(string.format("mpc clear >/dev/null && mpc find artist '%s' | mpc add && mpc play >/dev/null", escape(artist))) + end + os.exit(0) +elseif action == "search" then + local menu = "mpc --format '%title% - %artist% - %album%\t%file%' search any '' | " .. build_menu("Search music") + local choice = capture(menu) + if choice == "" then os.exit(0) end + local file = choice:match("\t(.-)$") + if file then + os.execute(string.format("mpc clear >/dev/null && mpc add '%s' >/dev/null && mpc play >/dev/null", escape(file))) + os.exit(0) + end +elseif action == "reload" then + os.execute("mpc update && mpc clear && mpc add / && mpc play >/dev/null") + os.execute("notify-send 'Library refreshed. Now playing...'") + os.exit(0) +end + +os.execute("mpc play >/dev/null 2>&1") +os.execute("mpc volume 15 >/dev/null 2>&1") +local file = capture("mpc --format '%file%' current") +local title = capture("mpc current") +local cover = get_cover(file) +local display = truncate(title, max_length) +os.execute(string.format("notify-send 'Now playing...' '%s' -i '%s'", escape(display), cover)) diff --git a/local/bin/nodeenv b/local/bin/nodeenv new file mode 100755 index 0000000..075fc9b --- /dev/null +++ b/local/bin/nodeenv @@ -0,0 +1,7 @@ +#!/usr/bin/python3.13 +import sys +from nodeenv import main +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(main()) diff --git a/local/bin/numpy-config b/local/bin/numpy-config new file mode 100755 index 0000000..399eb6f --- /dev/null +++ b/local/bin/numpy-config @@ -0,0 +1,8 @@ +#!/usr/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from numpy._configtool import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/pyright b/local/bin/pyright new file mode 100755 index 0000000..9c5770d --- /dev/null +++ b/local/bin/pyright @@ -0,0 +1,7 @@ +#!/usr/bin/python3.13 +import sys +from pyright.cli import entrypoint +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(entrypoint()) diff --git a/local/bin/pyright-langserver b/local/bin/pyright-langserver new file mode 100755 index 0000000..e206592 --- /dev/null +++ b/local/bin/pyright-langserver @@ -0,0 +1,7 @@ +#!/usr/bin/python3.13 +import sys +from pyright.langserver import entrypoint +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(entrypoint()) diff --git a/local/bin/pyright-python b/local/bin/pyright-python new file mode 100755 index 0000000..9c5770d --- /dev/null +++ b/local/bin/pyright-python @@ -0,0 +1,7 @@ +#!/usr/bin/python3.13 +import sys +from pyright.cli import entrypoint +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(entrypoint()) diff --git a/local/bin/pyright-python-langserver b/local/bin/pyright-python-langserver new file mode 100755 index 0000000..e206592 --- /dev/null +++ b/local/bin/pyright-python-langserver @@ -0,0 +1,7 @@ +#!/usr/bin/python3.13 +import sys +from pyright.langserver import entrypoint +if __name__ == '__main__': + if sys.argv[0].endswith('.exe'): + sys.argv[0] = sys.argv[0][:-4] + sys.exit(entrypoint()) diff --git a/local/bin/qr b/local/bin/qr new file mode 100755 index 0000000..650c903 --- /dev/null +++ b/local/bin/qr @@ -0,0 +1,8 @@ +#!/nix/store/1ki8jq5sax0hm1sqbw0jk6qnqpy417zx-python3-3.13.5/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +from qrcode.console_scripts import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/radio b/local/bin/radio new file mode 100755 index 0000000..20c369a --- /dev/null +++ b/local/bin/radio @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +import subprocess +import time +from pathlib import Path +import threading +import json +import tempfile +import urllib.request +import websocket +# 128kbps Opus +URL="https://radio.animebits.moe/stream/stream128.ogg" +# 256kbps Opus +#URL="https://radio.animebits.moe/stream/stream256.ogg" +# ~148kbps VBR AAC +#URL="https://radio.animebits.moe/stream/stream128.aac" +# ~192kbps VBR MP3 +#URL="https://radio.animebits.moe/stream/stream192.mp3" +# Lossless FLAC +#URL="https://radio.animebits.moe/stream/stream.flac" +#config file & pid +CONF = Path.home() / ".config" / "radiorc" +PID = Path.home() / ".config" / "radio-pid" +with open(CONF) as f: + VOL = f.read().strip() +def notify(title, image_url=None): + icon_path = None + if image_url: + try: + tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png") + urllib.request.urlretrieve(image_url, tmp.name) + icon_path = tmp.name + except: + icon_path = None + args = ["notify-send", title] + if icon_path: + args += ["-i", icon_path] + subprocess.run(args) +def ws_listener(): + def on_message(ws, message): + data = json.loads(message) + if "data" in data and "title" in data["data"]: + title = data["data"]["title"] + image = data["data"].get("album_cover") + notify(title, image) + def on_error(ws, error): + pass + def on_close(ws, close_status_code, close_msg): + time.sleep(1) + run_ws() + def on_open(ws): + pass + def run_ws(): + ws = websocket.WebSocketApp("wss://radio.animebits.moe/api/events/basic", + on_message=on_message, + on_error=on_error, + on_close=on_close, + on_open=on_open) + ws.run_forever() + run_ws() +threading.Thread(target=ws_listener, daemon=True).start() +while True: + try: + print("Playing now...") + subprocess.run(["notify-send", "Playing now..."]) + proc = subprocess.Popen(["mpv", "--no-video", f"--volume={VOL}", URL]) + with open(PID, "w") as f: + f.write(str(proc.pid)) + proc.wait() + except KeyboardInterrupt: + subprocess.run(["notify-send", "Stopping now..."]) + print("\nStopping now...") + break + except Exception as e: + print(f"Something broke... trying again... Error: {e}") + time.sleep(2) diff --git a/local/bin/resmacs b/local/bin/resmacs new file mode 100755 index 0000000..8be929c --- /dev/null +++ b/local/bin/resmacs @@ -0,0 +1,2 @@ +#!/bin/sh +systemctl restart --user emacs.service diff --git a/local/bin/rimworld b/local/bin/rimworld new file mode 100755 index 0000000..e776f9b --- /dev/null +++ b/local/bin/rimworld @@ -0,0 +1,3 @@ +#!/bin/sh +WINEPREFIX=$HOME/.wine +prime-run wine /home/coast/files/rimworld/RimWorldWin64.exe diff --git a/local/bin/sb-battery b/local/bin/sb-battery new file mode 100755 index 0000000..5e0a9fc --- /dev/null +++ b/local/bin/sb-battery @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +batteries=(/sys/class/power_supply/BAT*) +# Check if any battery directories exist +found=false +for b in "${batteries[@]}"; do + if [ -d "$b" ]; then + found=true + break + fi +done + +if [ "$found" = false ]; then + echo "None" + exit 1 +fi + +first=true +for battery in /sys/class/power_supply/BAT*; do + if [ -d "$battery" ]; then + if [ -r "$battery/capacity" ]; then + capacity=$(<"$battery/capacity") + else + capacity=0 + fi + if [ "$first" = true ]; then + echo -n "${capacity}%" + first=false + else + echo -n " ${capacity}%" + fi + fi +done +echo + diff --git a/local/bin/sb-cputemp b/local/bin/sb-cputemp new file mode 100755 index 0000000..5cbe975 --- /dev/null +++ b/local/bin/sb-cputemp @@ -0,0 +1,20 @@ +#!/bin/sh + +_linux() { + sensors $1 | awk '/^temp1/ {print $2}' | sed 's/+//' +} + +_openbsd() { + [ "$1" = "-f" ] && printf "$(expr $(sysctl | grep hw.sensors.cpu0.temp0 | sed 's/\.00.*//' | sed 's/.*=//') \* 9 / 5 + 32 2> /dev/null)°F" || sysctl | grep hw.sensors.cpu0.temp0 | sed 's/.*=//' | sed 's/\.00//' | sed 's/ deg/°/' +} + +_freebsd() { + C_TEMP=$(sysctl hw.acpi.thermal.tz0.temperature | sed 's/^.* //' ) + [ "$1" = "-f" ] && printf "$(expr $(printf $C_TEMP | sed 's/\..C//') \* 9 / 5 + 32)°F" || printf "$C_TEMP" | sed 's/C/°C/' +} + +case $(uname) in + Linux) _linux "$@" ;; + OpenBSD) _openbsd "$@" ;; + FreeBSD) _freebsd "$@" ;; +esac diff --git a/local/bin/sb-cpuusage b/local/bin/sb-cpuusage new file mode 100755 index 0000000..c05576b --- /dev/null +++ b/local/bin/sb-cpuusage @@ -0,0 +1,30 @@ +#!/bin/sh +#Display CPU usage percentage + +_openbsd() { + CPUS=$(sysctl | grep 'hw.ncpuonline' | sed 's/^.*=//') + TOTALUSAGE=$(ps aux | awk '{print $3}' | sed '1d' | sort | paste -s -d+ - | bc) + USAGE=$(printf "$TOTALUSAGE / $CPUS\n" | bc -l) + printf "$USAGE" | grep "^\.[0-9]" > /dev/null && printf "0$(printf $USAGE | cut -c1-3)%%" || printf "$(printf "$USAGE" | cut -c1-4)%%\n" +} + +_freebsd() { + CPUS="$(sysctl hw.ncpu | sed 's/^.*: //')" + FREE=$(ps -o %cpu -p $(pgrep -S idle) | tail -n 1) + TPP=$(expr $CPUS \* 100) + TOTALUSAGE=$(printf "$TPP - $FREE" | bc -l) + USAGE=$(printf "$TOTALUSAGE / $CPUS" | bc -l | cut -c -4) + printf "$USAGE" | egrep "\.[0-9]{3}" > /dev/null && printf "0$(printf $USAGE | cut -c -3)%%\n" || printf -- "$USAGE%%\n" +} + +_linux() { + TOTALUSAGE="$(ps axch -o cmd,%cpu --sort=-%cpu | sed 's/ //' | grep -E -o " [0-9].*" | sed 's/ //' | paste -s -d+ - | bc)" + USAGE="$(printf "$(printf "$TOTALUSAGE / $(nproc)\n" | bc -l | cut -c1-4)%%\n")" + printf -- "$USAGE%" | grep "^\.[0-9]" > /dev/null && printf -- "0$(printf -- $USAGE% | cut -c1-3)%%" || printf -- "$(printf -- "$USAGE%" | cut -c1-4)%%\n" +} + +case $(uname) in + Linux) _linux ;; + OpenBSD) _openbsd ;; + FreeBSD) _freebsd ;; +esac diff --git a/local/bin/sb-liisten b/local/bin/sb-liisten new file mode 100755 index 0000000..ff9b420 --- /dev/null +++ b/local/bin/sb-liisten @@ -0,0 +1,38 @@ +#!/bin/sh +#Liisten for the status bar + +#options +LOOPCOUNT=1 #however many times you want the song to play minus one (for technical reasons) +SONGDIR="$HOME/music/brstm" +cd "$SONGDIR" + +MODE=$(printf "Random\nForever" | dmenu -i) + +playsong () { + vgmstream-cli -m "$SONG" > /tmp/brstminfo.txt + STARTLOOP="$(grep "seconds" /tmp/brstminfo.txt | head -n 1 | sed 's/.*(//' | sed 's/ seconds)//')" + ENDLOOP="$(grep "seconds" /tmp/brstminfo.txt | tail -n 1 | sed 's/.*(//' | sed 's/ seconds)//')" + echo "Now playing: \"$(echo $SONG | sed 's/\.brstm//')\"" + mpv --ab-loop-a="$STARTLOOP" --ab-loop-b="$ENDLOOP" --ab-loop-count="$LOOPCOUNT" "$SONG" +} + +forever () { + SONG="$(command ls -1 | dmenu -i)" + vgmstream-cli -m "$SONG" > /tmp/brstminfo.txt + STARTLOOP="$(grep "seconds" /tmp/brstminfo.txt | head -n 1 | sed 's/.*(//' | sed 's/ seconds)//')" + ENDLOOP="$(grep "seconds" /tmp/brstminfo.txt | tail -n 1 | sed 's/.*(//' | sed 's/ seconds)//')" + mpv --ab-loop-a="$STARTLOOP" --ab-loop-b="$ENDLOOP" --loop-file=inf "$SONG" +} + +random () { + while true; do + RANDNUM=$(shuf -i 1-$(ls -1 | wc -l) -n 1) + SONG="$(command ls | head -n $RANDNUM | tail -n 1)" + playsong + done +} + +case "$MODE" in + Forever) forever ;; + Random) random ;; +esac diff --git a/local/bin/sb-memory b/local/bin/sb-memory new file mode 100755 index 0000000..282d6f7 --- /dev/null +++ b/local/bin/sb-memory @@ -0,0 +1,27 @@ +#!/bin/sh + +_openbsd() { + TOTAL="$(free | awk '/^Mem:/ {print $2}')" + MUSED="$(top -b -n 1 | grep -o 'Real.*' | sed 's/Real: //' | sed 's/\/.*//')" + printf "$MUSED" | egrep "[0-9]{4}" > /dev/null && FUSED="$(printf "$MUSED" | cut -c -2 | sed 's/./.&/2')G" || FUSED=$MUSED + printf "$FUSED/$TOTAL\n" +} + +_freebsd() { + TOTAL="$(freecolor -om | awk '/^Mem:/ {print $2}')" + MUSED="$(freecolor -om | awk '/^Mem:/ {print $3}')" + printf "$MUSED" | egrep "[0-9]{4}" > /dev/null && FUSED="$(printf "$MUSED" | cut -c -2 | sed 's/./.&/2')G" || FUSED=""$MUSED"M" + printf "$TOTAL" | egrep "[0-9]{4}" > /dev/null && TOTAL="$(printf "$TOTAL" | cut -c -2 | sed 's/./.&/2')G" || FUSED=$TOTAL + printf "$FUSED/$TOTAL\n" +} + +_linux() { + MUSED="$(free -m | awk '/^Mem:/ {print $3}')" + echo "$MUSED" +} + +case $(uname) in + Linux) _linux ;; + OpenBSD) _openbsd ;; + FreeBSD) _freebsd ;; +esac diff --git a/local/bin/sb-network b/local/bin/sb-network new file mode 100755 index 0000000..0937126 --- /dev/null +++ b/local/bin/sb-network @@ -0,0 +1,8 @@ +#!/bin/sh +# Show local IP and transfer if connected to the internet. Opens $NETWORKMANAGER on click +NETWORKMANAGER=connman-gtk +ifconfig | grep ".*inet.*netmask" | tail -n 1 | sed 's/inet //g' | sed 's/ netmask.*//g' | sed 's/ //g' | sed 's/ //g' + +case $BLOCK_BUTTON in + 1) $NETWORKMANAGER ;; +esac diff --git a/local/bin/sb-swap b/local/bin/sb-swap new file mode 100755 index 0000000..096e308 --- /dev/null +++ b/local/bin/sb-swap @@ -0,0 +1,7 @@ +#!/bin/sh + +swap_used_kib=$(awk '/SwapTotal/ {total=$2} /SwapFree/ {free=$2} END {print total - free}' /proc/meminfo) + +swap_used_mib=$((swap_used_kib / 1024)) + +echo "${swap_used_mib}" diff --git a/local/bin/sb-volume b/local/bin/sb-volume new file mode 100755 index 0000000..0736259 --- /dev/null +++ b/local/bin/sb-volume @@ -0,0 +1,14 @@ +#!/bin/sh + +_bsd() { + sndioctl -n output.level | sed 's/0\.//' | sed 's/.$/%/' | sed 's/\.//' +} + +_linux() { + printf "$(pamixer --get-volume)%%\n" +} + +case $(uname) in + Linux) _linux ;; + *BSD) _bsd ;; +esac diff --git a/local/bin/screencast b/local/bin/screencast new file mode 100755 index 0000000..9ea3683 --- /dev/null +++ b/local/bin/screencast @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +printf "Title: " +read TITLE +printf "Sound device (ex: default, 1, 2): " +read SNDDEV + +TITLE="$(echo $TITLE | sed 's/ /_/g')" +DIRNAME="$TITLE-$(date '+%s')" +mkdir -p "$HOME/videos/screencasts/$DIRNAME" + +ffmpeg -loglevel fatal -video_size 1600x900 -framerate 30 -f x11grab -i :0.0 -c:v libx264 -preset veryfast "$HOME/videos/screencasts/$DIRNAME/video.mkv" & printf "Video recording started.\n" +aucat -f snd/$SNDDEV -o "$HOME/videos/screencasts/$DIRNAME/audio.wav" > /dev/null & printf "Audio recording started.\n\n" + +printf "Press enter to stop recording" +read lol +kill $(pgrep ffmpeg) +kill $(pgrep aucat) + +cd "$HOME/videos/screencasts/$DIRNAME" +ffmpeg -loglevel fatal -i video.mkv -i audio.wav -c copy final.mkv diff --git a/local/bin/screenie b/local/bin/screenie new file mode 100755 index 0000000..5dcf99b --- /dev/null +++ b/local/bin/screenie @@ -0,0 +1,8 @@ +#!/bin/sh +DIR="$HOME/Pictures/Screenshots" +FILE="$DIR/shot_$(date +%s).png" + +mkdir -p "$DIR" +maim -s "$FILE" +xclip -selection clipboard -t image/png -i "$FILE" +notify-send "Region Captured" "Saved and copied to clipboard" diff --git a/local/bin/screenie-active b/local/bin/screenie-active new file mode 100755 index 0000000..eab9f1b --- /dev/null +++ b/local/bin/screenie-active @@ -0,0 +1,3 @@ +#!/bin/sh +maim -i "$(xdotool getactivewindow)" /tmp/shot.png +xclip -selection clipboard -t image/png -i /tmp/shot.png diff --git a/local/bin/screenie-wlr b/local/bin/screenie-wlr new file mode 100755 index 0000000..a478ab3 --- /dev/null +++ b/local/bin/screenie-wlr @@ -0,0 +1,13 @@ +#!/bin/sh +DIR="$HOME/Pictures/Screenshots" +mkdir -p "$DIR" +TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") +FINAL_FILE="$DIR/screenshot_$TIMESTAMP.png" +TEMP_FULLSCREEN=$(mktemp /tmp/fullscreen_XXXXXX.png) +grim "$TEMP_FULLSCREEN" +TEMP_FILE=$(mktemp /tmp/screenshot_XXXXXX.png) +grim -g "$(slurp)" "$TEMP_FILE" +cp "$TEMP_FILE" "$FINAL_FILE" +wl-copy < "$TEMP_FILE" +notify-send "Screenshot" "Saved to $FINAL_FILE" -i "$TEMP_FILE" +rm "$TEMP_FILE" "$TEMP_FULLSCREEN" diff --git a/local/bin/setwall.py b/local/bin/setwall.py new file mode 100755 index 0000000..0126288 --- /dev/null +++ b/local/bin/setwall.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import os +import secrets +import subprocess + +BASE_DIR = "/home/coast/.local/src/wall" + +wallpapers = [] +for root, dirs, files in os.walk(BASE_DIR): + for file in files: + if file.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')): + wallpapers.append(os.path.join(root, file)) + +if not wallpapers: + print("No wallpapers found!") + exit(1) + +chosen_wallpaper = secrets.choice(wallpapers) +print(chosen_wallpaper) +subprocess.run(["swaybg", "-i", chosen_wallpaper, "-m", "fill"]) diff --git a/local/bin/setwall.sh b/local/bin/setwall.sh new file mode 100755 index 0000000..548d281 --- /dev/null +++ b/local/bin/setwall.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +WALL_DIR="/home/coast/.local/src/wall" +SUBDIR=$(find "$WALL_DIR" -mindepth 1 -maxdepth 1 -type d | shuf -n1) +FILE=$(find "$SUBDIR" -type f \( -iname '*.jpg' -o -iname '*.png' -o -iname '*.jpeg' \) | shuf -n1) +if [[ -n "$FILE" ]]; then + swaymsg output '*' bg "$FILE" fill +fi diff --git a/local/bin/sober b/local/bin/sober new file mode 100644 index 0000000..69593c7 --- /dev/null +++ b/local/bin/sober @@ -0,0 +1,2 @@ +#!sh +flatpak run org.vinegarhq.Sober diff --git a/local/bin/stacki3 b/local/bin/stacki3 new file mode 100755 index 0000000..ad65f02 --- /dev/null +++ b/local/bin/stacki3 @@ -0,0 +1,8 @@ +#!/usr/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from stacki3 import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/start-meowgun.sh b/local/bin/start-meowgun.sh new file mode 100755 index 0000000..bcdd9e9 --- /dev/null +++ b/local/bin/start-meowgun.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cd "$HOME/Downloads/MeowGun" && wine meowgun.exe diff --git a/local/bin/start-wq.sh b/local/bin/start-wq.sh new file mode 100755 index 0000000..4c8563e --- /dev/null +++ b/local/bin/start-wq.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cd "/home/coast/.wine/drive_c/WolfQuest/" && env WINEDLLOVERRIDES="winhttp=n,b" wine64.bin WolfQuestAE.exe diff --git a/local/bin/start_qtile.sh b/local/bin/start_qtile.sh new file mode 100755 index 0000000..0b4758f --- /dev/null +++ b/local/bin/start_qtile.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +wlr-randr --output eDP-1 --off & + +( + if ! pgrep -x foot >/dev/null; then + foot -s + fi +) & + +( + if ! pgrep -x udiskie >/dev/null; then + /usr/bin/udiskie + fi +) & + + +( + if ! pgrep -x swaybg >/dev/null; then + swaybg -i "/home/coast/.local/src/wall/landscapes/1685466762541384.jpg" & + fi +) & + +( + if ! pgrep -x polkit-gnome-authentication-agent >/dev/null; then + /usr/libexec/polkit-gnome-authentication-agent-1 + fi +) & + +( + if ! pgrep -x eww >/dev/null; then + eww daemon & + eww open-many year month day & + else + pkill eww + eww daemon & + eww open-many year month day & + fi +) & diff --git a/local/bin/startniri b/local/bin/startniri new file mode 100755 index 0000000..a20c6cb --- /dev/null +++ b/local/bin/startniri @@ -0,0 +1,8 @@ +#!/bin/sh +export WAYLAND_DISPLAY=wayland-0 +export XDG_CURRENT_DESKTOP=niri +export XDG_SESSION_TYPE=wayland +export XWAYLAND_DISPLAY=:1 + +xwayland-satellite & +niri & diff --git a/local/bin/startw b/local/bin/startw new file mode 100755 index 0000000..348618c --- /dev/null +++ b/local/bin/startw @@ -0,0 +1,3 @@ +#!/bin/sh +dbus-run-session qtile start -b wayland + diff --git a/local/bin/swallow b/local/bin/swallow new file mode 100755 index 0000000..38756f9 --- /dev/null +++ b/local/bin/swallow @@ -0,0 +1,13 @@ +#!/bin/sh +COMMAND="$*" +BINARY="$(printf "$COMMAND" | sed 's/ .*//')" +ARGS="$(printf "$COMMAND" | sed "s/$BINARY //")" + +main() { + WINID=$(xdo id) + xdo hide $WINID + $BINARY "$ARGS" || $BINARY $ARGS + xdo show $WINID +} + +[ "$1" = "" ] && printf "Error: You must provide at least one argument.\nExample usage: swallow mpv ~/videos/AmericanPsycho.mkv\n" || main "$@" diff --git a/local/bin/swap.start b/local/bin/swap.start new file mode 100755 index 0000000..585568e --- /dev/null +++ b/local/bin/swap.start @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +# Open encrypted swap manually + +/usr/bin/cryptsetup open /dev/nvme0n1p2 cryptswap +/usr/sbin/swapon /dev/dm-1 diff --git a/local/bin/swap.stop b/local/bin/swap.stop new file mode 100755 index 0000000..b5294b1 --- /dev/null +++ b/local/bin/swap.stop @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +# Close encrypted swap manually + +swapoff /dev/dm-1 +cryptsetup close cryptswap diff --git a/local/bin/sway-status b/local/bin/sway-status new file mode 100755 index 0000000..064e181 --- /dev/null +++ b/local/bin/sway-status @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +# Date +date=$(date "+%I:%M %p") + +# CPU temp +cpu=$(sensors | grep "Package" | cut -f 1-3,5 -d " ") + +# Alsa master volume +volume=$(amixer get Master | grep "Right:" | cut -f 7,8 -d " ") + +# Battery percentage +batt="" +for b in /sys/class/power_supply/BAT*; do + if [ -d "$b" ]; then + if [ -r "$b/capacity" ]; then + cap=$(<"$b/capacity") + else + cap=0 + fi + if [ -z "$batt" ]; then + batt="${cap}%" + else + batt="$batt ${cap}%" + fi + fi +done +# If no battery found +if [ -z "$batt" ]; then + batt="None" +fi + +# Status bar +echo "BAT: $batt | $date" + diff --git a/local/bin/tabulate b/local/bin/tabulate new file mode 100755 index 0000000..ed4064c --- /dev/null +++ b/local/bin/tabulate @@ -0,0 +1,8 @@ +#!/usr/lib/python-exec/python3.13/python +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from tabulate import _main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(_main()) diff --git a/local/bin/toggle-screens.sh b/local/bin/toggle-screens.sh new file mode 100755 index 0000000..dcda9f3 --- /dev/null +++ b/local/bin/toggle-screens.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +outputs_json="$(niri msg --json outputs)" + +echo "$outputs_json" | jq -c '.[]' | while read -r out; do + name=$(echo "$out" | jq -r '.name') + dpms=$(echo "$out" | jq -r '.dpms') + + if [ "$dpms" = "On" ]; then + echo "Turning off $name" + niri msg output "$name" dpms off + fi +done diff --git a/local/bin/tun2socks b/local/bin/tun2socks Binary files differnew file mode 100755 index 0000000..2f8db64 --- /dev/null +++ b/local/bin/tun2socks diff --git a/local/bin/updateriver b/local/bin/updateriver new file mode 100755 index 0000000..3632cea --- /dev/null +++ b/local/bin/updateriver @@ -0,0 +1,79 @@ +#!/usr/bin/env lua + +local home = os.getenv("home") or os.getenv("HOME") +local cache_dir = home .. "/.cache" +local zig_cache = cache_dir .. "/zig" +local proxy_cmd = "ssh -o ProxyCommand='nc -X 5 -x 127.0.0.1:65000 %h %p'" + +local project_dir = arg[1] or (home .. "/Projects/river/river") + +local function run(cmd) + local ok = os.execute(cmd) + if not ok then + io.stderr:write("failed: " .. cmd .. "\n") + os.exit(1) + end +end + +local function fetch_git_dep(path, commit) + local name = path:match("([^/]+)$"):gsub("^zig%-", "") + local tmp = cache_dir .. "/" .. name .. "-tmp" + local tarball = cache_dir .. "/" .. name .. ".tar.gz" + + run("rm -rf " .. tmp) + run('GIT_SSH_COMMAND="' .. proxy_cmd .. '" git clone git@codeberg.org:' .. path .. ".git " .. tmp) + run("git -C " .. tmp .. " checkout " .. commit) + run("tar -czf " .. tarball .. " -C " .. cache_dir .. " " .. name .. "-tmp") + run("zig fetch --global-cache-dir " .. zig_cache .. " file://" .. tarball) + run( + "sed -i '/\\." + .. name + .. ' = /,/\\.hash/{s|.url = "[^"]*"|.url = "file://' + .. tarball + .. "\"|}' " + .. project_dir + .. "/build.zig.zon" + ) +end + +local function fetch_https_dep(url) + local filename = url:match("([^/]+)$") + local name = filename:gsub("^zig%-", ""):gsub("%-v?[0-9].*$", ""):gsub("%.tar%.gz$", "") + local tarball = cache_dir .. "/" .. filename + + run('GIT_SSH_COMMAND="' .. proxy_cmd .. '" curl -x socks5h://127.0.0.1:65000 -Lo ' .. tarball .. " " .. url) + run("zig fetch --global-cache-dir " .. zig_cache .. " file://" .. tarball) + run( + "sed -i '/\\." + .. name + .. ' = /,/\\.hash/{s|.url = "[^"]*"|.url = "file://' + .. tarball + .. "\"|}' " + .. project_dir + .. "/build.zig.zon" + ) +end + +run("git -C " .. project_dir .. " pull") + +local zon = io.open(project_dir .. "/build.zig.zon", "r") +if not zon then + io.stderr:write("cant open build.zig.zon\n") + os.exit(1) +end + +for line in zon:lines() do + local path, commit = line:match("git%+https://codeberg%.org/([^?]+)%?ref=[^#]+#([a-f0-9]+)") + if path and commit then + fetch_git_dep(path, commit) + else + local url = line:match('"(https://codeberg%.org/[^"]+%.tar%.gz)"') + if url then + fetch_https_dep(url) + end + end +end + +zon:close() + +run("cd " .. project_dir .. " && zig build -Doptimize=ReleaseSafe --prefix " .. home .. "/.local install") diff --git a/local/bin/upim b/local/bin/upim new file mode 100755 index 0000000..cbd07d1 --- /dev/null +++ b/local/bin/upim @@ -0,0 +1,21 @@ +#!/usr/bin/env sh +if [ -z "$1" ]; then + echo "usage: $0 <file>" + exit 1 +fi +FILE="$1" +RESPONSE=$(curl -s -X POST \ + -F "file=@${FILE}" \ + https://coast.is-terrible.com/api/files/create) +URL=$(echo "$RESPONSE" | jq -r '.url') +THUMBNAIL_URL=$(echo "$RESPONSE" | jq -r '.thumb') +DELETION_URL=$(echo "$RESPONSE" | jq -r '.del_url') +ERROR=$(echo "$RESPONSE" | jq -r '.error') +if [ "$ERROR" != "null" ]; then + echo "Error uploading file: $ERROR" + exit 1 +fi +echo "file uploaded successfully!" +echo "url: $URL" +echo "thumbnail url: $THUMBNAIL_URL" +echo "deletion url: $DELETION_URL" diff --git a/local/bin/usbmount b/local/bin/usbmount new file mode 100755 index 0000000..81ba1a5 --- /dev/null +++ b/local/bin/usbmount @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys + +RED = "\033[0;31m" +RESET = "\033[0m" + +def main(): + if os.geteuid() != 0: + print(f"{RED}[!] Superuser access is required{RESET}") + sys.exit(1) + + if not os.path.exists("/dev/sda"): + print(f"{RED}[!] USB not found!{RESET}") + sys.exit(1) + + print(f"{RED}[*] Decrypting /dev/sda1...{RESET}") + try: + subprocess.run(["cryptsetup", "open", "/dev/sda1", "sda1_crypt"], check=True) + subprocess.run(["mount", "/dev/mapper/sda1_crypt", "/mnt/usb", "--mkdir"], check=True) + print(f"{RED}[*] Decrypted and mounted to /mnt/usb!{RESET}") + except subprocess.CalledProcessError as e: + print(f"{RED}[!] Error: {e}{RESET}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/local/bin/usbumount b/local/bin/usbumount new file mode 100755 index 0000000..ffe68bc --- /dev/null +++ b/local/bin/usbumount @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys + +RED = "\033[0;31m" +RESET = "\033[0m" + +def run(cmd, fail_msg): + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + print(f"{RED}[!] {fail_msg}{RESET}") + sys.exit(1) + +def main(): + if os.geteuid() != 0: + print(f"{RED}[!] Superuser access is required{RESET}") + sys.exit(1) + + print(f"{RED}[*] Unmounting /mnt/usb...{RESET}") + run(["umount", "/mnt/usb"], "Failed to unmount /mnt/usb") + + print(f"{RED}[*] Closing encrypted device...{RESET}") + run(["cryptsetup", "close", "sda1_crypt"], "Failed to close mapper device") + + print(f"{RED}[*] Unmounted and closed successfully!{RESET}") + +if __name__ == "__main__": + main() diff --git a/local/bin/uwuify.awk b/local/bin/uwuify.awk new file mode 100755 index 0000000..7b42027 --- /dev/null +++ b/local/bin/uwuify.awk @@ -0,0 +1,75 @@ +#!awk -f + +function uwuify(s, o) { + o = s + + # r/l -> w/W + o = gensub(/[rl]/, "w", "g", o) + o = gensub(/[RL]/, "W", "g", o) + + # n + vowel -> ny + o = gensub(/N([AEIOU])/, "NY\\1", "g", o) + o = gensub(/([nN])([aeiouAEIOU])/, "\\1y\\2", "g", o) + + # soft c before e/i + o = gensub(/c([ie])/, "sh\\1", "g", o) + o = gensub(/C([ie])/, "Sh\\1", "g", o) + o = gensub(/C([IE])/, "SH\\1", "g", o) + + # th -> d + o = gensub(/th/, "d", "g", o) + o = gensub(/Th/, "D", "g", o) + o = gensub(/TH/, "D", "g", o) + + # ove -> uv + o = gensub(/ove/, "uv", "g", o) + o = gensub(/OVE/, "UV", "g", o) + + # ing -> in’ + o = gensub(/ing\b/, "in’", "g", o) + o = gensub(/ING\b/, "IN’", "g", o) + + # punctuation uwuifier + o = gensub(/!+/, " owo~ ", "g", o) + o = gensub(/\?+/, " uwu?", "g", o) + o = gensub(/\.{3}/, "… >w< ", "g", o) + + return o +} + +function uwuify_line(line, pre, post, uw_pre, diff, fullseq, num, newnum, newseq) { + if (match(line, /^(.*:)/)) { + pre = substr(line, 1, RLENGTH) + post = substr(line, RLENGTH + 1) + + uw_pre = uwuify(pre) + diff = length(uw_pre) - length(pre) + + if (match(uw_pre, /\033\[[0-9]+C/)) { + fullseq = substr(uw_pre, RSTART, RLENGTH) + if (match(fullseq, /\033\[([0-9]+)C/, m)) { + num = m[1] + newnum = num - diff + if (newnum < 0) newnum = 0 + newseq = "\033[" newnum "C" + uw_pre = substr(uw_pre, 1, RSTART - 1) newseq substr(uw_pre, RSTART + RLENGTH) + } + } + + return uw_pre uwuify(post) + } + return uwuify(line) +} + +{ + # Kitty image protocol lines stay raw + if ($0 ~ /\033_G/) { + print $0 + } else if ($0 ~ /\033\[[0-9]+C/) { + out = uwuify_line($0) + print out + } else { + out = uwuify($0) + print out + } +} diff --git a/local/bin/vesktop.sh b/local/bin/vesktop.sh new file mode 100755 index 0000000..5fa9d93 --- /dev/null +++ b/local/bin/vesktop.sh @@ -0,0 +1,2 @@ +#!/bin/sh +vesktop --ozone-platform=wayland diff --git a/local/bin/win2xcur b/local/bin/win2xcur new file mode 100755 index 0000000..ef5b208 --- /dev/null +++ b/local/bin/win2xcur @@ -0,0 +1,8 @@ +#!/usr/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from win2xcur.main.win2xcur import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/wsdump b/local/bin/wsdump new file mode 100755 index 0000000..e047f13 --- /dev/null +++ b/local/bin/wsdump @@ -0,0 +1,8 @@ +#!/usr/lib/python-exec/python3.13/python +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from websocket._wsdump import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/x2wincur b/local/bin/x2wincur new file mode 100755 index 0000000..68e4a97 --- /dev/null +++ b/local/bin/x2wincur @@ -0,0 +1,8 @@ +#!/usr/bin/python3.13 +# -*- coding: utf-8 -*- +import re +import sys +if __name__ == '__main__': + from win2xcur.main.x2wincur import main + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/local/bin/yellusb b/local/bin/yellusb new file mode 100755 index 0000000..1f53ecd --- /dev/null +++ b/local/bin/yellusb @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import pyudev +import subprocess + +context = pyudev.Context() +monitor = pyudev.Monitor.from_netlink(context) +monitor.filter_by(subsystem='block') + +for device in iter(monitor.poll, None): + if device.action == 'add': + print(f"New device detected: {device.device_node}") + subprocess.run(f"notify-send 'New device connected: {device.device_node}'", shell=True)
\ No newline at end of file |
