Various scripts that I maintain

Initial Commit

Signed-off-by: Shiloh Fen <shiloh@shilohfen.com>

+242
+39
README.md
··· 1 + Scripts 2 + ======= 3 + 4 + Various scripts and Nushell modules that I maintain or use. 5 + 6 + # Nushell Modules 7 + 8 + ## Nebula 9 + Wrapper to make setting up new hosts in a nebula network easier. 10 + 11 + 12 + # Scripts 13 + 14 + ## Nushell 15 + 16 + ### ADB Auto Connect 17 + Automatically find and connect to an Android device with Wireless Debugging over the local network. 18 + 19 + You'll need to create a file at `~/.config/adb-auto-connect.nuon` with the MAC Addresses you want to search for. For example: 20 + ```json 21 + [ 22 + "ff:ff:ff:ff:ff:ff", 23 + "aa:aa:aa:aa:aa:aa" 24 + ] 25 + ``` 26 + 27 + ### Auto Benchmark 28 + Set up and run a Blender benchmark on the specified device, then automatically compare your results to the results on [Blender Open Data](https://opendata.blender.org/). 29 + 30 + ### ln-bin 31 + Quickly symlink executable files to `~/.local/bin/` 32 + 33 + ### yt-rss 34 + Get an RSS feed for the specified YouTube channel. 35 + 36 + ## Bash 37 + 38 + ### oscavmgr-launch 39 + Slightly modified version of Galister's oscavmgr start script. Launches oscavmgr and VrcAdvert together.
+15
bash/oscavmgr-launch.sh
··· 1 + #!/usr/bin/env bash 2 + 3 + # stop VrcAdvert after OscAvMgr quits 4 + trap 'jobs -p | xargs kill' EXIT 5 + 6 + VrcAdvert OscAvMgr 9402 9002 --tracking & 7 + 8 + # If using WiVRn 9 + oscavmgr openxr 10 + 11 + ## If using ALVR 12 + #oscavmgr alvr 13 + 14 + ## If using Project Babble and/or EyeTrackVR 15 + #oscavmgr babble
+33
nushell/adb-auto-connect.nu
··· 1 + #!/usr/bin/nu 2 + 3 + const mac = open "~/.config/adb-auto-connect.nuon" 4 + 5 + def main [] { 6 + let connected = (adb devices -l | lines | skip | drop | length) > 0 7 + 8 + if $connected { 9 + print "Already Connected" 10 + } else { 11 + let ip = ip neigh 12 + | lines 13 + | parse "{ip} {type} {device} lladdr {mac} {status}" 14 + | where mac in $mac 15 + | get ip.0 16 + 17 + let port = nmap -p 37000-65000 --open --max-retries 1 --min-rate 500000 -T5 -oX - $ip 18 + | lines 19 + | skip 4 20 + | str join "\n" 21 + | from xml 22 + | get content 23 + | where tag == host 24 + | get content.0 25 + | where tag == ports 26 + | get content.0 27 + | where tag == port 28 + | get attributes.portid.0 29 + 30 + adb connect $"($ip):($port)" 31 + } 32 + 33 + }
+63
nushell/auto-benchmark.nu
··· 1 + #!/usr/bin/nu 2 + 3 + use std [log assert] 4 + 5 + def main [ 6 + --debug: string # NUON 7 + ] { 8 + log info "Getting latest version" 9 + let version = benchmark-launcher-cli blender list 10 + | parse "{version}\t{download_size}" 11 + | get 0.version 12 + 13 + log info "Getting latest scenes" 14 + let scenes = benchmark-launcher-cli scenes list --blender-version=($version) 15 + | parse "{name}\t{download_size}" 16 + | get name 17 + 18 + log info "Selecting device" 19 + let device = benchmark-launcher-cli devices --blender-version=($version) 20 + | parse "{device}\t{type}" 21 + | each {|e| $e.type + ": " + $e.device} 22 + | input list "Choose a device to benchmark" 23 + | split row ": " 24 + | {name: $in.1, type: $in.0} 25 + 26 + log info "Starting benchmark" 27 + let results = if $debug != null {$debug | from nuon} else { 28 + benchmark-launcher-cli benchmark ...$scenes --blender-version=($version) --device-type=($device.type) --device-name=($device.name) --json | from json 29 + } 30 + log info "Done!" 31 + 32 + let sum = $results.stats.samples_per_minute | math sum 33 + # HACK: It doesn't look like open data has a normal API so we have to do a bit of a workaround 34 + let opendata = http get $"https://opendata.blender.org/benchmarks/query/?device_name=($device.name)&blender_version=($version)&response_type=datatables" 35 + | $"[($in.columns.display_name | to nuon); ($in.rows | to nuon | str substring 1..-2)]" 36 + | from nuon 37 + let opendata_median = $opendata | get 'Median Score' | math median 38 + let diff = $sum - $opendata_median 39 + 40 + log debug "" 41 + log debug $"Blender Version: ($version)" 42 + log debug $"Benchmark Launcher Version: ($results.0.benchmark_launcher.label)" 43 + log debug $"Benchmark Script Version: ($results.0.benchmark_script.label)" 44 + log debug $"Device: ($device.name)" 45 + log debug $"Scenes: ($scenes | str join ', ')" 46 + log info "" 47 + log info "Results:" 48 + $results 49 + | each {|result| 50 + log debug $"-> ($result.scene.label): (ansi blue)($result.stats.samples_per_minute)(ansi reset) samples/min" 51 + } 52 + log info $"-> Total: (ansi blue)($sum)(ansi reset) samples/min" 53 + log info $"-> Open Data: (ansi blue)($opendata_median)(ansi reset) samples/min" 54 + log info $"-> Delta: ( 55 + if $diff < 0 { 56 + (ansi red) 57 + } else if $diff == 0 { 58 + (ansi grey) + "±" 59 + } else { 60 + (ansi green) + "+" 61 + } 62 + )($diff)(ansi reset) samples/min" 63 + }
+6
nushell/ln-bin.nu
··· 1 + #!/usr/bin/nu 2 + 3 + def main [bin: path, name?: string] { 4 + let name = $name | default ($bin | path parse | get stem) 5 + ln -sf ($bin | path expand) $"($env.HOME)/.local/bin/($name)" 6 + }
+44
nushell/nebula/mod.nu
··· 1 + # SPDX-License-Identifier: AGPL-3.0-only 2 + # SPDX-FileCopyrightText: 2025 Shiloh Fen <shiloh@shilohfen.com> 3 + 4 + const path_data: path = "~/.local/share/nebula" | path expand 5 + const path_ca_cert: path = $path_data | path join "ca.crt" 6 + const path_ca_key: path = $path_data | path join "ca.key" 7 + const path_state: path = $path_data | path join "state.nuon" 8 + 9 + export def sign [ 10 + name: string 11 + groups: list<string> 12 + ]: nothing -> record<path_cert: path, path_key: path> { 13 + if not ($path_ca_key | path exists) { 14 + error make { 15 + text: "No CA key found." 16 + help: "Run submodule `ca` to generate a CA before attempting to sign a device cert." 17 + } 18 + } 19 + 20 + let tmp = mktemp -td "nebula-XXXXX" 21 + let path_device_cert = $tmp | path join $"($name).crt" 22 + let path_device_key = $tmp | path join $"($name).key" 23 + let ip_part = (open $path_state | get last_ip) + 1 24 + 25 + nebula-cert sign -name $name -ca-crt $path_ca_cert -ca-key $path_ca_key -ip $"192.168.100.($ip_part)/24" -groups ($groups | str join ",") -out-crt $path_device_cert -out-key $path_device_key 26 + 27 + {last_ip: $ip_part} | save -f $path_state 28 + 29 + { 30 + path_cert: $path_device_cert 31 + path_key: $path_device_key 32 + } 33 + } 34 + 35 + export def ca [ 36 + name: string 37 + ] { 38 + mkdir $path_data 39 + nebula-cert ca -name $name -out-crt $path_ca_cert -out-key $path_ca_key -encrypt 40 + 41 + print "Certificate will be valid for one year. Be sure to set up an alert or calendar event to rotate your CA and certificates before then to ensure continued connectivity!" 42 + 43 + {last_ip: 0} | save -f $path_state 44 + }
+42
nushell/yt-rss.nu
··· 1 + #!/usr/bin/nu 2 + 3 + use std assert 4 + 5 + def main [ 6 + channel_url: string 7 + --copy (-c) 8 + ] { 9 + validate-url $channel_url 10 + 11 + let rss_url = $"https://www.youtube.com/feeds/videos.xml?channel_id=(get-channel-id $channel_url)" 12 + 13 + if $copy { 14 + wl-copy $rss_url 15 + } else { 16 + print $rss_url 17 + } 18 + } 19 + 20 + def validate-url [channel_url: string] { 21 + assert ( 22 + ($channel_url | str starts-with "https://www.youtube.com/@") 23 + or ($channel_url | str starts-with "https://www.youtube.com/channel/") 24 + or ($channel_url | str starts-with "https://www.youtube.com/c/") 25 + ) --error-label { 26 + text: "This is not a valid YouTube channel URL.", 27 + span: (metadata $channel_url).span 28 + } 29 + } 30 + 31 + def get-channel-id [channel_url: string]: nothing -> string { 32 + let path = ($channel_url | url parse).path 33 + 34 + if ($path | str starts-with "/channel") { 35 + $path 36 + | str replace "/channel/" "" 37 + } else { 38 + http get -r $channel_url 39 + | parse -r '{"key":"browse_id","value":"(?P<channel_id>[^"]*)"}' 40 + | get channel_id.0 41 + } 42 + }