Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
* James Utils
|
||||||
|
|
||||||
|
This repository contains various shell scripts I use for either daily computer use or home network maintenance.
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#pacmd set-default-sink alsa_output.usb-Logitech_Logitech_G933_Gaming_Wireless_Headset-00.analog-stereo
|
||||||
|
#pacmd set-default-source alsa_input.usb-Logitech_Logitech_G933_Gaming_Wireless_Headset-00.analog-mono
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
QUDELIX_SINK="alsa_output.usb-QTIL_Qudelix-5K_USB_DAC_ABCDEF0123456789-00.analog-stereo"
|
||||||
|
SPEAKER_SINK="alsa_output.pci-0000_0f_00.4.3.iec958-stereo"
|
||||||
|
STAGE_SINK="alsa_output.usb-ACTIONS_Stage_V2-00.analog-stereo"
|
||||||
|
BOSE_SINK="bluez_output.78_2B_64_CE_04_03.1"
|
||||||
|
FRACTAL_SINK="alsa_output.usb-Fractal_Fractal_Scape_Dongle_00000000911AD5560372-00.analog-stereo"
|
||||||
|
SNAPCAST_SINK="snapcast_out"
|
||||||
|
YETI_SOURCE="alsa_input.usb-Blue_Microphones_Yeti_Nano_2231SQ0017G8_888-000476140106-00.analog-stereo"
|
||||||
|
NOISETORCH_SOURCE="NoiseTorch Microphone for Yeti Nano"
|
||||||
|
FRACTAL_SOURCE="alsa_input.usb-Fractal_Fractal_Scape_Dongle_00000000911AD5560372-00.mono-fallback"
|
||||||
|
|
||||||
|
switchAudio() {
|
||||||
|
case "$1" in
|
||||||
|
"-s")
|
||||||
|
#echo fractal
|
||||||
|
echo -e "fractal\0icon\x1faudio-headphones"
|
||||||
|
#echo snapcast
|
||||||
|
echo -e "snapcast"
|
||||||
|
#echo -en "Firefox\0icon\x1ffirefox" | fuzzel --dmenu
|
||||||
|
echo -e "stage\0icon\x1faudio-speakers"
|
||||||
|
#echo "stage"
|
||||||
|
echo -e "bose\0icon\x1fbluetooth"
|
||||||
|
#echo "qudelix"
|
||||||
|
echo -e "qudelix\0icon\x1faudio-headphones"
|
||||||
|
exit 0;
|
||||||
|
;;
|
||||||
|
"qudelix")
|
||||||
|
local sink="$QUDELIX_SINK"
|
||||||
|
# local source="$NOISETORCH_SOURCE"
|
||||||
|
local source="$YETI_SOURCE"
|
||||||
|
;;
|
||||||
|
"speakers")
|
||||||
|
local sink="$SPEAKER_SINK"
|
||||||
|
local source="$YETI_SOURCE"
|
||||||
|
;;
|
||||||
|
"stage")
|
||||||
|
local sink="$STAGE_SINK"
|
||||||
|
local source="$YETI_SOURCE"
|
||||||
|
;;
|
||||||
|
"bose")
|
||||||
|
local sink="$BOSE_SINK"
|
||||||
|
local source="$YETI_SOURCE"
|
||||||
|
;;
|
||||||
|
"fractal")
|
||||||
|
local sink="$FRACTAL_SINK"
|
||||||
|
local source="$FRACTAL_SOURCE"
|
||||||
|
;;
|
||||||
|
"snapcast")
|
||||||
|
local sink="$SNAPCAST_SINK"
|
||||||
|
local source="$FRACTAL_SOURCE"
|
||||||
|
;;
|
||||||
|
esac;
|
||||||
|
|
||||||
|
local sourceCommand="pactl move-source-output {} $source"
|
||||||
|
local sinkCommand="pactl move-sink-input {} $sink"
|
||||||
|
|
||||||
|
pactl set-default-sink $sink
|
||||||
|
pactl list | grep -o -E 'Sink Input #([0-9]+)' | cut -d"#" -f2 | xargs -I '{}' $sinkCommand
|
||||||
|
#pactl list | grep -o -E 'Source Output #([0-9]+)' | cut -d"#" -f2 | xargs -I '{}' $sourceCommand
|
||||||
|
pactl set-default-source $source
|
||||||
|
echo $1 > $HOME/.last_audio
|
||||||
|
notify-send -a "Audio" "Switched to $1"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nextAudio() {
|
||||||
|
local last_audio=$(cat $HOME/.last_audio)
|
||||||
|
case "$last_audio" in
|
||||||
|
"fractal")
|
||||||
|
local next="speakers"
|
||||||
|
;;
|
||||||
|
"speakers")
|
||||||
|
local next="fractal"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
local next="fractal"
|
||||||
|
;;
|
||||||
|
esac;
|
||||||
|
|
||||||
|
switchAudio $next
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"next")
|
||||||
|
nextAudio
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
switchAudio $1
|
||||||
|
;;
|
||||||
|
esac;
|
||||||
Executable
+79
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/nu
|
||||||
|
|
||||||
|
let launcher_apps = open $"($env.HOME)/.config/switchrun/apps.nuon"
|
||||||
|
|
||||||
|
def lookup_window_id [running_apps, app_id] {
|
||||||
|
let matches = $running_apps | where app_id == $app_id
|
||||||
|
if ($matches | is-empty) {
|
||||||
|
"none"
|
||||||
|
} else {
|
||||||
|
$matches | get id | first | into string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def switch_to [target_window_id: string] {
|
||||||
|
let focus_cmd = {Action: { FocusWindow: { id: ($target_window_id | into int ) } } }
|
||||||
|
$focus_cmd | to json -r | socat STDIO $env.NIRI_SOCKET
|
||||||
|
}
|
||||||
|
|
||||||
|
def launch [target_app_id: string] {
|
||||||
|
let app = (
|
||||||
|
$launcher_apps |
|
||||||
|
where app_id == $target_app_id |
|
||||||
|
first
|
||||||
|
)
|
||||||
|
print $app.exec
|
||||||
|
print ...$app.args
|
||||||
|
if $app != null { run-external $app.exec ...$app.args} else { print "no exec found" }
|
||||||
|
}
|
||||||
|
|
||||||
|
def main [target_app_id: string] {
|
||||||
|
let running_apps = niri msg --json windows | from json
|
||||||
|
let matches = $running_apps | where app_id == $target_app_id
|
||||||
|
print $matches
|
||||||
|
if ($matches | is-empty) {
|
||||||
|
launch $target_app_id
|
||||||
|
} else {
|
||||||
|
let focused_matches = $matches | enumerate | where item.is_focused == true | get index
|
||||||
|
if ($focused_matches | is-empty) {
|
||||||
|
switch_to (($matches | first | get id) | into string)
|
||||||
|
} else {
|
||||||
|
# In the event of multiple matches, switch to the one after the focused one - wrapping around
|
||||||
|
# That way we will cycle through them
|
||||||
|
let target_index = ($focused_matches | first) - 1
|
||||||
|
print $target_index
|
||||||
|
print ($matches | length)
|
||||||
|
let target_window = if ($target_index < 0) { $matches | last } else { ($matches | get $target_index) }
|
||||||
|
switch_to ($target_window.id | into string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "main list" [tag?: string] {
|
||||||
|
let running_apps = niri msg --json windows | from json
|
||||||
|
|
||||||
|
# Optionally narrow to apps carrying the requested tag.
|
||||||
|
let filtered = (if ($tag | is-empty) {
|
||||||
|
$launcher_apps
|
||||||
|
} else {
|
||||||
|
$launcher_apps | where { |app| ($tag in ($app.tags? | default [])) }
|
||||||
|
})
|
||||||
|
|
||||||
|
if ($filtered | is-empty) {
|
||||||
|
print $"No applications match tag '($tag)'"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let apps = $filtered | each { |app| $app | insert window_id { lookup_window_id $running_apps $app.app_id } }
|
||||||
|
# if the selected app_id is running then
|
||||||
|
# focus it by its window id (first window id for that app id is fine)
|
||||||
|
# if it's not running then launch it using the app's desktop entry
|
||||||
|
#
|
||||||
|
let app_lines = $apps | each { $"($in.name) - [($in.app_id), ($in.window_id)]" }
|
||||||
|
|
||||||
|
let prompt = if ($tag | is-empty) { "Launch/Switch" } else { $"Launch/Switch [($tag)]" }
|
||||||
|
let selection = $app_lines | each { echo $in } | str join "|" | rofi -dmenu -i -p $prompt -sep "|"
|
||||||
|
let parsed = $selection | parse "{name} - [{app_id}, {window_id}]" | first
|
||||||
|
let match = $apps | where app_id == $parsed.app_id | first
|
||||||
|
if $parsed.window_id == "none" { launch $match.app_id } else { switch_to $match.window_id }
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
[ { name: "Firefox - Personal"
|
||||||
|
, app_id: "firefox_personal"
|
||||||
|
, exec: "/usr/lib/firefox/firefox"
|
||||||
|
, args: ["--class=firefox", "-P", "personal", "--name=firefox_personal"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Firefox - Flipstone"
|
||||||
|
, app_id: "firefox_flipstone"
|
||||||
|
, exec: "/usr/lib/firefox/firefox"
|
||||||
|
, args: ["--class=firefox", "-P", "flipstone", "--name=firefox_flipstone"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Obsidian"
|
||||||
|
, app_id: "obsidian"
|
||||||
|
, exec: "/usr/bin/obsidian"
|
||||||
|
, args: []
|
||||||
|
}
|
||||||
|
, { name: "Slack"
|
||||||
|
, app_id: "Slack"
|
||||||
|
, exec: "/usr/bin/slack"
|
||||||
|
, args: ["--ozone-platform=wayland", "-s", "%U"]
|
||||||
|
}
|
||||||
|
, { name: "Emacs"
|
||||||
|
, app_id: "jmacs"
|
||||||
|
, exec: "emacsclient"
|
||||||
|
, args: ["--alternate-editor=", "--create-frame"]
|
||||||
|
}
|
||||||
|
, { name: "Flipstone - Standup"
|
||||||
|
, app_id: "chrome-dokoinnladjmopjidoajilmllagdhbnc-Work"
|
||||||
|
, exec: "/usr/bin/chromium"
|
||||||
|
, args: ["--ozone-platform=wayland", "--profile-directory=Work", "--app-id=dokoinnladjmopjidoajilmllagdhbnc"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Flipstone - Gather"
|
||||||
|
, app_id: "chrome-monjdkojdghbbohnhnccccmkogahhgpj-Work"
|
||||||
|
, exec: "/usr/bin/chromium"
|
||||||
|
, args: ["--ozone-platform=wayland", "--profile-directory=Work", "--app-id=monjdkojdghbbohnhnccccmkogahhgpj"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Text Messages"
|
||||||
|
, app_id: "chrome-hpfldicfbfomlpcikngkocigghgafkph-Profile_1"
|
||||||
|
, exec: "/usr/bin/chromium"
|
||||||
|
, args: ["--ozone-platform=wayland", "--profile-directory=Profile_1", "--app-id=hpfldicfbfomlpcikngkocigghgafkph"]
|
||||||
|
}
|
||||||
|
, { name: "Whatsi (WhatsApp)"
|
||||||
|
, app_id: "com.ktechpit.whatsie"
|
||||||
|
, exec: "whatsie"
|
||||||
|
, args: []
|
||||||
|
}
|
||||||
|
, { name: "Signal"
|
||||||
|
, app_id: "signal"
|
||||||
|
, exec: "signal-desktop"
|
||||||
|
, args: ["--password-store=gnome-libsecret"]
|
||||||
|
}
|
||||||
|
, { name: "Chromium"
|
||||||
|
, app_id: "chromium"
|
||||||
|
, exec: "chromium"
|
||||||
|
, args: ["--ozone-platform=wayland"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Thunar (file manager)"
|
||||||
|
, app_id: "thunar"
|
||||||
|
, exec: "thunar"
|
||||||
|
, args: []
|
||||||
|
}
|
||||||
|
, { name: "Obsidian"
|
||||||
|
, app_id: "obsidian"
|
||||||
|
, exec: "/usr/bin/obsidian"
|
||||||
|
, args: []
|
||||||
|
}
|
||||||
|
, { name: "WezTerm"
|
||||||
|
, app_id: "org.wezfurlong.wezterm"
|
||||||
|
, exec: "/usr/bin/wezterm"
|
||||||
|
, args: []
|
||||||
|
, tags: ["terminals"]
|
||||||
|
}
|
||||||
|
, { name: "WezTerm-Flipstone-Dev"
|
||||||
|
, app_id: "lol.roo.flipstone.dev.term"
|
||||||
|
, exec: "/usr/bin/wezterm"
|
||||||
|
, args: ["--config", "color_scheme=\"zenbones_dark\"", "start", "--class", "lol.roo.flipstone.dev.term"]
|
||||||
|
, tags: ["terminals"]
|
||||||
|
}
|
||||||
|
, { name: "WezTerm-Flipstone-FSDB"
|
||||||
|
, app_id: "lol.roo.flipstone.fsdb.term"
|
||||||
|
, exec: "/usr/bin/wezterm"
|
||||||
|
, args: ["--config", "color_scheme=\"Urple\"", "start", "--class", "lol.roo.flipstone.fsdb.term"]
|
||||||
|
, tags: ["terminals"]
|
||||||
|
}
|
||||||
|
, { name: "WezTerm-Home"
|
||||||
|
, app_id: "lol.roo.home.term"
|
||||||
|
, exec: "/usr/bin/wezterm"
|
||||||
|
, args: ["--config", "color_scheme=\"Zenburn\"", "start", "--class", "lol.roo.home.term"]
|
||||||
|
, tags: ["terminals"]
|
||||||
|
}
|
||||||
|
, { name: "Heidi"
|
||||||
|
, app_id: "mpv"
|
||||||
|
, exec: "mpv"
|
||||||
|
, args: ["rtsp://camera:PMLVK2Kp4r@192.168.10.63/stream1"]
|
||||||
|
}
|
||||||
|
, { name: "Chromium - Personal"
|
||||||
|
, app_id: "chromium-personal"
|
||||||
|
, exec: "/usr/bin/chromium"
|
||||||
|
, args: ["--class=chromium-personal", "--profile-directory=Personal"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
, { name: "Chromium - Work"
|
||||||
|
, app_id: "chromium-work"
|
||||||
|
, exec: "/usr/bin/chromium"
|
||||||
|
, args: ["--class=chromium-work", "--profile-directory=Work"]
|
||||||
|
, tags: ["browser"]
|
||||||
|
}
|
||||||
|
]
|
||||||
Executable
+61
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env nu
|
||||||
|
|
||||||
|
# install.nu — install scripts and config from this repo into the user's home.
|
||||||
|
#
|
||||||
|
# bin/ -> $HOME/bin (made executable, overwrite silently)
|
||||||
|
# config/ -> $HOME/.config/ (mirrored recursively, overwrite silently)
|
||||||
|
#
|
||||||
|
# The repo root is resolved relative to this script's own location, so it
|
||||||
|
# works regardless of the current working directory.
|
||||||
|
|
||||||
|
def "repo-root" [] {
|
||||||
|
$env.CURRENT_FILE | path dirname | path expand
|
||||||
|
}
|
||||||
|
|
||||||
|
# Recursively mirror a source directory tree into a target directory,
|
||||||
|
# overwriting existing files and creating needed subdirectories.
|
||||||
|
# Optionally chmod +x each target file.
|
||||||
|
def "install-tree" [source_dir: path, target_dir: path, make_exec: bool] {
|
||||||
|
if not ($source_dir | path exists) {
|
||||||
|
error make { msg: $"Source directory not found: ($source_dir)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir $target_dir
|
||||||
|
|
||||||
|
# Enumerate all files under source_dir (dirs filtered; hidden files included).
|
||||||
|
let files = (glob -D $"($source_dir)/**/*")
|
||||||
|
if ($files | is-empty) {
|
||||||
|
error make { msg: $"No files found in ($source_dir)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
let installed = ($files | each { |file|
|
||||||
|
let rel = ($file | path relative-to $source_dir)
|
||||||
|
let dest = ($target_dir | path join $rel)
|
||||||
|
# Ensure the parent directory exists, then copy the file.
|
||||||
|
mkdir ($dest | path dirname)
|
||||||
|
cp $file $dest
|
||||||
|
if $make_exec { chmod +x $dest }
|
||||||
|
$dest
|
||||||
|
})
|
||||||
|
|
||||||
|
$installed | each { |path| print $"installed: ($path)" }
|
||||||
|
|
||||||
|
let count = ($installed | length)
|
||||||
|
print $"installed ($count) entries into ($target_dir)"
|
||||||
|
}
|
||||||
|
|
||||||
|
def "main" [] {
|
||||||
|
let root = (repo-root)
|
||||||
|
|
||||||
|
let bin_source = ($root | path join bin)
|
||||||
|
let bin_target = ($env.HOME | path join bin | path expand)
|
||||||
|
print $"(ansi cyan_bold)Installing scripts(ansi reset) bin/ -> ($bin_target)"
|
||||||
|
install-tree $bin_source $bin_target true
|
||||||
|
|
||||||
|
print ""
|
||||||
|
|
||||||
|
let cfg_source = ($root | path join config)
|
||||||
|
let cfg_target = ($env.HOME | path join .config | path expand)
|
||||||
|
print $"(ansi cyan_bold)Installing config(ansi reset) config/ -> ($cfg_target)"
|
||||||
|
install-tree $cfg_source $cfg_target false
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user