From 73dd504acf7c0d4a32b360d84712842f57020da0 Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:49:26 +0100 Subject: [PATCH 1/8] feat: define SUB/WAVE station model --- BarWidget.qml | 6 +++ LICENSE | 21 +++++++++ StationModel.js | 102 +++++++++++++++++++++++++++++++++++++++++++ StationPicker.qml | 8 ++++ manifest.json | 25 +++++++++++ tests/model.test.mjs | 50 +++++++++++++++++++++ tests/run | 12 +++++ 7 files changed, 224 insertions(+) create mode 100644 BarWidget.qml create mode 100644 LICENSE create mode 100644 StationModel.js create mode 100644 StationPicker.qml create mode 100644 manifest.json create mode 100644 tests/model.test.mjs create mode 100755 tests/run diff --git a/BarWidget.qml b/BarWidget.qml new file mode 100644 index 0000000..b233978 --- /dev/null +++ b/BarWidget.qml @@ -0,0 +1,6 @@ +import QtQuick +import qs.Commons + +BarWidget { + moduleName: "getsubwave.radio" +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fa079b3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 SUB/WAVE contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/StationModel.js b/StationModel.js new file mode 100644 index 0000000..1ba66aa --- /dev/null +++ b/StationModel.js @@ -0,0 +1,102 @@ +var MAX_STATIONS = 200 +var MAX_FIELD = 512 + +function singleLine(value, limit) { + var cap = Math.max(0, Math.min(MAX_FIELD, Number(limit) || MAX_FIELD)) + return String(value || "").replace(/[\r\n\t\u0000-\u001f\u007f]+/g, " ").trim().slice(0, cap) +} + +function normalizeOrigin(value) { + var raw = String(value || "").trim() + if (!raw || /[\u0000-\u001f\u007f]/.test(raw)) return "" + try { + var parsed = new URL(raw) + if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "" + if (parsed.username || parsed.password || parsed.hash) return "" + return parsed.origin + } catch (error) { + return "" + } +} + +function fallbackSlug(name) { + return singleLine(name, 80).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 49) +} + +function normalizeStation(value) { + if (!value || typeof value !== "object") return null + var name = singleLine(value.name, 160) + var url = normalizeOrigin(value.url) + if (!name || !url) return null + return { + slug: singleLine(value.slug, 49) || fallbackSlug(name), + name: name, + url: url, + location: singleLine(value.location, 160), + country: singleLine(value.country, 100), + operator: singleLine(value.operator, 100), + genre: singleLine(value.genre, 160), + description: singleLine(value.description, MAX_FIELD), + featured: value.featured === true, + submitted: singleLine(value.submitted, 32), + isConfigured: value.isConfigured === true + } +} + +function compareStations(a, b) { + if (a.featured !== b.featured) return a.featured ? -1 : 1 + var left = a.name.toLowerCase() + var right = b.name.toLowerCase() + return left < right ? -1 : (left > right ? 1 : 0) +} + +function normalizeCatalog(value) { + var source = Array.isArray(value) ? value : [] + var seen = ({}) + var rows = [] + for (var i = 0; i < source.length; i++) { + var station = normalizeStation(source[i]) + if (!station || seen[station.url]) continue + seen[station.url] = true + rows.push(station) + } + rows.sort(compareStations) + return rows.slice(0, MAX_STATIONS) +} + +function mergeConfigured(stations, stationUrl) { + var rows = normalizeCatalog(stations) + var origin = normalizeOrigin(stationUrl) + if (!origin) return rows + for (var i = 0; i < rows.length; i++) { + if (rows[i].url !== origin) continue + var matched = Object.assign({}, rows[i], { isConfigured: true }) + rows.splice(i, 1) + rows.unshift(matched) + return rows + } + rows.unshift({ + slug: "__configured", + name: "My station", + url: origin, + location: "", + country: "", + operator: "", + genre: "", + description: "Your configured SUB/WAVE station", + featured: false, + submitted: "", + isConfigured: true + }) + return rows.slice(0, MAX_STATIONS) +} + +function searchStations(stations, query) { + var rows = Array.isArray(stations) ? stations : [] + var needle = singleLine(query, 160).toLowerCase() + if (!needle) return rows.slice() + return rows.filter(function(station) { + return [station.name, station.genre, station.location, station.country, + station.operator, station.description].join(" ").toLowerCase().indexOf(needle) !== -1 + }) +} diff --git a/StationPicker.qml b/StationPicker.qml new file mode 100644 index 0000000..c23f196 --- /dev/null +++ b/StationPicker.qml @@ -0,0 +1,8 @@ +import QtQuick + +Item { + property var shell: null + property var manifest: null + function open(payloadJson) {} + function close() {} +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..b4eb562 --- /dev/null +++ b/manifest.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "getsubwave.radio", + "name": "SUB/WAVE Radio", + "version": "0.1.0", + "author": "SUB/WAVE", + "license": "MIT", + "description": "Listen to your SUB/WAVE station and discover community stations from the Omarchy bar.", + "homepage": "https://github.com/getsubwave/omarchy-subwave", + "repository": "https://github.com/getsubwave/omarchy-subwave", + "keywords": ["radio", "subwave", "music", "mpris"], + "kinds": ["overlay", "bar-widget"], + "keepLoaded": true, + "entryPoints": { + "overlay": "StationPicker.qml", + "barWidget": "BarWidget.qml" + }, + "barWidget": { + "displayName": "SUB/WAVE Radio", + "description": "SUB/WAVE community radio player", + "category": "Media", + "allowMultiple": false, + "defaultSection": "left" + } +} diff --git a/tests/model.test.mjs b/tests/model.test.mjs new file mode 100644 index 0000000..c00a7b6 --- /dev/null +++ b/tests/model.test.mjs @@ -0,0 +1,50 @@ +import assert from "node:assert/strict" +import fs from "node:fs" +import path from "node:path" +import vm from "node:vm" +import { fileURLToPath } from "node:url" + +const testDir = path.dirname(fileURLToPath(import.meta.url)) +const source = fs.readFileSync(path.join(testDir, "..", "StationModel.js"), "utf8") +const model = { Array, Boolean, JSON, Math, Number, Object, RegExp, String, URL } +vm.createContext(model) +vm.runInContext(source, model) + +assert.equal(model.normalizeOrigin(" https://radio.example.com/path/ "), "https://radio.example.com") +assert.equal(model.normalizeOrigin("http://radio.example.com:7700"), "http://radio.example.com:7700") +assert.equal(model.normalizeOrigin("https://user:pass@radio.example.com"), "") +assert.equal(model.normalizeOrigin("file:///tmp/stream"), "") +assert.equal(model.normalizeOrigin("https://radio.example.com/#secret"), "") +assert.equal(model.normalizeOrigin("https://radio.example.com/\nnext"), "") + +const rows = model.normalizeCatalog([ + { slug: "zeta", name: "Zeta", url: "https://zeta.example", genre: "Jazz" }, + { slug: "featured", name: "Featured", url: "https://featured.example", featured: true }, + { slug: "bad", name: "", url: "https://bad.example" }, + { slug: "creds", name: "Creds", url: "https://u:p@bad.example" } +]) +assert.deepEqual(Array.from(rows, row => row.slug), ["featured", "zeta"]) + +const merged = model.mergeConfigured(rows, "https://zeta.example/listen") +assert.equal(merged.length, 2) +assert.equal(merged[0].slug, "zeta") +assert.equal(merged[0].isConfigured, true) + +const synthetic = model.mergeConfigured(rows, "https://mine.example") +assert.equal(synthetic[0].slug, "__configured") +assert.equal(synthetic[0].name, "My station") +assert.equal(synthetic[0].url, "https://mine.example") + +assert.deepEqual( + Array.from(model.searchStations(synthetic, "jazz"), row => row.slug), + ["zeta"] +) +assert.equal(model.searchStations(synthetic, "").length, 3) +assert.equal(model.normalizeCatalog(Array.from({ length: 250 }, (_, i) => ({ + slug: `s-${i}`, name: `Station ${i}`, url: `https://s-${i}.example` +}))).length, 200) + +assert.equal(model.singleLine(" a\n\tb ", 20), "a b") +assert.equal(model.singleLine("abcdef", 3), "abc") + +console.log("StationModel tests passed") diff --git a/tests/run b/tests/run new file mode 100755 index 0000000..adc127e --- /dev/null +++ b/tests/run @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +node "$root/tests/model.test.mjs" + +if command -v omarchy >/dev/null 2>&1; then + omarchy plugin validate "$root" +fi +if command -v qmllint >/dev/null 2>&1; then + qmllint -I /usr/share/omarchy/shell "$root/BarWidget.qml" "$root/StationPicker.qml" +fi From 82a5f2d32ce5c9bf0e8f8a21e4cd21d775601101 Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:51:34 +0100 Subject: [PATCH 2/8] feat: fetch SUB/WAVE station data safely --- subwave-fetch | 149 ++++++++++++++++++++++++++++++++++++++++++++ tests/fetch.test.sh | 61 ++++++++++++++++++ tests/run | 1 + 3 files changed, 211 insertions(+) create mode 100755 subwave-fetch create mode 100755 tests/fetch.test.sh diff --git a/subwave-fetch b/subwave-fetch new file mode 100755 index 0000000..3d561fb --- /dev/null +++ b/subwave-fetch @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail +umask 077 + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +data_root=${XDG_DATA_HOME:-$HOME/.local/share} +data_dir="$data_root/omarchy-subwave" +cache_file="$data_dir/catalog.json" +catalog_url=${SUBWAVE_CATALOG_URL:-https://www.getsubwave.com/stations.json} +max_catalog_bytes=1048576 +max_now_bytes=262144 +install -d -m 700 "$data_dir" +version=$(jq -r '.version // "0.0.0"' "$script_dir/manifest.json" 2>/dev/null || printf '0.0.0') +user_agent="Omarchy SUB/WAVE/$version" + +normalize_origin() { + local raw=${1:-} + [[ -n $raw && ! $raw =~ [[:cntrl:]] ]] || return 1 + if [[ $raw =~ ^(https?)://([^/@?#[:space:]]+)(/[^?#]*)?/?$ ]]; then + printf '%s://%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + return 0 + fi + return 1 +} + +valid_cache() { + [[ -s $cache_file ]] \ + && (( $(stat -c '%s' -- "$cache_file") <= max_catalog_bytes )) \ + && jq -e 'type == "array" and length <= 200' "$cache_file" >/dev/null 2>&1 +} + +emit_cache() { + if valid_cache; then cat "$cache_file"; else printf '[]\n'; fi +} + +normalize_catalog() { + jq -c ' + def line($n): tostring | gsub("[\u0000-\u001f\u007f]"; " ") | gsub("[ \t]+"; " ") | ltrimstr(" ") | rtrimstr(" ") | .[0:$n]; + def origin: + select(type == "string") + | try capture("^(?https?)://(?[^/@?#[:space:]]+)(?:/[^?#]*)?/?$") catch null + | select(. != null) + | "\(.scheme)://\(.host)"; + if type != "array" then error("catalog is not an array") else . end + | map( + . as $row + | (($row.name // "") | line(160)) as $name + | (($row.url // "") | origin) as $url + | select($name != "" and $url != "") + | { + slug: (($row.slug // ($name | ascii_downcase | gsub("[^a-z0-9]+"; "-") | ltrimstr("-") | rtrimstr("-"))) | line(49)), + name: $name, + url: $url, + location: (($row.location // "") | line(160)), + country: (($row.country // "") | line(100)), + operator: (($row.operator // "") | line(100)), + genre: (($row.genre // "") | line(160)), + description: (($row.description // "") | line(512)), + featured: ($row.featured == true), + submitted: (($row.submitted // "") | line(32)), + isConfigured: false + } + ) + | sort_by([if .featured then 0 else 1 end, (.name | ascii_downcase)]) + | reduce .[] as $row ([]; if any(.[]; .url == $row.url) then . else . + [$row] end) + | .[:200] + ' +} + +write_cache() { + local source=$1 temporary + temporary=$(mktemp "$data_dir/.catalog.XXXXXX") + install -m 600 "$source" "$temporary" + mv -f "$temporary" "$cache_file" +} + +fetch_catalog() { + local download normalized + download=$(mktemp "$data_dir/.download.XXXXXX") + normalized=$(mktemp "$data_dir/.normalized.XXXXXX") + trap 'rm -f "$download" "$normalized"' RETURN + if ! curl --fail --silent --show-error --location \ + --proto '=https' --proto-redir '=https' \ + --connect-timeout 4 --max-time 10 --max-filesize "$max_catalog_bytes" \ + --user-agent "$user_agent" --output "$download" "$catalog_url"; then + emit_cache + valid_cache + return + fi + if (( $(stat -c '%s' -- "$download") > max_catalog_bytes )) \ + || ! normalize_catalog <"$download" >"$normalized"; then + emit_cache + valid_cache + return + fi + write_cache "$normalized" + cat "$cache_file" +} + +offline_json() { + jq -cn '{online:false,station:"",dj:"",show:"",title:"",artist:"",album:"",coverUrl:"",listeners:null,error:"Station unavailable"}' +} + +fetch_now_playing() { + local origin scheme response + if ! origin=$(normalize_origin "${1:-}"); then + offline_json + return 2 + fi + scheme=${origin%%:*} + response=$(mktemp "$data_dir/.now.XXXXXX") + trap 'rm -f "$response"' RETURN + if ! curl --fail --silent --show-error --location \ + --proto "=$scheme" --proto-redir "=$scheme" \ + --connect-timeout 3 --max-time 6 --max-filesize "$max_now_bytes" \ + --user-agent "$user_agent" --output "$response" "$origin/api/now-playing" \ + || (( $(stat -c '%s' -- "$response") > max_now_bytes )); then + offline_json + return 3 + fi + if ! jq -ce --arg origin "$origin" ' + def line($n): tostring | gsub("[\u0000-\u001f\u007f]"; " ") | gsub("[ \t]+"; " ") | ltrimstr(" ") | rtrimstr(" ") | .[0:$n]; + if type != "object" then error("invalid now-playing") else . end + | (.nowPlaying // {}) as $np + | ($np.subsonic_id // "") as $id + | { + online: (.streamOnline != false), + station: ((.dj.station // "") | line(160)), + dj: ((.dj.name // "") | line(100)), + show: ((.activeShow.name // "") | line(160)), + title: (($np.title // "") | line(512)), + artist: (($np.artist // "") | line(512)), + album: (($np.album // "") | line(512)), + coverUrl: (if ($id | type == "string" and test("^[A-Za-z0-9_-]{1,64}$")) then ($origin + "/api/cover/" + $id) else "" end), + listeners: ((if (.listeners | type) == "number" then .listeners elif (.listeners.current | type) == "number" then .listeners.current else null end) as $n | if $n != null and $n >= 0 then ($n | floor) else null end), + error: "" + } + ' "$response"; then + offline_json + return 4 + fi +} + +case ${1:-} in + cache) emit_cache ;; + catalog) fetch_catalog ;; + now-playing) fetch_now_playing "${2:-}" ;; + *) echo "Usage: subwave-fetch cache|catalog|now-playing " >&2; exit 2 ;; +esac diff --git a/tests/fetch.test.sh b/tests/fetch.test.sh new file mode 100755 index 0000000..0dabaa0 --- /dev/null +++ b/tests/fetch.test.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +mkdir -p "$tmp/bin" "$tmp/data" "$tmp/runtime" +export XDG_DATA_HOME="$tmp/data" +export XDG_RUNTIME_DIR="$tmp/runtime" +export PATH="$tmp/bin:$PATH" + +cat >"$tmp/bin/curl" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +output= +printf '%s\n' "$@" >"${FAKE_CURL_ARGS:?}" +while (($#)); do + if [[ $1 == --output ]]; then output=$2; shift 2; else shift; fi +done +if [[ ${FAKE_CURL_EXIT:-0} != 0 ]]; then exit "$FAKE_CURL_EXIT"; fi +cp "${FAKE_CURL_BODY:?}" "$output" +SH +chmod +x "$tmp/bin/curl" +export FAKE_CURL_ARGS="$tmp/curl.args" + +cat >"$tmp/catalog.json" <<'JSON' +[ + {"slug":"plain","name":"Plain","url":"https://radio.example/path","genre":"Jazz"}, + {"slug":"featured","name":"Featured","url":"https://featured.example","featured":true}, + {"slug":"bad","name":"","url":"https://bad.example"} +] +JSON +FAKE_CURL_BODY="$tmp/catalog.json" "$root/subwave-fetch" catalog >"$tmp/out.json" +jq -e 'length == 2 and .[0].slug == "featured" and .[1].url == "https://radio.example"' "$tmp/out.json" >/dev/null +test "$(stat -c %a "$XDG_DATA_HOME/omarchy-subwave/catalog.json")" = 600 +grep -Fx 'Omarchy SUB/WAVE/0.1.0' "$tmp/curl.args" >/dev/null + +FAKE_CURL_EXIT=22 "$root/subwave-fetch" catalog >"$tmp/cached.json" +cmp "$tmp/out.json" "$tmp/cached.json" +"$root/subwave-fetch" cache >"$tmp/cache-command.json" +cmp "$tmp/out.json" "$tmp/cache-command.json" + +cat >"$tmp/now.json" <<'JSON' +{"nowPlaying":{"title":"Track","artist":"Artist","album":"Album","subsonic_id":"abc"},"dj":{"station":"Example","name":"Frequency"},"activeShow":{"name":"Night Drive"},"listeners":{"current":4},"streamOnline":true} +JSON +FAKE_CURL_BODY="$tmp/now.json" "$root/subwave-fetch" now-playing https://radio.example >"$tmp/now-out.json" +jq -e '.online == true and .title == "Track" and .artist == "Artist" and .listeners == 4 and .coverUrl == "https://radio.example/api/cover/abc"' "$tmp/now-out.json" >/dev/null + +if "$root/subwave-fetch" now-playing 'https://u:p@radio.example' >/dev/null 2>&1; then + echo "credentialed URL was accepted" >&2 + exit 1 +fi + +dd if=/dev/zero of="$tmp/large.json" bs=1048577 count=1 status=none +before=$(sha256sum "$XDG_DATA_HOME/omarchy-subwave/catalog.json") +FAKE_CURL_BODY="$tmp/large.json" "$root/subwave-fetch" catalog >"$tmp/large-out.json" +after=$(sha256sum "$XDG_DATA_HOME/omarchy-subwave/catalog.json") +test "$before" = "$after" +cmp "$tmp/out.json" "$tmp/large-out.json" + +echo "subwave-fetch tests passed" diff --git a/tests/run b/tests/run index adc127e..d27b004 100755 --- a/tests/run +++ b/tests/run @@ -3,6 +3,7 @@ set -euo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) node "$root/tests/model.test.mjs" +bash "$root/tests/fetch.test.sh" if command -v omarchy >/dev/null 2>&1; then omarchy plugin validate "$root" From 7f4d580d6a48f8a0bbd1b352a724654af909efcd Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:53:27 +0100 Subject: [PATCH 3/8] feat: add guarded SUB/WAVE playback --- subwave-player | 236 +++++++++++++++++++++++++++++++++++++++++++ tests/player.test.sh | 96 ++++++++++++++++++ tests/run | 1 + 3 files changed, 333 insertions(+) create mode 100755 subwave-player create mode 100755 tests/player.test.sh diff --git a/subwave-player b/subwave-player new file mode 100755 index 0000000..eb63ecb --- /dev/null +++ b/subwave-player @@ -0,0 +1,236 @@ +#!/usr/bin/env bash +set -euo pipefail +umask 077 + +: "${XDG_RUNTIME_DIR:?SUB/WAVE requires XDG_RUNTIME_DIR}" +runtime_dir="$XDG_RUNTIME_DIR/omarchy-subwave" +data_root=${XDG_DATA_HOME:-$HOME/.local/share} +data_dir="$data_root/omarchy-subwave" +state_file="$data_dir/state.json" +socket="$runtime_dir/mpv.sock" +pid_file="$runtime_dir/player.pid" +station_file="$runtime_dir/station.json" +status_file="$runtime_dir/status.json" +log_file="$runtime_dir/mpv.log" +install -d -m 700 "$runtime_dir" "$data_dir" +exec 8>"$runtime_dir/player.lock" + +normalize_origin() { + local raw=${1:-} + [[ -n $raw && ! $raw =~ [[:cntrl:]] ]] || return 1 + if [[ $raw =~ ^(https?)://([^/@?#[:space:]]+)(/[^?#]*)?/?$ ]]; then + printf '%s://%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + return 0 + fi + return 1 +} + +process_start_time() { + local pid=$1 + [[ -r /proc/$pid/stat ]] || return 1 + awk '$3 != "Z" { print $22 }' "/proc/$pid/stat" 2>/dev/null +} + +player_alive() { + local pid expected actual + [[ -s $pid_file ]] || return 1 + read -r pid expected <"$pid_file" || return 1 + [[ $pid =~ ^[0-9]+$ && $expected =~ ^[0-9]+$ ]] || return 1 + kill -0 "$pid" 2>/dev/null || return 1 + actual=$(process_start_time "$pid") || return 1 + [[ $actual == "$expected" ]] +} + +valid_state() { + [[ -s $state_file ]] && (( $(stat -c '%s' -- "$state_file") <= 65536 )) \ + && jq -e 'type == "object" and ((.volume // 70) | type == "number")' "$state_file" >/dev/null 2>&1 +} + +read_state() { + if valid_state; then + jq -c '{volume: ((.volume // 70) | floor | if . < 0 then 0 elif . > 100 then 100 else . end), lastStation: (.lastStation // {url:"",name:""})}' "$state_file" + else + jq -cn '{volume:70,lastStation:{url:"",name:""}}' + fi +} + +write_state() { + local json=$1 temporary + temporary=$(mktemp "$data_dir/.state.XXXXXX") + printf '%s\n' "$json" >"$temporary" + chmod 600 "$temporary" + mv -f "$temporary" "$state_file" +} + +configured_volume() { + read_state | jq -r '.volume' +} + +current_station() { + if [[ -s $station_file ]] && (( $(stat -c '%s' -- "$station_file") <= 65536 )) \ + && jq -e 'type == "object" and (.url | type == "string")' "$station_file" >/dev/null 2>&1; then + cat "$station_file" + else + jq -cn '{name:"",url:""}' + fi +} + +write_station() { + local origin=$1 name=$2 temporary state + temporary=$(mktemp "$runtime_dir/.station.XXXXXX") + jq -cn --arg url "$origin" --arg name "$name" '{name:($name | gsub("[\\r\\n\\t]";" ") | .[:160]),url:$url}' >"$temporary" + mv -f "$temporary" "$station_file" + state=$(read_state | jq -c --argjson station "$(cat "$station_file")" '.lastStation = $station') + write_state "$state" +} + +cleanup_stale() { + player_alive && return 0 + rm -f "$pid_file" "$socket" "$station_file" + return 1 +} + +send_command() { + local payload=$1 response request_id=7101 + [[ -S $socket ]] || return 1 + payload=$(jq -c --argjson id "$request_id" '. + {request_id:$id}' <<<"$payload") + response=$(printf '%s\n' "$payload" | socat -T 1 - "UNIX-CONNECT:$socket" 2>/dev/null | head -c 65537) || return 1 + (( ${#response} <= 65536 )) || return 1 + jq -e --argjson id "$request_id" 'select(.request_id == $id and .error == "success")' <<<"$response" >/dev/null || return 1 + printf '%s\n' "$response" +} + +property() { + local name=$1 payload + payload=$(jq -cn --arg name "$name" '{command:["get_property",$name]}') + send_command "$payload" | jq -c '.data' +} + +write_status() { + local json=$1 temporary + temporary=$(mktemp "$runtime_dir/.status.XXXXXX") + printf '%s\n' "$json" >"$temporary" + mv -f "$temporary" "$status_file" + printf '%s\n' "$json" +} + +status() { + local volume station paused=false + volume=$(configured_volume) + if ! player_alive || [[ ! -S $socket ]]; then + cleanup_stale || true + write_status "$(jq -cn --argjson volume "$volume" '{running:false,paused:false,volume:$volume,station:{name:"",url:""},error:""}')" + return + fi + paused=$(property pause 2>/dev/null || printf false) + volume=$(property volume 2>/dev/null || printf '%s' "$volume") + station=$(current_station) + write_status "$(jq -cn --argjson paused "$paused" --argjson volume "$volume" --argjson station "$station" '{running:true,paused:($paused == true),volume:($volume|floor),station:$station,error:""}')" +} + +start_player() { + local origin=$1 name=$2 volume pid start + volume=$(configured_volume) + rm -f "$socket" + setsid mpv \ + --no-video \ + --force-window=no \ + --audio-display=no \ + --idle=yes \ + --cache-secs=20 \ + --demuxer-max-bytes=8MiB \ + --demuxer-max-back-bytes=2MiB \ + --network-timeout=30 \ + --volume="$volume" \ + --volume-max=100 \ + --input-ipc-server="$socket" \ + --no-terminal \ + --really-quiet \ + "$origin/stream.mp3" >"$log_file" 2>&1 8>&- & + pid=$! + start=$(process_start_time "$pid") || { kill "$pid" 2>/dev/null || true; return 1; } + printf '%s %s\n' "$pid" "$start" >"$pid_file" + for _ in $(seq 1 150); do + [[ -S $socket ]] && break + sleep 0.02 + done + if [[ ! -S $socket ]]; then + kill -- "-$pid" 2>/dev/null || kill "$pid" 2>/dev/null || true + rm -f "$pid_file" "$socket" + return 1 + fi + write_station "$origin" "$name" +} + +play() { + local origin name payload + origin=$(normalize_origin "${1:-}") || { echo "Station URL must be an HTTP(S) origin" >&2; exit 2; } + name=${2:-SUB/WAVE} + if player_alive && [[ -S $socket ]]; then + payload=$(jq -cn --arg url "$origin/stream.mp3" '{command:["loadfile",$url,"replace"]}') + send_command "$payload" >/dev/null || { echo "Player could not load station" >&2; exit 4; } + write_station "$origin" "$name" + else + cleanup_stale || true + start_player "$origin" "$name" || { echo "Player could not start" >&2; exit 4; } + fi + status +} + +set_volume() { + local volume=${1:-} payload state + [[ $volume =~ ^[0-9]+$ ]] && (( volume >= 0 && volume <= 100 )) \ + || { echo "Volume must be an integer from 0 to 100" >&2; exit 2; } + if player_alive && [[ -S $socket ]]; then + payload=$(jq -cn --argjson volume "$volume" '{command:["set_property","volume",$volume]}') + send_command "$payload" >/dev/null || { echo "Player volume could not be changed" >&2; exit 4; } + fi + state=$(read_state | jq -c --argjson volume "$volume" '.volume = $volume') + write_state "$state" + status +} + +transport() { + local payload=$1 + player_alive && [[ -S $socket ]] || { echo "Player is unavailable" >&2; exit 4; } + send_command "$payload" >/dev/null || { echo "Player command failed" >&2; exit 4; } + status +} + +stop_player() { + local pid + if ! player_alive; then + cleanup_stale || true + status + return + fi + read -r pid _ <"$pid_file" + send_command '{"command":["quit"]}' >/dev/null 2>&1 || true + for _ in $(seq 1 100); do + player_alive || break + sleep 0.02 + done + if player_alive; then + kill -- "-$pid" 2>/dev/null || kill "$pid" 2>/dev/null || true + fi + for _ in $(seq 1 50); do + player_alive || break + sleep 0.02 + done + if player_alive; then + kill -KILL -- "-$pid" 2>/dev/null || kill -KILL "$pid" 2>/dev/null || true + fi + rm -f "$pid_file" "$socket" "$station_file" + status +} + +flock -x 8 +case ${1:-status} in + play) play "${2:-}" "${3:-SUB/WAVE}" ;; + toggle) transport '{"command":["cycle","pause"]}' ;; + pause) transport '{"command":["set_property","pause",true]}' ;; + stop) stop_player ;; + volume) set_volume "${2:-}" ;; + status) status ;; + *) echo "Usage: subwave-player play|toggle|pause|stop|volume|status" >&2; exit 2 ;; +esac diff --git a/tests/player.test.sh b/tests/player.test.sh new file mode 100755 index 0000000..9e8b41c --- /dev/null +++ b/tests/player.test.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +tmp=$(mktemp -d) +cleanup() { + XDG_RUNTIME_DIR="$tmp/runtime" XDG_DATA_HOME="$tmp/data" "$root/subwave-player" stop >/dev/null 2>&1 || true + rm -rf "$tmp" +} +trap cleanup EXIT +mkdir -p "$tmp/bin" "$tmp/data" "$tmp/runtime" +export XDG_DATA_HOME="$tmp/data" +export XDG_RUNTIME_DIR="$tmp/runtime" +export PATH="$tmp/bin:$PATH" +export FAKE_MPV_ARGS="$tmp/mpv.args" +export FAKE_MPV_VOLUME="$tmp/volume" + +cat >"$tmp/bin/mpv-ipc" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +IFS= read -r request +id=$(jq -r '.request_id' <<<"$request") +action=$(jq -r '.command[0]' <<<"$request") +property=$(jq -r '.command[1] // ""' <<<"$request") +if [[ $action == get_property && $property == pause ]]; then data=false +elif [[ $action == get_property && $property == volume ]]; then data=$(cat "$FAKE_MPV_VOLUME" 2>/dev/null || printf 70) +elif [[ $action == set_property && $property == volume ]]; then + jq -r '.command[2]' <<<"$request" >"$FAKE_MPV_VOLUME" + data=null +else data=null +fi +jq -cn --argjson id "$id" --argjson data "$data" '{request_id:$id,error:"success",data:$data}' +SH +chmod +x "$tmp/bin/mpv-ipc" + +cat >"$tmp/bin/mpv" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +printf '%s\n' "$@" >"$FAKE_MPV_ARGS" +socket= +for arg in "$@"; do + [[ $arg == --input-ipc-server=* ]] && socket=${arg#*=} +done +[[ -n $socket ]] +exec socat "UNIX-LISTEN:$socket,fork" "SYSTEM:$PWD/tests/fake-unused" 2>/dev/null +SH +chmod +x "$tmp/bin/mpv" + +# Override socat for the fake MPV listener and for client calls. +real_socat=$(command -v socat) +export REAL_SOCAT="$real_socat" +cat >"$tmp/bin/socat" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +if [[ ${1:-} == UNIX-LISTEN:* ]]; then + exec "$REAL_SOCAT" "$1" "SYSTEM:$PATH" >/dev/null +fi +exec "$REAL_SOCAT" "$@" +SH +chmod +x "$tmp/bin/socat" + +# Replace the listener fake with a direct real-socat command after PATH setup. +cat >"$tmp/bin/mpv" <"\$FAKE_MPV_ARGS" +socket= +for arg in "\$@"; do [[ \$arg == --input-ipc-server=* ]] && socket=\${arg#*=}; done +exec "$real_socat" "UNIX-LISTEN:\$socket,fork" "SYSTEM:$tmp/bin/mpv-ipc" +SH +chmod +x "$tmp/bin/mpv" + +"$root/subwave-player" status | jq -e '.running == false and .volume == 70' >/dev/null +if "$root/subwave-player" play 'file:///tmp/audio' 'Bad' >/dev/null 2>&1; then + echo "unsafe player URL was accepted" >&2 + exit 1 +fi +"$root/subwave-player" play 'https://radio.example/path' 'Example Radio' | jq -e '.running == true' >/dev/null +grep -Fx -- '--no-video' "$FAKE_MPV_ARGS" >/dev/null +grep -E '^--input-ipc-server=' "$FAKE_MPV_ARGS" >/dev/null +grep -Fx -- 'https://radio.example/stream.mp3' "$FAKE_MPV_ARGS" >/dev/null +"$root/subwave-player" volume 95 | jq -e '.volume == 95' >/dev/null +if "$root/subwave-player" volume 101 >/dev/null 2>&1; then + echo "out-of-range volume was accepted" >&2 + exit 1 +fi +"$root/subwave-player" toggle | jq -e '.running == true' >/dev/null +"$root/subwave-player" stop | jq -e '.running == false' >/dev/null + +mkdir -p "$XDG_RUNTIME_DIR/omarchy-subwave" +start=$(awk '{print $22}' "/proc/$$/stat") +printf '%s %s\n' "$$" "$((start + 1))" >"$XDG_RUNTIME_DIR/omarchy-subwave/player.pid" +"$root/subwave-player" stop | jq -e '.running == false' >/dev/null +kill -0 "$$" + +echo "subwave-player tests passed" diff --git a/tests/run b/tests/run index d27b004..3e6880b 100755 --- a/tests/run +++ b/tests/run @@ -4,6 +4,7 @@ set -euo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) node "$root/tests/model.test.mjs" bash "$root/tests/fetch.test.sh" +bash "$root/tests/player.test.sh" if command -v omarchy >/dev/null 2>&1; then omarchy plugin validate "$root" From a0e0f3abb7192bf8007950e8fc7b56fcd751ffdd Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:55:53 +0100 Subject: [PATCH 4/8] feat: add native SUB/WAVE station picker --- BarWidget.qml | 161 +++++++++++++++++++ StationPicker.qml | 383 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 542 insertions(+), 2 deletions(-) diff --git a/BarWidget.qml b/BarWidget.qml index b233978..1dfea39 100644 --- a/BarWidget.qml +++ b/BarWidget.qml @@ -1,6 +1,167 @@ import QtQuick +import Quickshell +import Quickshell.Io import qs.Commons +import qs.Ui +import "StationModel.js" as StationModel BarWidget { + id: root moduleName: "getsubwave.radio" + + property bool playerRunning: false + property bool playerPaused: false + property int playerVolume: 70 + property string stationName: "SUB/WAVE" + property string stationUrl: "" + property string trackTitle: "" + property string trackArtist: "" + property bool stationOnline: true + readonly property string playerPath: Qt.resolvedUrl("subwave-player").toString().replace(/^file:\/\//, "") + readonly property string fetchPath: Qt.resolvedUrl("subwave-fetch").toString().replace(/^file:\/\//, "") + readonly property string statusPath: Quickshell.env("XDG_RUNTIME_DIR") + "/omarchy-subwave/status.json" + readonly property string label: trackTitle + ? trackTitle + (trackArtist ? " · " + trackArtist : "") + : stationName + + function applyStatus(raw) { + try { + if (typeof raw !== "string" || raw.length > 65536) return + var state = JSON.parse(raw || "{}") + playerRunning = state.running === true + playerPaused = state.paused === true + playerVolume = Math.max(0, Math.min(100, Math.round(Number(state.volume || 70)))) + stationName = StationModel.singleLine(state.station && state.station.name || "SUB/WAVE", 160) + stationUrl = StationModel.normalizeOrigin(state.station && state.station.url || "") + if (!playerRunning) { + trackTitle = "" + trackArtist = "" + } + nowTimer.running = playerRunning && stationUrl !== "" + if (nowTimer.running) refreshNowPlaying() + } catch (error) {} + } + + function applyNowPlaying(raw) { + try { + if (typeof raw !== "string" || raw.length > 65536) return + var state = JSON.parse(raw || "{}") + stationOnline = state.online !== false + if (state.station) stationName = StationModel.singleLine(state.station, 160) + if (!state.error) { + trackTitle = StationModel.singleLine(state.title, 512) + trackArtist = StationModel.singleLine(state.artist, 512) + } + } catch (error) { stationOnline = false } + } + + function runAction(action, value) { + if (actionProcess.running) return + actionProcess.command = value === undefined + ? [playerPath, action] + : [playerPath, action, String(value)] + actionProcess.running = true + } + + function changeVolume(delta) { + runAction("volume", Math.max(0, Math.min(100, playerVolume + (delta > 0 ? 5 : -5)))) + } + + function toggleOverlay() { + var configured = StationModel.normalizeOrigin(setting("stationUrl", "")) + var payload = JSON.stringify({ stationUrl: configured }) + Quickshell.execDetached(["omarchy-shell", "shell", "toggle", "getsubwave.radio", payload]) + } + + function refreshNowPlaying() { + if (nowProcess.running || !stationUrl) return + nowProcess.command = [fetchPath, "now-playing", stationUrl] + nowProcess.running = true + } + + implicitWidth: row.implicitWidth + Style.space(14) + implicitHeight: barSize + + FileView { + path: root.statusPath + watchChanges: true + atomicWrites: true + printErrors: false + onLoaded: root.applyStatus(text()) + onFileChanged: reload() + } + + Process { + id: statusProcess + command: [root.playerPath, "status"] + running: true + stdout: StdioCollector { id: statusOutput } + onExited: root.applyStatus(statusOutput.text) + } + + Process { + id: actionProcess + command: [] + stdout: StdioCollector { id: actionOutput } + onExited: root.applyStatus(actionOutput.text) + } + + Process { + id: nowProcess + command: [] + stdout: StdioCollector { id: nowOutput } + onExited: root.applyNowPlaying(nowOutput.text) + } + + Timer { + id: nowTimer + interval: 5000 + repeat: true + running: false + onTriggered: root.refreshNowPlaying() + } + + Row { + id: row + anchors.centerIn: parent + spacing: Style.space(6) + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "󰝚" + color: root.playerRunning && !root.playerPaused && root.stationOnline + ? Color.accent : root.bar.barForeground + font.family: root.bar.fontFamily + font.pixelSize: Style.font.body + } + + Text { + visible: !root.vertical + width: Math.min(implicitWidth, Style.space(180)) + anchors.verticalCenter: parent.verticalCenter + text: root.label + color: root.bar.barForeground + font.family: root.bar.fontFamily + font.pixelSize: Style.font.body + elide: Text.ElideRight + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton + cursorShape: Qt.PointingHandCursor + onClicked: function(mouse) { + if (mouse.button === Qt.MiddleButton) root.runAction("toggle") + else if (mouse.button === Qt.RightButton) root.runAction("stop") + else root.toggleOverlay() + } + onWheel: function(wheel) { root.changeVolume(wheel.angleDelta.y) } + onEntered: if (root.bar) root.bar.showTooltip(root, + (root.playerRunning ? (root.playerPaused ? "Paused · " : "Playing · ") : "Open · ") + + root.stationName + (root.trackTitle ? "\n" + root.label : "") + + " · " + root.playerVolume + "%") + onExited: if (root.bar) root.bar.hideTooltip(root) + } } diff --git a/StationPicker.qml b/StationPicker.qml index c23f196..a164252 100644 --- a/StationPicker.qml +++ b/StationPicker.qml @@ -1,8 +1,387 @@ import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import qs.Commons +import qs.Ui +import "StationModel.js" as StationModel Item { + id: root + + property string omarchyPath: Quickshell.env("OMARCHY_PATH") property var shell: null property var manifest: null - function open(payloadJson) {} - function close() {} + property bool opened: false + property string configuredUrl: "" + property var allStations: [] + property string filterText: "" + property int selectedIndex: 0 + property var liveByUrl: ({}) + property int liveRevision: 0 + property var probeQueue: [] + property string probingUrl: "" + property string errorText: "" + property string playingUrl: "" + readonly property string fetchPath: Qt.resolvedUrl("subwave-fetch").toString().replace(/^file:\/\//, "") + readonly property string playerPath: Qt.resolvedUrl("subwave-player").toString().replace(/^file:\/\//, "") + readonly property color background: Color.menu.background + readonly property color foreground: Color.menu.text + readonly property color border: Color.menu.border + readonly property color scrim: Color.menu.scrim + readonly property color accent: Color.accent + readonly property int cardWidth: Math.min(Style.space(680), panel.width - Style.gapsOut * 2) + readonly property int cardHeight: Math.min(Style.space(650), panel.height - Style.gapsOut * 2) + + function open(payloadJson) { + var payload = ({}) + try { payload = JSON.parse(payloadJson || "{}") } catch (error) {} + configuredUrl = StationModel.normalizeOrigin(payload.stationUrl || "") + opened = true + errorText = "" + filterText = "" + selectedIndex = 0 + loadCache() + Qt.callLater(function() { searchField.forceActiveFocus() }) + } + + function close() { + opened = false + probeTimer.stop() + probeQueue = [] + } + + function dismiss() { + close() + if (shell && typeof shell.hide === "function") shell.hide((manifest && manifest.id) || "getsubwave.radio") + } + + function loadCache() { + if (cacheProcess.running) return + cacheProcess.command = [fetchPath, "cache"] + cacheProcess.running = true + } + + function refreshCatalog() { + if (catalogProcess.running) return + catalogProcess.command = [fetchPath, "catalog"] + catalogProcess.running = true + } + + function applyCatalog(raw) { + try { + if (typeof raw !== "string" || raw.length > 1048576) throw new Error("Directory response is too large") + var parsed = JSON.parse(raw || "[]") + allStations = StationModel.mergeConfigured(parsed, configuredUrl) + rebuildVisible() + queueVisibleProbes() + } catch (error) { + errorText = "Station directory unavailable" + } + } + + function rebuildVisible() { + var rows = StationModel.searchStations(allStations, filterText) + visibleStations.clear() + for (var i = 0; i < rows.length; i++) visibleStations.append(rows[i]) + selectedIndex = Math.max(0, Math.min(selectedIndex, visibleStations.count - 1)) + stationList.currentIndex = selectedIndex + } + + function setFilter(value) { + filterText = StationModel.singleLine(value, 160) + rebuildVisible() + queueVisibleProbes() + } + + function moveSelection(delta) { + if (!visibleStations.count) return + selectedIndex = (selectedIndex + delta + visibleStations.count) % visibleStations.count + stationList.currentIndex = selectedIndex + stationList.positionViewAtIndex(selectedIndex, ListView.Contain) + } + + function playSelected() { + if (!visibleStations.count || playProcess.running) return + var station = visibleStations.get(selectedIndex) + if (playingUrl === station.url) { + dismiss() + return + } + errorText = "" + playProcess.stationUrl = station.url + playProcess.command = [playerPath, "play", station.url, station.name] + playProcess.running = true + } + + function queueVisibleProbes() { + var next = [] + var limit = Math.min(24, visibleStations.count) + for (var i = 0; i < limit; i++) { + var url = visibleStations.get(i).url + if (url !== probingUrl) next.push(url) + } + probeQueue = next + startNextProbe() + } + + function startNextProbe() { + if (probeProcess.running || !opened || probeQueue.length === 0) return + var next = probeQueue.slice() + probingUrl = next.shift() + probeQueue = next + probeProcess.command = [fetchPath, "now-playing", probingUrl] + probeProcess.running = true + } + + function applyProbe(url, raw) { + var state = ({ online: false, error: "Station unavailable" }) + try { + if (typeof raw === "string" && raw.length <= 65536) state = JSON.parse(raw || "{}") + } catch (error) {} + var copy = ({}) + for (var key in liveByUrl) copy[key] = liveByUrl[key] + copy[url] = state + liveByUrl = copy + liveRevision++ + } + + function liveFor(url) { + var revision = liveRevision + return liveByUrl[url] || null + } + + ListModel { id: visibleStations } + + Process { + id: cacheProcess + command: [] + stdout: StdioCollector { id: cacheOutput } + onExited: { + root.applyCatalog(cacheOutput.text) + root.refreshCatalog() + } + } + + Process { + id: catalogProcess + command: [] + stdout: StdioCollector { id: catalogOutput } + onExited: function(exitCode) { + if (exitCode === 0) root.applyCatalog(catalogOutput.text) + else if (root.allStations.length === 0) root.errorText = "Could not refresh the station directory" + } + } + + Process { + id: probeProcess + command: [] + stdout: StdioCollector { id: probeOutput } + onExited: { + root.applyProbe(root.probingUrl, probeOutput.text) + root.probingUrl = "" + root.startNextProbe() + } + } + + Process { + id: playProcess + property string stationUrl: "" + command: [] + stdout: StdioCollector { id: playOutput } + stderr: StdioCollector { id: playError } + onExited: function(exitCode) { + if (exitCode === 0) { + root.playingUrl = stationUrl + root.queueVisibleProbes() + } else root.errorText = StationModel.singleLine(playError.text, 200) || "Could not start this station" + } + } + + Timer { + id: probeTimer + interval: 30000 + repeat: true + running: root.opened + onTriggered: root.queueVisibleProbes() + } + + PanelWindow { + id: panel + visible: root.opened + anchors { top: true; bottom: true; left: true; right: true } + color: "transparent" + WlrLayershell.namespace: "omarchy-subwave" + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.keyboardFocus: root.opened ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + exclusionMode: ExclusionMode.Ignore + + Rectangle { anchors.fill: parent; color: root.scrim } + MouseArea { anchors.fill: parent; onClicked: root.dismiss() } + + BorderSurface { + id: card + width: root.cardWidth + height: root.cardHeight + anchors.centerIn: parent + radius: Style.cornerRadius + color: root.background + borderSpec: Border.surfaceSpec("menu", "border", root.border, Math.max(1, Style.space(2))) + + MouseArea { anchors.fill: parent; onClicked: {} } + + Column { + anchors.fill: parent + anchors.margins: Style.spacing.panelPadding + spacing: Style.spacing.md + + Row { + width: parent.width + spacing: Style.spacing.md + + Text { + text: "SUB/WAVE" + color: root.foreground + font.family: Style.font.menuFamily + font.pixelSize: Style.font.title + font.bold: true + } + + Text { + width: parent.width - x + text: visibleStations.count + " stations" + color: root.foreground + opacity: 0.58 + font.family: Style.font.menuFamily + font.pixelSize: Style.font.body + horizontalAlignment: Text.AlignRight + } + } + + TextField { + id: searchField + width: parent.width + placeholderText: "Search stations, places, genres…" + foreground: root.foreground + accent: root.accent + font.family: Style.font.menuFamily + font.pixelSize: Style.font.body + onTextChanged: root.setFilter(text) + Keys.onPressed: function(event) { + if (event.key === Qt.Key_Down) { root.moveSelection(1); event.accepted = true } + else if (event.key === Qt.Key_Up) { root.moveSelection(-1); event.accepted = true } + else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { root.playSelected(); event.accepted = true } + else if (event.key === Qt.Key_Escape) { + if (text) text = "" + else root.dismiss() + event.accepted = true + } + } + } + + Text { + visible: root.errorText !== "" + width: parent.width + text: root.errorText + color: Color.urgent + font.family: Style.font.menuFamily + font.pixelSize: Style.font.caption + wrapMode: Text.Wrap + } + + ListView { + id: stationList + width: parent.width + height: parent.height - y + clip: true + spacing: Style.spacing.xs + model: visibleStations + currentIndex: root.selectedIndex + + delegate: BorderSurface { + required property int index + required property string name + required property string url + required property string location + required property string country + required property string genre + required property bool featured + required property bool isConfigured + readonly property var live: root.liveFor(url) + width: ListView.view.width + height: Style.space(68) + radius: Style.spacing.labelGap + color: index === root.selectedIndex + ? Color.menu.selectedBackground + : Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.025) + borderSpec: index === root.selectedIndex + ? Border.surfaceSpec("menu", "selected-border", Color.menu.selectedBorder, 1) + : Border.flat(Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.08), 1) + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onEntered: root.selectedIndex = index + onClicked: { root.selectedIndex = index; root.playSelected() } + } + + Column { + anchors.left: parent.left + anchors.right: status.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Style.space(14) + anchors.rightMargin: Style.space(12) + spacing: Style.space(4) + + Text { + width: parent.width + text: name + (isConfigured ? " · MY STATION" : (featured ? " · FEATURED" : "")) + color: root.foreground + font.family: Style.font.menuFamily + font.pixelSize: Style.font.body + font.bold: true + elide: Text.ElideRight + } + + Text { + width: parent.width + text: live && live.title + ? live.title + (live.artist ? " · " + live.artist : "") + : [location || country, genre].filter(function(value) { return value }).join(" · ") + color: root.foreground + opacity: 0.62 + font.family: Style.font.menuFamily + font.pixelSize: Style.font.caption + elide: Text.ElideRight + } + } + + Text { + id: status + anchors.right: parent.right + anchors.rightMargin: Style.space(14) + anchors.verticalCenter: parent.verticalCenter + text: root.playingUrl === url ? "PLAYING" : (!live ? "CHECKING" : (live.online ? "ON AIR" : "OFFLINE")) + color: live && live.online ? root.accent : root.foreground + opacity: live && live.online ? 1 : 0.5 + font.family: Style.font.menuFamily + font.pixelSize: Style.font.caption + font.bold: true + } + } + + Text { + anchors.centerIn: parent + visible: visibleStations.count === 0 + text: root.filterText ? "No matching stations" : "No stations available" + color: root.foreground + opacity: 0.58 + font.family: Style.font.menuFamily + font.pixelSize: Style.font.body + } + } + } + } + } } From 70e9f1e052d8f0fc0ea7cf6243aea7fdf82a3514 Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:56:37 +0100 Subject: [PATCH 5/8] docs: document Omarchy SUB/WAVE plugin --- .github/workflows/validate.yml | 30 ++++++++ README.md | 124 +++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 .github/workflows/validate.yml create mode 100644 README.md diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..c88ab18 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,30 @@ +name: Validate + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install test dependencies + run: sudo apt-get update && sudo apt-get install -y jq socat + - name: Validate manifest contract + run: | + jq -e ' + .schemaVersion == 1 + and .id == "getsubwave.radio" + and (.kinds | sort) == (["bar-widget", "overlay"] | sort) + and .entryPoints.barWidget == "BarWidget.qml" + and .entryPoints.overlay == "StationPicker.qml" + ' manifest.json + test -x subwave-fetch + test -x subwave-player + test -x tests/run + - name: Run tests + run: ./tests/run diff --git a/README.md b/README.md new file mode 100644 index 0000000..a27e3ff --- /dev/null +++ b/README.md @@ -0,0 +1,124 @@ +# SUB/WAVE for Omarchy + +Listen to your own [SUB/WAVE](https://www.getsubwave.com) station and explore +the public community directory without leaving the Omarchy shell. The plugin +adds a theme-aware bar widget, a searchable station picker, and an MPV player +that works with Omarchy's existing media controls. + +## Install + +```bash +omarchy plugin add https://github.com/getsubwave/omarchy-subwave.git --enable +``` + +The community directory works immediately. To put your own self-hosted station +first in the list, configure its bare public origin: + +```bash +omarchy bar set getsubwave.radio stationUrl https://radio.example.com +``` + +Do not include `/listen`, `/stream.mp3`, credentials, query parameters, or a +fragment. The plugin derives the API and stream paths from the origin. + +## Controls + +### Bar + +| Input | Action | +| --- | --- | +| Left click | Open or close the station picker | +| Middle click | Play or pause | +| Right click | Stop playback | +| Mouse wheel | Change volume in 5% steps | + +### Station picker + +| Input | Action | +| --- | --- | +| Type | Search names, places, genres, operators, and descriptions | +| Up / Down | Move through stations | +| Enter | Play the selected station | +| Escape | Clear search, then close | + +Selecting the station that is already playing closes the picker. Playback uses +the station's always-available `/stream.mp3` mount. `mpv-mpris` exposes it to +the built-in `omarchy.media` widget, media keys, and compatible headset controls. + +## Data and privacy + +The plugin fetches the normalized community directory from +`https://www.getsubwave.com/stations.json`. It asks each visible station's +public `/api/now-playing` endpoint for its current track and online state, and +connects MPV directly to the selected station's `/stream.mp3` mount. + +Remote responses are size- and record-limited before entering QML. Only +credential-free HTTP(S) origins are accepted, remote strings are never +evaluated as commands, and cache/status writes are atomic. + +Version 1 supports public stations only. It does not accept or store listener +passwords. Favorites, requests, and station administration remain in the +station's web player. + +Non-secret persistent data is stored in: + +```text +${XDG_DATA_HOME:-~/.local/share}/omarchy-subwave/ +``` + +Player sockets, status, PID identity, and logs live in: + +```text +$XDG_RUNTIME_DIR/omarchy-subwave/ +``` + +## Remove + +Stop the dedicated player before removing the plugin: + +```bash +~/.config/omarchy/plugins/getsubwave.radio/subwave-player stop +omarchy plugin remove getsubwave.radio +``` + +The last station, volume, and directory cache remain under +`~/.local/share/omarchy-subwave/`. Remove that directory manually only if you +also want to delete those preferences. + +## Troubleshooting + +Check the helper contracts directly: + +```bash +~/.config/omarchy/plugins/getsubwave.radio/subwave-fetch catalog | jq 'length' +~/.config/omarchy/plugins/getsubwave.radio/subwave-fetch now-playing https://radio.example.com | jq . +~/.config/omarchy/plugins/getsubwave.radio/subwave-player status | jq . +``` + +MPV diagnostics are written to +`$XDG_RUNTIME_DIR/omarchy-subwave/mpv.log`. If the bar does not pick up a saved +plugin change, run: + +```bash +omarchy-shell shell rescanPlugins +``` + +Malformed or oversized saved data is not overwritten automatically. Back up +the affected file under `~/.local/share/omarchy-subwave/` before repairing or +removing it. + +## Development + +```bash +./tests/run +omarchy plugin validate . +qmllint -I /usr/share/omarchy/shell BarWidget.qml StationPicker.qml +``` + +The test suite uses temporary XDG directories and fake network/player +boundaries; it does not tune a real station. The final QML checks require an +Omarchy installation because they import the installed shell components. + +## License + +MIT From 41b39c441c07cb92577d3f3ddd8f44274b9077a5 Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 12:59:18 +0100 Subject: [PATCH 6/8] fix: wait for QML process output --- BarWidget.qml | 6 +++--- StationPicker.qml | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/BarWidget.qml b/BarWidget.qml index 1dfea39..16010cb 100644 --- a/BarWidget.qml +++ b/BarWidget.qml @@ -95,21 +95,21 @@ BarWidget { id: statusProcess command: [root.playerPath, "status"] running: true - stdout: StdioCollector { id: statusOutput } + stdout: StdioCollector { id: statusOutput; waitForEnd: true } onExited: root.applyStatus(statusOutput.text) } Process { id: actionProcess command: [] - stdout: StdioCollector { id: actionOutput } + stdout: StdioCollector { id: actionOutput; waitForEnd: true } onExited: root.applyStatus(actionOutput.text) } Process { id: nowProcess command: [] - stdout: StdioCollector { id: nowOutput } + stdout: StdioCollector { id: nowOutput; waitForEnd: true } onExited: root.applyNowPlaying(nowOutput.text) } diff --git a/StationPicker.qml b/StationPicker.qml index a164252..de30990 100644 --- a/StationPicker.qml +++ b/StationPicker.qml @@ -156,7 +156,7 @@ Item { Process { id: cacheProcess command: [] - stdout: StdioCollector { id: cacheOutput } + stdout: StdioCollector { id: cacheOutput; waitForEnd: true } onExited: { root.applyCatalog(cacheOutput.text) root.refreshCatalog() @@ -166,7 +166,7 @@ Item { Process { id: catalogProcess command: [] - stdout: StdioCollector { id: catalogOutput } + stdout: StdioCollector { id: catalogOutput; waitForEnd: true } onExited: function(exitCode) { if (exitCode === 0) root.applyCatalog(catalogOutput.text) else if (root.allStations.length === 0) root.errorText = "Could not refresh the station directory" @@ -176,7 +176,7 @@ Item { Process { id: probeProcess command: [] - stdout: StdioCollector { id: probeOutput } + stdout: StdioCollector { id: probeOutput; waitForEnd: true } onExited: { root.applyProbe(root.probingUrl, probeOutput.text) root.probingUrl = "" @@ -188,8 +188,8 @@ Item { id: playProcess property string stationUrl: "" command: [] - stdout: StdioCollector { id: playOutput } - stderr: StdioCollector { id: playError } + stdout: StdioCollector { id: playOutput; waitForEnd: true } + stderr: StdioCollector { id: playError; waitForEnd: true } onExited: function(exitCode) { if (exitCode === 0) { root.playingUrl = stationUrl From c7fbeabf3081f6ecef9ab2eb283f0341d01446ac Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 13:00:12 +0100 Subject: [PATCH 7/8] fix: parse station origins in QML --- StationModel.js | 11 +++-------- tests/model.test.mjs | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/StationModel.js b/StationModel.js index 1ba66aa..0fb93b6 100644 --- a/StationModel.js +++ b/StationModel.js @@ -9,14 +9,9 @@ function singleLine(value, limit) { function normalizeOrigin(value) { var raw = String(value || "").trim() if (!raw || /[\u0000-\u001f\u007f]/.test(raw)) return "" - try { - var parsed = new URL(raw) - if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "" - if (parsed.username || parsed.password || parsed.hash) return "" - return parsed.origin - } catch (error) { - return "" - } + var matched = raw.match(/^(https?):\/\/([^\/@?#\s]+)(?:\/[^?#]*)?\/?$/i) + if (!matched) return "" + return matched[1].toLowerCase() + "://" + matched[2] } function fallbackSlug(name) { diff --git a/tests/model.test.mjs b/tests/model.test.mjs index c00a7b6..157ed79 100644 --- a/tests/model.test.mjs +++ b/tests/model.test.mjs @@ -6,7 +6,8 @@ import { fileURLToPath } from "node:url" const testDir = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(testDir, "..", "StationModel.js"), "utf8") -const model = { Array, Boolean, JSON, Math, Number, Object, RegExp, String, URL } +// QML's JavaScript engine does not provide the browser/Node URL constructor. +const model = { Array, Boolean, JSON, Math, Number, Object, RegExp, String } vm.createContext(model) vm.runInContext(source, model) From 8ebe37d9ccfd6a87023e51bf472d7ce494f4e4e7 Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Mon, 17 Aug 2026 13:03:26 +0100 Subject: [PATCH 8/8] chore: finish Omarchy plugin validation --- README.md | 2 ++ preview.png | Bin 0 -> 101864 bytes 2 files changed, 2 insertions(+) create mode 100644 preview.png diff --git a/README.md b/README.md index a27e3ff..61b2698 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ the public community directory without leaving the Omarchy shell. The plugin adds a theme-aware bar widget, a searchable station picker, and an MPV player that works with Omarchy's existing media controls. +![SUB/WAVE station picker in Omarchy](preview.png) + ## Install ```bash diff --git a/preview.png b/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..76aecd13c8587fda91f0c70c3753287c083c2032 GIT binary patch literal 101864 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 z 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 literal 0 HcmV?d00001