feat: add fullscreen startup apps and apod wallpaper
This commit is contained in:
parent
9260cbff20
commit
039ccb6f72
2 changed files with 174 additions and 358 deletions
24
flake.lock
generated
24
flake.lock
generated
|
|
@ -7,11 +7,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775002057,
|
"lastModified": 1775171219,
|
||||||
"narHash": "sha256-2BlROtk2O6cHEBWYOodHIHWGh55x/kK0nlQIrVHRj68=",
|
"narHash": "sha256-3poVYyTB/THwwX2OIA4YNTEhg5pW3XEt1l53GV0j2mk=",
|
||||||
"owner": "ryoppippi",
|
"owner": "ryoppippi",
|
||||||
"repo": "claude-code-overlay",
|
"repo": "claude-code-overlay",
|
||||||
"rev": "f657902903109bd56352ff86cd522b4721b3b87a",
|
"rev": "644838d512a95c415886736f1e6dc28531625f7d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -87,11 +87,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775080052,
|
"lastModified": 1775143651,
|
||||||
"narHash": "sha256-jAB4ZZbx8ECu9GcE/PUUwT+wpooZ0Ssmn2imB8PVTdM=",
|
"narHash": "sha256-S0RqAyDPMTcv9vASMaE8eY1QexFysAOdnxUxFHIPOyE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "6267895e9898399f0ce2fe79b645e9ee4858aaff",
|
"rev": "d166a078541982a76f14d3e06e9665fa5c9ed85e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -180,11 +180,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775083152,
|
"lastModified": 1775171065,
|
||||||
"narHash": "sha256-jmj9atnmjkaqnmNz63TV0gcoaNeC1ooxmxyWgQ9vGfk=",
|
"narHash": "sha256-S0lTH4iokBAUoDLF8yiFowBCa3J7DrQLTE+isXAHCqM=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "f0acccabf10fa7fa1e8d27da0d20e2f6df3150b2",
|
"rev": "8014c3dae628bb117c00ad835d1a9deb39b3f731",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -228,11 +228,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775021133,
|
"lastModified": 1775162238,
|
||||||
"narHash": "sha256-JB0u0evfSlmNg9HdGDxtXjaCcdKUpFPdSAMGxvJo5Pw=",
|
"narHash": "sha256-0qt2cfUqfTbesQlvO3NeJLCqa7NoVxUK9vxs79prNHk=",
|
||||||
"owner": "0xc000022070",
|
"owner": "0xc000022070",
|
||||||
"repo": "zen-browser-flake",
|
"repo": "zen-browser-flake",
|
||||||
"rev": "4bf1a6837064486c4f573a9d500c4cf3c1c075c0",
|
"rev": "9bf98d57ca82698483ec2d9211ce01669ba37820",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
504
home.nix
504
home.nix
|
|
@ -9,6 +9,106 @@ let
|
||||||
name = "Jet";
|
name = "Jet";
|
||||||
email = "jet@extremist.software";
|
email = "jet@extremist.software";
|
||||||
sshSigningKey = "~/.ssh/id_ed25519.pub";
|
sshSigningKey = "~/.ssh/id_ed25519.pub";
|
||||||
|
zenStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "zen-startup";
|
||||||
|
desktopName = "Zen Startup";
|
||||||
|
comment = "Launch Zen in fullscreen";
|
||||||
|
exec = "${config.programs.zen-browser.package}/bin/zen --fullscreen";
|
||||||
|
terminal = false;
|
||||||
|
categories = [ "Network" ];
|
||||||
|
};
|
||||||
|
kittyZellijStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "kitty-zellij-startup";
|
||||||
|
desktopName = "Kitty Zellij Startup";
|
||||||
|
comment = "Open Kitty, pick a directory, and launch Zellij";
|
||||||
|
exec = "${pkgs.kitty}/bin/kitty --start-as=fullscreen ${zellijNewTabZoxide}/bin/zellij-new-tab-zoxide";
|
||||||
|
terminal = false;
|
||||||
|
categories = [
|
||||||
|
"TerminalEmulator"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
vesktopStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "vesktop-startup";
|
||||||
|
desktopName = "Vesktop Startup";
|
||||||
|
comment = "Launch Vesktop in fullscreen";
|
||||||
|
exec = "${pkgs.vesktop}/bin/vesktop --start-fullscreen";
|
||||||
|
terminal = false;
|
||||||
|
categories = [ "Network" ];
|
||||||
|
};
|
||||||
|
signalStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "signal-startup";
|
||||||
|
desktopName = "Signal Startup";
|
||||||
|
comment = "Launch Signal in fullscreen";
|
||||||
|
exec = "${pkgs.signal-desktop}/bin/signal-desktop --start-fullscreen";
|
||||||
|
terminal = false;
|
||||||
|
categories = [ "Network" ];
|
||||||
|
};
|
||||||
|
thunderbirdStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "thunderbird-startup";
|
||||||
|
desktopName = "Thunderbird Startup";
|
||||||
|
comment = "Launch Thunderbird in fullscreen";
|
||||||
|
exec = "${pkgs.thunderbird}/bin/thunderbird --fullscreen";
|
||||||
|
terminal = false;
|
||||||
|
categories = [ "Network" ];
|
||||||
|
};
|
||||||
|
zulipStartup = pkgs.makeDesktopItem {
|
||||||
|
name = "zulip-startup";
|
||||||
|
desktopName = "Zulip Startup";
|
||||||
|
comment = "Launch Zulip in fullscreen";
|
||||||
|
exec = "${pkgs.zulip}/bin/zulip --start-fullscreen";
|
||||||
|
terminal = false;
|
||||||
|
categories = [ "Network" ];
|
||||||
|
};
|
||||||
|
nasaApodWallpaper = pkgs.writeShellApplication {
|
||||||
|
name = "nasa-apod-wallpaper";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.glib
|
||||||
|
pkgs.jq
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
state_dir="${config.home.homeDirectory}/.local/state/nasa-apod"
|
||||||
|
mkdir -p "$state_dir"
|
||||||
|
|
||||||
|
json="$(curl -fsSL 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')"
|
||||||
|
media_type="$(printf '%s' "$json" | jq -r '.media_type // empty')"
|
||||||
|
|
||||||
|
if [ "$media_type" != "image" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
image_url="$(printf '%s' "$json" | jq -r '.hdurl // .url // empty')"
|
||||||
|
if [ -z "$image_url" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ext="''${image_url##*.}"
|
||||||
|
ext="''${ext%%\?*}"
|
||||||
|
if [ -z "$ext" ] || [ "$ext" = "$image_url" ]; then
|
||||||
|
ext="jpg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
date_stamp="$(printf '%s' "$json" | jq -r '.date // empty')"
|
||||||
|
if [ -z "$date_stamp" ]; then
|
||||||
|
date_stamp="$(date +%F)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
target="$state_dir/apod-$date_stamp.$ext"
|
||||||
|
tmp="$target.tmp"
|
||||||
|
|
||||||
|
curl -fsSL "$image_url" -o "$tmp"
|
||||||
|
mv "$tmp" "$target"
|
||||||
|
ln -sfn "$target" "$state_dir/current"
|
||||||
|
|
||||||
|
wallpaper_uri="file://$state_dir/current"
|
||||||
|
gsettings set org.gnome.desktop.background picture-uri "$wallpaper_uri"
|
||||||
|
gsettings set org.gnome.desktop.background picture-uri-dark "$wallpaper_uri"
|
||||||
|
gsettings set org.gnome.desktop.background picture-options 'zoom'
|
||||||
|
'';
|
||||||
|
};
|
||||||
zellijNewTabZoxide = pkgs.writeShellApplication {
|
zellijNewTabZoxide = pkgs.writeShellApplication {
|
||||||
name = "zellij-new-tab-zoxide";
|
name = "zellij-new-tab-zoxide";
|
||||||
runtimeInputs = [
|
runtimeInputs = [
|
||||||
|
|
@ -27,8 +127,11 @@ let
|
||||||
done)"
|
done)"
|
||||||
|
|
||||||
if [ -z "$dirs" ]; then
|
if [ -z "$dirs" ]; then
|
||||||
|
if [ -n "''${ZELLIJ:-}" ]; then
|
||||||
exec ${pkgs.bashInteractive}/bin/bash -i
|
exec ${pkgs.bashInteractive}/bin/bash -i
|
||||||
fi
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
dir="$(printf '%s\n' "$dirs" | ${pkgs.fzf}/bin/fzf \
|
dir="$(printf '%s\n' "$dirs" | ${pkgs.fzf}/bin/fzf \
|
||||||
--delimiter='\t' \
|
--delimiter='\t' \
|
||||||
|
|
@ -54,11 +157,34 @@ let
|
||||||
|
|
||||||
cd "$dir"
|
cd "$dir"
|
||||||
|
|
||||||
|
escape_kdl() {
|
||||||
|
local value="$1"
|
||||||
|
value="''${value//\\/\\\\}"
|
||||||
|
value="''${value//\"/\\\"}"
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
if [ -n "''${ZELLIJ:-}" ]; then
|
if [ -n "''${ZELLIJ:-}" ]; then
|
||||||
${pkgs.zellij}/bin/zellij action rename-tab "$tab_name" >/dev/null 2>&1 || true
|
${pkgs.zellij}/bin/zellij action rename-tab "$tab_name" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "''${ZELLIJ:-}" ]; then
|
||||||
exec ${pkgs.bashInteractive}/bin/bash -i
|
exec ${pkgs.bashInteractive}/bin/bash -i
|
||||||
|
fi
|
||||||
|
|
||||||
|
layout_file="${config.home.homeDirectory}/.local/state/zellij-launch-layout.kdl"
|
||||||
|
mkdir -p "$(dirname "$layout_file")"
|
||||||
|
printf '%s\n' \
|
||||||
|
'layout {' \
|
||||||
|
" tab name=\"$(escape_kdl "$tab_name")\" cwd=\"$(escape_kdl "$dir")\" {" \
|
||||||
|
' pane focus=true' \
|
||||||
|
' pane size=1 borderless=true {' \
|
||||||
|
' plugin location="compact-bar"' \
|
||||||
|
' }' \
|
||||||
|
' }' \
|
||||||
|
'}' > "$layout_file"
|
||||||
|
|
||||||
|
exec ${pkgs.zellij}/bin/zellij -l "$layout_file"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
zellijSyncTabName = pkgs.writeShellApplication {
|
zellijSyncTabName = pkgs.writeShellApplication {
|
||||||
|
|
@ -100,327 +226,6 @@ let
|
||||||
exec ${pkgs.zellij}/bin/zellij action rename-tab "$next_tab_name"
|
exec ${pkgs.zellij}/bin/zellij action rename-tab "$next_tab_name"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
browserAudio = pkgs.writeShellApplication {
|
|
||||||
name = "browser-audio";
|
|
||||||
runtimeInputs = [
|
|
||||||
pkgs.coreutils
|
|
||||||
pkgs.curl
|
|
||||||
pkgs.ffmpeg-full
|
|
||||||
pkgs.fzf
|
|
||||||
pkgs.gawk
|
|
||||||
pkgs.gnugrep
|
|
||||||
pkgs.jq
|
|
||||||
pkgs.pulseaudio
|
|
||||||
pkgs.qpwgraph
|
|
||||||
pkgs.pavucontrol
|
|
||||||
pkgs.procps
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
sink_name="''${BROWSER_AUDIO_SINK:-browser-radio}"
|
|
||||||
sink_description="''${BROWSER_AUDIO_DESCRIPTION:-Browser Radio}"
|
|
||||||
bitrate="''${BROWSER_AUDIO_BITRATE:-128k}"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
printf '%s\n' \
|
|
||||||
"Usage: browser-audio <command> [args]" \
|
|
||||||
"" \
|
|
||||||
"Commands:" \
|
|
||||||
" setup Create the dedicated browser sink if needed" \
|
|
||||||
" pick Pick a live playback stream and move it to the sink" \
|
|
||||||
" route <regex> Move matching playback streams to the sink" \
|
|
||||||
" status Show the sink and any streams already routed to it" \
|
|
||||||
" open Open pavucontrol and qpwgraph for manual routing" \
|
|
||||||
" cast <icecast-url> Stream the sink monitor to Icecast/Shoutcast with ffmpeg" \
|
|
||||||
" cast-pick <url> Pick a live stream, route it, then start casting" \
|
|
||||||
" stop Stop prior ffmpeg jobs and remove the sink" \
|
|
||||||
" remove Remove the dedicated sink" \
|
|
||||||
"" \
|
|
||||||
"Notes:" \
|
|
||||||
" - If your browser exposes a tab as its own playback stream, pick can isolate it." \
|
|
||||||
" - Otherwise, launch a dedicated browser instance for music and route that stream."
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_sink() {
|
|
||||||
if ! pactl list short sinks | awk '{print $2}' | grep -Fxq "$sink_name"; then
|
|
||||||
pactl load-module module-null-sink \
|
|
||||||
sink_name="$sink_name" \
|
|
||||||
sink_properties="device.description=$sink_description" >/dev/null
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
sink_module_id() {
|
|
||||||
pactl -f json list modules | jq -r --arg sink_name "$sink_name" '
|
|
||||||
.[]
|
|
||||||
| select(.name == "module-null-sink")
|
|
||||||
| select((.argument // "") | contains("sink_name=" + $sink_name))
|
|
||||||
| .index
|
|
||||||
' | head -n1
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_existing_casts() {
|
|
||||||
pkill -f "ffmpeg.*$sink_name\.monitor" >/dev/null 2>&1 || true
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_sink() {
|
|
||||||
local module_id
|
|
||||||
|
|
||||||
module_id="$(sink_module_id || true)"
|
|
||||||
if [ -n "$module_id" ] && [ "$module_id" != "null" ]; then
|
|
||||||
pactl unload-module "$module_id"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_state() {
|
|
||||||
stop_existing_casts
|
|
||||||
remove_sink
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_rows() {
|
|
||||||
pactl -f json list sink-inputs | jq -r '
|
|
||||||
.[]
|
|
||||||
| [
|
|
||||||
(.index | tostring),
|
|
||||||
(.sink | tostring),
|
|
||||||
(.properties."application.name" // "unknown-app"),
|
|
||||||
(.properties."media.name" // .properties."node.description" // "unknown-media"),
|
|
||||||
(.properties."application.process.binary" // "unknown-bin")
|
|
||||||
]
|
|
||||||
| @tsv
|
|
||||||
'
|
|
||||||
}
|
|
||||||
|
|
||||||
pick_stream() {
|
|
||||||
local selection
|
|
||||||
|
|
||||||
selection="$(stream_rows | fzf \
|
|
||||||
--delimiter=$'\t' \
|
|
||||||
--with-nth=3,4,5 \
|
|
||||||
--layout=reverse \
|
|
||||||
--border \
|
|
||||||
--prompt='audio> ' \
|
|
||||||
--header=$'Pick a live playback stream to route into browser-radio\napp | media | binary' \
|
|
||||||
--exit-0)"
|
|
||||||
|
|
||||||
if [ -z "$selection" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
pactl move-sink-input "$(printf '%s\n' "$selection" | cut -f1)" "$sink_name"
|
|
||||||
}
|
|
||||||
|
|
||||||
route_matching() {
|
|
||||||
local pattern="$1"
|
|
||||||
local matches
|
|
||||||
|
|
||||||
matches="$(stream_rows | grep -Ei "$pattern" || true)"
|
|
||||||
if [ -z "$matches" ]; then
|
|
||||||
printf 'No playback streams matched %s\n' "$pattern" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s\n' "$matches" | while IFS=$'\t' read -r stream_id _rest; do
|
|
||||||
[ -n "$stream_id" ] || continue
|
|
||||||
pactl move-sink-input "$stream_id" "$sink_name"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
show_status() {
|
|
||||||
printf 'Sink: %s\n' "$sink_name"
|
|
||||||
pactl list short sinks | awk -v sink="$sink_name" '$2 == sink {print}'
|
|
||||||
printf '\nStreams on %s:\n' "$sink_name"
|
|
||||||
pactl -f json list sink-inputs | jq -r --arg sink_name "$sink_name" --argjson sink_index "$(pactl list short sinks | awk -v sink="$sink_name" '$2 == sink {print $1; exit}')" '
|
|
||||||
.[]
|
|
||||||
| select(.sink == $sink_index)
|
|
||||||
| "- #\(.index) \(.properties["application.name"] // "unknown-app") :: \(.properties["media.name"] // .properties["node.description"] // "unknown-media")"
|
|
||||||
'
|
|
||||||
}
|
|
||||||
|
|
||||||
cast_sink() {
|
|
||||||
local url="$1"
|
|
||||||
local rest auth host_path endpoint
|
|
||||||
local tmpdir fifo ffmpeg_pid curl_pid ffmpeg_status curl_status interrupted=0
|
|
||||||
|
|
||||||
case "$url" in
|
|
||||||
icecast://*)
|
|
||||||
rest="''${url#icecast://}"
|
|
||||||
auth="''${rest%%@*}"
|
|
||||||
host_path="''${rest#*@}"
|
|
||||||
endpoint="http://''${host_path}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf 'cast requires an icecast:// URL\n' >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
tmpdir="$(mktemp -d)"
|
|
||||||
fifo="$tmpdir/audio.mp3"
|
|
||||||
mkfifo "$fifo"
|
|
||||||
|
|
||||||
cleanup_cast() {
|
|
||||||
local pid
|
|
||||||
local waited
|
|
||||||
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
|
|
||||||
for pid in "''${ffmpeg_pid:-}" "''${curl_pid:-}"; do
|
|
||||||
[ -n "$pid" ] || continue
|
|
||||||
kill "$pid" >/dev/null 2>&1 || true
|
|
||||||
done
|
|
||||||
|
|
||||||
for pid in "''${ffmpeg_pid:-}" "''${curl_pid:-}"; do
|
|
||||||
[ -n "$pid" ] || continue
|
|
||||||
waited=0
|
|
||||||
while kill -0 "$pid" >/dev/null 2>&1; do
|
|
||||||
if [ "$waited" -ge 20 ]; then
|
|
||||||
kill -9 "$pid" >/dev/null 2>&1 || true
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
waited=$((waited + 1))
|
|
||||||
done
|
|
||||||
wait "$pid" >/dev/null 2>&1 || true
|
|
||||||
done
|
|
||||||
|
|
||||||
rm -rf "$tmpdir"
|
|
||||||
if [ "$interrupted" -eq 1 ]; then
|
|
||||||
exit 130
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
trap 'interrupted=1; cleanup_cast' INT TERM
|
|
||||||
trap cleanup_cast EXIT
|
|
||||||
|
|
||||||
curl \
|
|
||||||
--silent \
|
|
||||||
--show-error \
|
|
||||||
--http1.0 \
|
|
||||||
--user "$auth" \
|
|
||||||
--header 'Content-Type: audio/mpeg' \
|
|
||||||
--request SOURCE \
|
|
||||||
--data-binary @- \
|
|
||||||
"$endpoint" <"$fifo" &
|
|
||||||
curl_pid=$!
|
|
||||||
|
|
||||||
ffmpeg \
|
|
||||||
-y \
|
|
||||||
-hide_banner \
|
|
||||||
-loglevel warning \
|
|
||||||
-f pulse \
|
|
||||||
-channel_layout stereo \
|
|
||||||
-i "$sink_name.monitor" \
|
|
||||||
-ac 2 \
|
|
||||||
-ar 44100 \
|
|
||||||
-acodec libmp3lame \
|
|
||||||
-b:a "$bitrate" \
|
|
||||||
-id3v2_version 0 \
|
|
||||||
-write_xing 0 \
|
|
||||||
-f mp3 \
|
|
||||||
"$fifo" &
|
|
||||||
ffmpeg_pid=$!
|
|
||||||
|
|
||||||
set +e
|
|
||||||
wait "$ffmpeg_pid"
|
|
||||||
ffmpeg_status=$?
|
|
||||||
wait "$curl_pid"
|
|
||||||
curl_status=$?
|
|
||||||
set -e
|
|
||||||
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
rm -rf "$tmpdir"
|
|
||||||
|
|
||||||
if [ "$ffmpeg_status" -ne 0 ]; then
|
|
||||||
return "$ffmpeg_status"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$curl_status" -ne 0 ]; then
|
|
||||||
return "$curl_status"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
command="''${1:-help}"
|
|
||||||
case "$command" in
|
|
||||||
setup)
|
|
||||||
ensure_sink
|
|
||||||
show_status
|
|
||||||
;;
|
|
||||||
pick)
|
|
||||||
ensure_sink
|
|
||||||
pick_stream
|
|
||||||
show_status
|
|
||||||
;;
|
|
||||||
route)
|
|
||||||
ensure_sink
|
|
||||||
if [ "''${2:-}" = "" ]; then
|
|
||||||
printf 'route requires a regex\n' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
route_matching "$2"
|
|
||||||
show_status
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
ensure_sink
|
|
||||||
show_status
|
|
||||||
;;
|
|
||||||
open)
|
|
||||||
ensure_sink
|
|
||||||
pavucontrol >/dev/null 2>&1 &
|
|
||||||
qpwgraph >/dev/null 2>&1 &
|
|
||||||
;;
|
|
||||||
cast)
|
|
||||||
reset_state
|
|
||||||
ensure_sink
|
|
||||||
if [ "''${2:-}" = "" ]; then
|
|
||||||
printf 'cast requires an icecast:// URL\n' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cast_sink "$2"
|
|
||||||
;;
|
|
||||||
cast-pick)
|
|
||||||
reset_state
|
|
||||||
ensure_sink
|
|
||||||
if [ "''${2:-}" = "" ]; then
|
|
||||||
printf 'cast-pick requires an icecast:// URL\n' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
pick_stream
|
|
||||||
show_status
|
|
||||||
cast_sink "$2"
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
reset_state
|
|
||||||
;;
|
|
||||||
remove)
|
|
||||||
remove_sink
|
|
||||||
;;
|
|
||||||
help|-h|--help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf 'Unknown command: %s\n\n' "$command" >&2
|
|
||||||
usage >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
zenRadio = pkgs.writeShellApplication {
|
|
||||||
name = "zen-radio";
|
|
||||||
runtimeInputs = [
|
|
||||||
config.programs.zen-browser.package
|
|
||||||
pkgs.coreutils
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
profile_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/zen-radio-profile"
|
|
||||||
mkdir -p "$profile_dir"
|
|
||||||
|
|
||||||
exec zen --new-instance --profile "$profile_dir" "$@"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ inputs.zen-browser.homeModules.default ];
|
imports = [ inputs.zen-browser.homeModules.default ];
|
||||||
|
|
@ -431,6 +236,11 @@ in
|
||||||
|
|
||||||
# Configure GNOME settings
|
# Configure GNOME settings
|
||||||
dconf.settings = {
|
dconf.settings = {
|
||||||
|
"org/gnome/desktop/background" = {
|
||||||
|
picture-options = "zoom";
|
||||||
|
picture-uri = "file://${config.home.homeDirectory}/.local/state/nasa-apod/current";
|
||||||
|
picture-uri-dark = "file://${config.home.homeDirectory}/.local/state/nasa-apod/current";
|
||||||
|
};
|
||||||
"org/gnome/desktop/interface" = {
|
"org/gnome/desktop/interface" = {
|
||||||
clock-format = "12h";
|
clock-format = "12h";
|
||||||
clock-show-weekday = true;
|
clock-show-weekday = true;
|
||||||
|
|
@ -487,7 +297,6 @@ in
|
||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
bat
|
bat
|
||||||
browserAudio
|
|
||||||
ffmpeg-full
|
ffmpeg-full
|
||||||
claude-code
|
claude-code
|
||||||
opencode
|
opencode
|
||||||
|
|
@ -535,7 +344,6 @@ in
|
||||||
tor-browser
|
tor-browser
|
||||||
vesktop
|
vesktop
|
||||||
vlc
|
vlc
|
||||||
zenRadio
|
|
||||||
zulip
|
zulip
|
||||||
linphone
|
linphone
|
||||||
lmstudio
|
lmstudio
|
||||||
|
|
@ -750,10 +558,6 @@ in
|
||||||
confirm_os_window_close = "0";
|
confirm_os_window_close = "0";
|
||||||
enable_audio_bell = "no";
|
enable_audio_bell = "no";
|
||||||
};
|
};
|
||||||
keybindings = {
|
|
||||||
"ctrl+shift+c" = "copy_and_clear_or_interrupt";
|
|
||||||
"ctrl+shift+v" = "paste_from_clipboard";
|
|
||||||
};
|
|
||||||
themeFile = "GitHub_Dark_High_Contrast";
|
themeFile = "GitHub_Dark_High_Contrast";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -860,7 +664,7 @@ in
|
||||||
xdg.desktopEntries.kitty = {
|
xdg.desktopEntries.kitty = {
|
||||||
name = "Kitty";
|
name = "Kitty";
|
||||||
genericName = "Terminal Emulator";
|
genericName = "Terminal Emulator";
|
||||||
exec = "kitty --start-as=fullscreen";
|
exec = "${pkgs.kitty}/bin/kitty --start-as=fullscreen ${zellijNewTabZoxide}/bin/zellij-new-tab-zoxide";
|
||||||
icon = "kitty";
|
icon = "kitty";
|
||||||
type = "Application";
|
type = "Application";
|
||||||
categories = [
|
categories = [
|
||||||
|
|
@ -870,20 +674,6 @@ in
|
||||||
comment = "Fast, featureful, GPU based terminal emulator";
|
comment = "Fast, featureful, GPU based terminal emulator";
|
||||||
};
|
};
|
||||||
|
|
||||||
xdg.desktopEntries.zen-radio = {
|
|
||||||
name = "Zen Radio";
|
|
||||||
genericName = "Dedicated Browser Audio";
|
|
||||||
exec = "zen-radio %U";
|
|
||||||
icon = "zen";
|
|
||||||
type = "Application";
|
|
||||||
categories = [
|
|
||||||
"Network"
|
|
||||||
"WebBrowser"
|
|
||||||
"AudioVideo"
|
|
||||||
];
|
|
||||||
comment = "Dedicated Zen instance for isolating music playback";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Extract archives on double-click
|
# Extract archives on double-click
|
||||||
xdg.desktopEntries.extract-here = {
|
xdg.desktopEntries.extract-here = {
|
||||||
name = "Extract Here";
|
name = "Extract Here";
|
||||||
|
|
@ -910,11 +700,37 @@ in
|
||||||
xdg.autostart = {
|
xdg.autostart = {
|
||||||
enable = true;
|
enable = true;
|
||||||
entries = [
|
entries = [
|
||||||
pkgs.kitty
|
zenStartup
|
||||||
config.programs.zen-browser.package
|
kittyZellijStartup
|
||||||
|
signalStartup
|
||||||
|
thunderbirdStartup
|
||||||
|
vesktopStartup
|
||||||
|
zulipStartup
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.user.services.nasa-apod-wallpaper = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Fetch NASA APOD wallpaper";
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
PartOf = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${nasaApodWallpaper}/bin/nasa-apod-wallpaper";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.timers.nasa-apod-wallpaper = {
|
||||||
|
Unit.Description = "Refresh NASA APOD wallpaper daily";
|
||||||
|
Timer = {
|
||||||
|
OnStartupSec = "2m";
|
||||||
|
OnUnitActiveSec = "1d";
|
||||||
|
Unit = "nasa-apod-wallpaper.service";
|
||||||
|
};
|
||||||
|
Install.WantedBy = [ "timers.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
# Set Zen Browser as default
|
# Set Zen Browser as default
|
||||||
xdg.mimeApps = {
|
xdg.mimeApps = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue