summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid T. Sadler <davidtsadler@googlemail.com>2026-07-01 14:42:07 +0100
committerDavid T. Sadler <davidtsadler@googlemail.com>2026-07-01 14:42:07 +0100
commit9dd2fa87e55075887b2036246951169e0ae6e9ea (patch)
tree40b208f865760a2acd72abaa0e76c52eed399f53
parenta81384be8899621aad68826af5c2b648dceaf3e5 (diff)
parent796e8cd52879f87220e76d71d512f2cc6a79a715 (diff)
Merge branch 'main' into howl
-rwxr-xr-xbin/.bin/bluetooth.sh140
-rw-r--r--bookmarks.txt3
-rw-r--r--nvim/.config/nvim/lua/plugins/conform.lua4
-rw-r--r--oxwm/.config/oxwm/config.lua10
4 files changed, 151 insertions, 6 deletions
diff --git a/bin/.bin/bluetooth.sh b/bin/.bin/bluetooth.sh
new file mode 100755
index 0000000..5ae5281
--- /dev/null
+++ b/bin/.bin/bluetooth.sh
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+set -uo pipefail # Keep -e off so our self-healing logic can handle error codes safely
+
+# Define the Rofi menu layout.
+declare -a order=(
+ "⚡ Power On Bluetooth"
+ "🛑 Power Off Bluetooth"
+ "🔌 Disconnect All Devices"
+ "---"
+ "Speaker"
+ "Earphones"
+ "Earphones Left"
+ "Living Room"
+)
+
+# Map profiles to hardware MAC addresses.
+declare -A devices
+devices[Speaker]="A0:E9:DB:0E:43:79"
+devices[Earphones]="98:52:3D:F2:6E:3E"
+devices["Earphones Left"]="98:52:3D:F2:36:78"
+devices["Living Room"]="42:46:9F:D0:2C:53"
+
+# Prompt User via Rofi.
+MENU_OPTIONS=$(printf "%s\n" "${order[@]}")
+SELECTION=$(echo "$MENU_OPTIONS" | rofi -dmenu -p "Bluetooth Menu:")
+
+# Exit gracefully if the user hits Escape.
+if [ -z "$SELECTION" ] || [ "$SELECTION" = "---" ]; then
+ exit 0
+fi
+
+if [ "$SELECTION" = "⚡ Power On Bluetooth" ]; then
+ notify-send "BT" "Powering adapter on..."
+ bluetoothctl power on
+ exit 0
+fi
+
+if [ "$SELECTION" = "🛑 Power Off Bluetooth" ]; then
+ notify-send "BT" "Powering adapter off..."
+ bluetoothctl power off
+ exit 0
+fi
+
+if [ "$SELECTION" = "🔌 Disconnect All Devices" ]; then
+ notify-send "BT" "Clearing all active connections..."
+ for name in "${!devices[@]}"; do
+ bluetoothctl disconnect "${devices[$name]}" >/dev/null 2>&1 || true
+ done
+ notify-send "BT" "All devices disconnected."
+ exit 0
+fi
+
+if [ -z "${devices[$SELECTION]:-}" ]; then
+ notify-send "ERROR" "Invalid choice: $SELECTION"
+ exit 1
+fi
+
+TARGET_MAC="${devices[$SELECTION]}"
+
+# Ensure controller is actually powered up before trying to connect.
+if ! bluetoothctl show | grep -q "Powered: yes"; then
+ notify-send "BT" "Waking up Bluetooth adapter..."
+ bluetoothctl power on
+ sleep 2
+fi
+
+# Force controller runtime options to accept incoming passthroughs.
+bluetoothctl pairable on >/dev/null 2>&1 || true
+bluetoothctl discoverable on >/dev/null 2>&1 || true
+
+# Disconnect existing targets to free up the system audio pipelines.
+for name in "${!devices[@]}"; do
+ bluetoothctl disconnect "${devices[$name]}" >/dev/null 2>&1 || true
+done
+
+# Query the machine's local hardware database cache.
+DEVICE_CHECK=$(bluetoothctl info "$TARGET_MAC" 2>&1 || true)
+
+if echo "$DEVICE_CHECK" | grep -q "not available"; then
+ notify-send "BT: Provisioning" "Device missing from system cache. Probing airwaves..."
+
+ # Run a targeted background scan pass to register device metadata.
+ bluetoothctl --timeout 5 scan on >/dev/null 2>&1 &
+ SCAN_PID=$!
+ sleep 4
+ kill "$SCAN_PID" 2>/dev/null || true
+ wait "$SCAN_PID" 2>/dev/null || true
+ sleep 1
+
+ notify-send "BT: Provisioning" "Exchanging encryption keys..."
+ bluetoothctl pair "$TARGET_MAC"
+ bluetoothctl trust "$TARGET_MAC"
+fi
+
+# Attempt targeted connection sequence.
+notify-send "BT Switch" "Routing audio to $SELECTION..."
+CONNECT_OUT=$(bluetoothctl connect "$TARGET_MAC" 2>&1 || true)
+echo "$CONNECT_OUT"
+
+if echo "$CONNECT_OUT" | grep -q "Connection successful"; then
+ bluetoothctl trust "$TARGET_MAC" >/dev/null 2>&1 || true
+
+ # WirePlumber Sinks Syncing Engine.
+ CLEAN_MAC="${TARGET_MAC//:/_}"
+ SINK_NAME=$(wpctl status | grep -o "bluez_output\.[^\ ]*${CLEAN_MAC}[^\ ]*" | head -n 1 || true)
+
+ if [ ! -z "$SINK_NAME" ]; then
+ wpctl set-default "$SINK_NAME"
+ # Set a safe volumne just in case we connect to earphones.
+ wpctl set-volume "$SINK_NAME" 0.10
+ fi
+
+ notify-send "BT Switch" "$SELECTION connected successfully!"
+
+# Handle key synchronization issues seamlessly....
+elif echo "$CONNECT_OUT" | grep -q "br-connection-key-missing"; then
+ notify-send "BT Error" "Key mismatch! Purging and re-pairing..."
+
+ bluetoothctl remove "$TARGET_MAC" >/dev/null 2>&1 || true
+ sleep 1
+
+ bluetoothctl --timeout 5 scan on >/dev/null 2>&1 &
+ SCAN_PID=$!
+ sleep 4
+ kill "$SCAN_PID" 2>/dev/null || true
+ wait "$SCAN_PID" 2>/dev/null || true
+ sleep 1
+
+ notify-send "BT Recovery" "Put device in pairing mode!"
+ bluetoothctl pair "$TARGET_MAC"
+ bluetoothctl trust "$TARGET_MAC"
+
+ if bluetoothctl connect "$TARGET_MAC"; then
+ notify-send "BT Switch" "$SELECTION repaired and connected!"
+ else
+ notify-send "BT ERROR" "Repair fallback routing failed."
+ fi
+else
+ notify-send "BT ERROR" "Failed to link with $SELECTION. Check pairing state or other devices."
+fi
diff --git a/bookmarks.txt b/bookmarks.txt
index d6954be..4b45d46 100644
--- a/bookmarks.txt
+++ b/bookmarks.txt
@@ -1,2 +1,3 @@
-Gemini|https://gemini.google.com/app
+gemini|https://gemini.google.com/app
davidtsadler.com|https://davidtsadler.com/
+jellyfin|http://192.168.1.11:8096/web
diff --git a/nvim/.config/nvim/lua/plugins/conform.lua b/nvim/.config/nvim/lua/plugins/conform.lua
index 365fb2d..94bdb06 100644
--- a/nvim/.config/nvim/lua/plugins/conform.lua
+++ b/nvim/.config/nvim/lua/plugins/conform.lua
@@ -22,5 +22,9 @@ require("conform").setup({
command = "biome",
args = { "format", "--stdin-file-path", "$FILENAME" },
},
+ -- Force shfmt to always use the bash parser variant.
+ shfmt = {
+ prepend_args = { "-ln", "bash" },
+ },
},
})
diff --git a/oxwm/.config/oxwm/config.lua b/oxwm/.config/oxwm/config.lua
index 68a5b28..3b37a8c 100644
--- a/oxwm/.config/oxwm/config.lua
+++ b/oxwm/.config/oxwm/config.lua
@@ -261,11 +261,6 @@ oxwm.key.bind({ modkey, "Control", "Shift" }, "9", oxwm.tag.toggletag(8))
-- Format: {{modifiers}, key1}, {{modifiers}, key2}, ...
-- Example: Press Mod4+Space, then release and press T to spawn a terminal without auto starting anything.
oxwm.key.chord({
- { { modkey }, "Space" },
- { {}, "B" }
-}, oxwm.spawn({ "firefox" }))
-
-oxwm.key.chord({
{ { modkey }, "b" },
{ {}, "a" }
}, oxwm.spawn({ "add-bookmark.sh" }))
@@ -280,6 +275,11 @@ oxwm.key.chord({
{ {}, "p" }
}, oxwm.spawn({ "power.sh" }))
+oxwm.key.chord({
+ { { modkey }, "Space" },
+ { {}, "b" }
+}, oxwm.spawn({ "bluetooth.sh" }))
+
-------------------------------------------------------------------------------
-- Autostart
-------------------------------------------------------------------------------