Radio
This commit is contained in:
@@ -27,3 +27,5 @@ $border-width: 2px;
|
||||
|
||||
$gaps-screen: 8px;
|
||||
$gaps-window: 4px;
|
||||
|
||||
$panel-font-size: 10pt;
|
||||
@@ -1,66 +1,90 @@
|
||||
.radio-win {
|
||||
//margin: $gaps-screen;
|
||||
//padding: .5em;
|
||||
|
||||
.radio-accent { background-color: $base0D; }
|
||||
|
||||
// Now playing
|
||||
.radio-now-playing {
|
||||
margin-bottom: 8pt;
|
||||
}
|
||||
|
||||
.album_art, .station_art {
|
||||
.radio-art {
|
||||
background-repeat: no-repeat;
|
||||
@include border-radius;
|
||||
@include background-base2;
|
||||
min-width: 72px;
|
||||
min-height: 72px;
|
||||
}
|
||||
|
||||
.album_art {
|
||||
background-size: 240px;
|
||||
min-height: 240px;
|
||||
min-width: 240px;
|
||||
margin: $gaps-screen;
|
||||
}
|
||||
|
||||
.song {
|
||||
@include color-accent;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: 20px 0 0;
|
||||
}
|
||||
|
||||
.artist {
|
||||
color: $base0E;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin: 0 0 $gaps-screen;
|
||||
}
|
||||
|
||||
.btn_bar {
|
||||
.radio-art-icon {
|
||||
font-size: 2em;
|
||||
@include color-body;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.radio-song {
|
||||
font-size: 0.88em;
|
||||
font-weight: bold;
|
||||
margin: $gaps-screen 0;
|
||||
@include color-base;
|
||||
margin-bottom: 2pt;
|
||||
}
|
||||
|
||||
.btn_play {
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
margin: 0 12px;
|
||||
|
||||
&:hover { @include color-base; }
|
||||
.radio-artist {
|
||||
font-size: 0.74em;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
.station_list {
|
||||
border-right: $border-width solid $base03;
|
||||
margin-right: $gaps-screen;
|
||||
// Controls
|
||||
.radio-controls {
|
||||
margin-top: 6pt;
|
||||
}
|
||||
|
||||
.station_art {
|
||||
background-size: 50px;
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
margin: $gaps-window;
|
||||
margin-right: $gaps-screen;
|
||||
@include background-base;
|
||||
border: $border-width solid $base00;
|
||||
|
||||
&:hover { border-color: $base04; }
|
||||
.radio-ctrl-btn {
|
||||
font-size: 2em;
|
||||
padding: 4pt 20pt;
|
||||
@include border-radius;
|
||||
@include color-body;
|
||||
&:hover { @include background-active; @include color-base; }
|
||||
}
|
||||
|
||||
.station_sel {
|
||||
border-color: $base03;
|
||||
// Station list
|
||||
.station-list {}
|
||||
|
||||
scrollbar {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
min-width: 6px;
|
||||
}
|
||||
scrollbar trough {
|
||||
@include background-base2;
|
||||
@include border-radius;
|
||||
min-width: 6px;
|
||||
}
|
||||
scrollbar slider {
|
||||
background-color: $base04;
|
||||
@include border-radius;
|
||||
min-width: 6px;
|
||||
min-height: 20px;
|
||||
&:hover { background-color: $base05; }
|
||||
}
|
||||
|
||||
.station-row {
|
||||
padding: 4pt 3pt;
|
||||
@include border-radius;
|
||||
&:hover { @include background-base2; }
|
||||
}
|
||||
|
||||
.station-row-active {
|
||||
.station-name { @include color-accent; }
|
||||
}
|
||||
|
||||
.station-icon {
|
||||
background-repeat: no-repeat;
|
||||
@include border-radius;
|
||||
@include background-base2;
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
margin-right: 8pt;
|
||||
}
|
||||
|
||||
.station-name {
|
||||
font-size: 0.76em;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
.cpubar, .gpubar, .membar, .batbar { @include background-base2; margin: $gaps-window 0; }
|
||||
|
||||
// Window chrome
|
||||
.sys-win { padding: 10pt; }
|
||||
.sys-win { padding: 10pt; font-size: $panel-font-size; }
|
||||
.sys-section { margin-bottom: 0; }
|
||||
.sys-section-header { margin-bottom: 10pt; }
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
.ram-ring { color: $base08; }
|
||||
.swap-ring { color: $base09; }
|
||||
|
||||
// Ring margins — freq rings use larger margins for concentric overlay effect
|
||||
// Ring margins - freq rings use larger margins for concentric overlay effect
|
||||
.cpu-usage-ring, .gpu-ring { margin: 3pt; }
|
||||
.ram-ring, .bat-ring { margin: 4pt; }
|
||||
.swap-ring { margin: 3.5pt; }
|
||||
|
||||
@@ -41,7 +41,7 @@ make_content() {
|
||||
usb_connected=true
|
||||
fi
|
||||
|
||||
# WiFi — use IP presence as connection indicator (more reliable than wpa_cli)
|
||||
# WiFi - use IP presence as connection indicator (more reliable than wpa_cli)
|
||||
local wifi_connected=false wifi_enabled=false wifi_icon="" wifi_ssid=""
|
||||
if ! rfkill list wlan 2>/dev/null | grep -q "Soft blocked: yes"; then
|
||||
wifi_enabled=true
|
||||
|
||||
@@ -1,12 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
PANEL="$1"
|
||||
CURRENT=$(eww state 2>/dev/null | grep '^active-panel:' | sed 's/^active-panel: //' | tr -d '"')
|
||||
|
||||
# Drop concurrent invocations, but recover from stale locks (dead processes)
|
||||
LOCK="/tmp/eww_panel_toggle.lock"
|
||||
if [ -f "$LOCK" ] && kill -0 "$(cat "$LOCK" 2>/dev/null)" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
echo $$ > "$LOCK"
|
||||
trap 'rm -f "$LOCK"' EXIT
|
||||
|
||||
CURRENT=$(eww get active-panel 2>/dev/null | tr -d '"')
|
||||
|
||||
open_popup() {
|
||||
local screen
|
||||
screen=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.focused == true) | .name' | head -n1)
|
||||
if [ -n "$screen" ]; then
|
||||
eww open popup --screen "$screen"
|
||||
else
|
||||
eww open popup
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$CURRENT" = "$PANEL" ]; then
|
||||
eww close popup
|
||||
eww update active-panel=""
|
||||
eww close popup 2>/dev/null
|
||||
else
|
||||
eww update active-panel="$PANEL"
|
||||
SCREEN=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.focused == true) | .name' | head -n1)
|
||||
[ -n "$SCREEN" ] && eww open popup --screen "$SCREEN" || eww open popup
|
||||
open_popup
|
||||
fi
|
||||
|
||||
@@ -1,106 +1,224 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
get_time_ms() {
|
||||
date -u +%s%3N
|
||||
}
|
||||
|
||||
URL_BASE="https://www.radiorecord.ru/api"
|
||||
|
||||
MPV_PID_FILE="/tmp/mpv_radio_pid"
|
||||
RADIO_ID_FILE="/tmp/radio_id"
|
||||
|
||||
STATION_IDS='[507,522,523,536,537,42532,42602]'
|
||||
|
||||
# Custom (non-radiorecord) stations
|
||||
# id must be a unique integer >= 1000000 to avoid collision with radiorecord IDs.
|
||||
# icon_fill_white: URL to station icon image, or "" for none.
|
||||
CUSTOM_STATIONS='[
|
||||
]'
|
||||
|
||||
STATIONS="[]"
|
||||
DEFAULT_INFO='{"artist":"","song":"","image600":""}'
|
||||
DEFAULT_MEDIA='{"player":"","status":"Stopped","artist":"","title":"","art":""}'
|
||||
|
||||
PID=$([ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0)
|
||||
RADIO_ID=$([ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0)
|
||||
RADIO_URL=""
|
||||
INFO='{"id":null,"artist":null,"song":null,"image600":null}'
|
||||
PAUSED=$(( $PID == 0 || $RADIO_ID == 0 ? 1 : 0 ))
|
||||
PAUSED=$(( PID == 0 ? 1 : 0 ))
|
||||
INFO="$DEFAULT_INFO"
|
||||
MEDIA="$DEFAULT_MEDIA"
|
||||
STATUS="{}"
|
||||
|
||||
get_radio() {
|
||||
echo "$STATIONS" | jq -r --argjson sel_id "$RADIO_ID" 'map(select(.id == $sel_id)).[0]'
|
||||
get_stations() {
|
||||
local rr
|
||||
rr=$(curl -s --compressed "$URL_BASE/stations/" 2>/dev/null \
|
||||
| jq --argjson ids "$STATION_IDS" \
|
||||
'.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white, "radiorecord": true})' 2>/dev/null)
|
||||
jq -n \
|
||||
--argjson rr "${rr:-[]}" \
|
||||
--argjson custom "$CUSTOM_STATIONS" \
|
||||
'$rr + ($custom | map(. + {"radiorecord": false}))'
|
||||
}
|
||||
|
||||
get_song() {
|
||||
echo $(curl -s "$URL_BASE/station/history/?id=$RADIO_ID" | jq '.result.history[0] | ({id, artist, song, image600})')
|
||||
curl -s --compressed "$URL_BASE/station/history/?id=$RADIO_ID" \
|
||||
| jq '.result.history[0] | {artist, song, image600}'
|
||||
}
|
||||
|
||||
get_stream_url() {
|
||||
echo "$STATIONS" | jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].stream_hls // empty'
|
||||
}
|
||||
|
||||
update() {
|
||||
get_player_info() {
|
||||
local player status artist title art
|
||||
# exclude mpv (radio) so it never appears as "external player"
|
||||
player=$(playerctl -l 2>/dev/null | grep -Ev '^mpv' | head -1)
|
||||
if [ -z "$player" ]; then
|
||||
echo '{"player":"","status":"Stopped","artist":"","title":"","art":""}'
|
||||
return
|
||||
fi
|
||||
status=$(playerctl -p "$player" status 2>/dev/null || echo "Stopped")
|
||||
artist=$(playerctl -p "$player" metadata artist 2>/dev/null || echo "")
|
||||
title=$(playerctl -p "$player" metadata title 2>/dev/null || echo "")
|
||||
art=$(playerctl -p "$player" metadata mpris:artUrl 2>/dev/null || echo "")
|
||||
jq -cnr --arg player "$player" --arg status "$status" \
|
||||
--arg artist "$artist" --arg title "$title" --arg art "$art" \
|
||||
'{player:$player, status:$status, artist:$artist, title:$title, art:$art}'
|
||||
}
|
||||
|
||||
update_state() {
|
||||
PID=$([ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0)
|
||||
RADIO_ID=$([ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0)
|
||||
PAUSED=$(( $PID == 0 && $RADIO_ID > 0 ? 1 : 0 ))
|
||||
}
|
||||
|
||||
start() {
|
||||
STATIONS=$(curl -s "$URL_BASE/stations/" | jq --argjson ids '[507,522,523,536,537,42532,42602]' '.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white})')
|
||||
RADIO_URL=$(get_radio | jq -r '.stream_hls')
|
||||
if [ "$PAUSED" = 0 ]; then
|
||||
kill -9 $PID
|
||||
if [ "$PID" -gt 0 ] && ! kill -0 "$PID" 2>/dev/null; then
|
||||
PID=0
|
||||
rm -f "$MPV_PID_FILE"
|
||||
fi
|
||||
mpv "$RADIO_URL" & echo $! > "$MPV_PID_FILE"
|
||||
echo $RADIO_ID > "$RADIO_ID_FILE"
|
||||
PAUSED=$(( PID == 0 ? 1 : 0 ))
|
||||
}
|
||||
|
||||
emit_status() {
|
||||
jq -cnr \
|
||||
--argjson stations "${STATIONS:-[]}" \
|
||||
--argjson radio_id "${RADIO_ID:-0}" \
|
||||
--argjson is_paused "${PAUSED:-1}" \
|
||||
--argjson info "${INFO:-$DEFAULT_INFO}" \
|
||||
--argjson media "${MEDIA:-$DEFAULT_MEDIA}" \
|
||||
'{"is_paused": $is_paused, "song": $info, "radio": $radio_id, "stations": $stations, "media": $media}'
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
echo $RADIO_ID $PID
|
||||
start
|
||||
get_mpv_node() {
|
||||
wpctl status 2>/dev/null | awk '
|
||||
/Streams:/ { in_s = 1 }
|
||||
/Sinks:|Sources:|Clients:/ { in_s = 0 }
|
||||
in_s && /[0-9]+\..*mpv/ { match($0, /[0-9]+/); print substr($0, RSTART, RLENGTH); exit }
|
||||
'
|
||||
}
|
||||
|
||||
get_volume() {
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
[ -n "$node_id" ] && wpctl get-volume "$node_id" 2>/dev/null \
|
||||
| awk '{printf "%d", $2 * 100}'
|
||||
else
|
||||
kill -9 "$PID"
|
||||
rm -f $MPV_PID_FILE
|
||||
local player; player=$(playerctl -l 2>/dev/null | grep -Ev '^mpv' | head -1)
|
||||
[ -n "$player" ] && playerctl -p "$player" volume 2>/dev/null \
|
||||
| awk '{printf "%d", $1 * 100}'
|
||||
fi
|
||||
}
|
||||
|
||||
status() {
|
||||
echo $(jq -cnr --argjson pid "$PID" --argjson stations "$STATIONS" --argjson radio_id "$RADIO_ID" --argjson is_paused "$PAUSED" --argjson info "$INFO" '{"is_paused": $is_paused, "song": $info, "radio": $radio_id, "stations": $stations}')
|
||||
do_vol() {
|
||||
local vol="${1%.*}"
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
[ -n "$node_id" ] && wpctl set-volume "$node_id" "${vol}%"
|
||||
else
|
||||
playerctl volume "$(awk -v v="$vol" 'BEGIN{printf "%.2f", v/100}')" 2>/dev/null
|
||||
fi
|
||||
eww update radio-vol="$vol"
|
||||
}
|
||||
|
||||
do_mute() {
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
if [ -n "$node_id" ]; then
|
||||
wpctl set-mute "$node_id" toggle
|
||||
if wpctl get-volume "$node_id" 2>/dev/null | grep -q MUTED; then
|
||||
eww update radio-muted=true
|
||||
else
|
||||
eww update radio-muted=false
|
||||
fi
|
||||
fi
|
||||
else
|
||||
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
if wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null | grep -q MUTED; then
|
||||
eww update radio-muted=true
|
||||
else
|
||||
eww update radio-muted=false
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
do_start() {
|
||||
[ "$RADIO_ID" -le 0 ] && return
|
||||
STATIONS=$(get_stations)
|
||||
RADIO_URL=$(get_stream_url)
|
||||
[ -z "$RADIO_URL" ] || [ "$RADIO_URL" = "null" ] && return
|
||||
[ "$PID" -gt 0 ] && kill "$PID" 2>/dev/null
|
||||
nohup mpv --no-video --quiet "$RADIO_URL" >/dev/null 2>&1 &
|
||||
echo $! > "$MPV_PID_FILE"
|
||||
echo "$RADIO_ID" > "$RADIO_ID_FILE"
|
||||
}
|
||||
|
||||
status_loop() {
|
||||
STATUS=$(status)
|
||||
echo $STATUS
|
||||
STATIONS=$(curl -s "$URL_BASE/stations/" | jq --argjson ids '[507,522,523,536,537,42532,42602]' '.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white})')
|
||||
last_time_info=0
|
||||
last_time=0
|
||||
STATIONS=$(get_stations)
|
||||
echo "$(emit_status)"
|
||||
|
||||
last_pid_check=0
|
||||
last_song_fetch=0
|
||||
last_media_fetch=0
|
||||
|
||||
while true; do
|
||||
current_time=$(get_time_ms)
|
||||
delta=$((current_time - last_time))
|
||||
delta_i=$((current_time - last_time_info))
|
||||
if [[ $delta -gt 1000 ]]; then
|
||||
PID=$( [ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0 )
|
||||
RADIO_ID=$( [ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0 )
|
||||
PAUSED=$(( $PID == 0 && $RADIO_ID > 0 ? 1 : 0 ))
|
||||
NEW_STATUS=$(status)
|
||||
if [[ "$NEW_STATUS" != "$STATUS" ]]; then
|
||||
STATUS=$NEW_STATUS
|
||||
echo $STATUS
|
||||
now=$(date -u +%s%3N)
|
||||
|
||||
if (( now - last_pid_check > 1000 )); then
|
||||
update_state
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
last_pid_check=$now
|
||||
fi
|
||||
last_time=$current_time
|
||||
fi
|
||||
if [[ $delta_i -gt 15000 ]]; then
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
INFO="{\"id\":null,\"artist\":null,\"song\":null,\"image600\": \"$(get_radio | jq -r '.icon_fill_white')\"}"
|
||||
|
||||
if (( now - last_song_fetch > 15000 )); then
|
||||
if [ "$PAUSED" = 0 ]; then
|
||||
IS_RR=$(echo "$STATIONS" | jq --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].radiorecord // true')
|
||||
if [ "$IS_RR" = "true" ]; then
|
||||
FETCHED=$(get_song)
|
||||
INFO=$(echo "$INFO" "$FETCHED" | jq -s '
|
||||
reduce .[] as $x ({}; . + ($x | with_entries(select(.value != null))))')
|
||||
else
|
||||
INFO=$(echo "$INFO" "$(get_song)" | jq -s ' reduce .[] as $item ( {}; . + (
|
||||
reduce ($item | to_entries[]) as $entry ( {}; if $entry.value != null then .[$entry.key] = $entry.value else . end
|
||||
)) )')
|
||||
STATION_TITLE=$(echo "$STATIONS" | jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].title // ""')
|
||||
INFO=$(jq -cnr --arg title "$STATION_TITLE" '{artist:"",song:$title,image600:""}')
|
||||
fi
|
||||
last_time_info=$current_time
|
||||
else
|
||||
STATION_IMG=$(echo "$STATIONS" \
|
||||
| jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].icon_fill_white // ""')
|
||||
STATION_TITLE=$(echo "$STATIONS" \
|
||||
| jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].title // ""')
|
||||
INFO=$(jq -cnr --arg img "$STATION_IMG" --arg title "$STATION_TITLE" \
|
||||
'{artist:"",song:$title,image600:$img}')
|
||||
fi
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
last_song_fetch=$now
|
||||
fi
|
||||
|
||||
if (( now - last_media_fetch > 3000 )); then
|
||||
MEDIA=$(get_player_info)
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
VOL=$(get_volume)
|
||||
[ -n "$VOL" ] && eww update radio-vol="$VOL" 2>/dev/null
|
||||
last_media_fetch=$now
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
done
|
||||
}
|
||||
|
||||
# Main script
|
||||
case "$1" in
|
||||
"start")
|
||||
RADIO_ID=$2
|
||||
start
|
||||
start)
|
||||
RADIO_ID="$2"
|
||||
echo "$RADIO_ID" > "$RADIO_ID_FILE"
|
||||
do_start
|
||||
;;
|
||||
"toggle")
|
||||
toggle
|
||||
vol)
|
||||
do_vol "$2"
|
||||
;;
|
||||
mute)
|
||||
update_state
|
||||
do_mute
|
||||
;;
|
||||
toggle)
|
||||
update_state
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
[ "$RADIO_ID" -gt 0 ] && do_start
|
||||
else
|
||||
[ "$PID" -gt 0 ] && kill "$PID" 2>/dev/null
|
||||
rm -f "$MPV_PID_FILE"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
status_loop
|
||||
|
||||
@@ -82,23 +82,15 @@
|
||||
(defwidget quick-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Quick Actions" :accent "quick-accent")
|
||||
(box :orientation "h" :homogeneous true :class "quick-grid"
|
||||
(quick-btn
|
||||
:icon "" :label "Wallpaper"
|
||||
:onclick "scripts/wallpaper"
|
||||
:active false)
|
||||
(quick-btn
|
||||
:icon "" :label "Power Save"
|
||||
:onclick "eww update power-save=$(scripts/power-save)"
|
||||
:active {power-save})
|
||||
(quick-btn
|
||||
:icon "" :label "Night Light"
|
||||
:onclick "eww update night-light=$(scripts/nightlight)"
|
||||
:active {night-light})
|
||||
(quick-btn
|
||||
:icon "" :label "Screenshot"
|
||||
:onclick "scripts/screenshot"
|
||||
:active false))))
|
||||
(box :orientation "v" :space-evenly false :class "quick-grid" :spacing 4
|
||||
(box :orientation "h" :space-evenly true
|
||||
(quick-btn :icon "" :label "Wallpaper" :onclick "scripts/wallpaper" :active false)
|
||||
(quick-btn :icon "" :label "Power Save" :onclick "eww update power-save=$(scripts/power-save)" :active {power-save})
|
||||
(quick-btn :icon "" :label "Night Light" :onclick "eww update night-light=$(scripts/nightlight)" :active {night-light}))
|
||||
(box :orientation "h" :space-evenly true
|
||||
(quick-btn :icon "" :label "Screenshot" :onclick "scripts/screenshot" :active false)
|
||||
(quick-btn :icon "" :label "Lock" :onclick "swaylock" :active false)
|
||||
(quick-btn :icon "" :label "Color Pick" :onclick "hyprpicker -a" :active false)))))
|
||||
|
||||
; --- Brightness ---
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
(revealer :reveal {active-panel == "net"} :transition "slidedown" :duration 120
|
||||
(net-win))
|
||||
(revealer :reveal {active-panel == "clock"} :transition "slidedown" :duration 120
|
||||
(clock-win))))
|
||||
(clock-win))
|
||||
(revealer :reveal {active-panel == "radio"} :transition "slidedown" :duration 120
|
||||
(radio-win))))
|
||||
|
||||
(defwindow popup
|
||||
:monitor 0
|
||||
|
||||
@@ -1,111 +1,82 @@
|
||||
(deflisten radio :initial '{"is_paused":1,"song":{"artist":"","song":"","image600":"https://www.radiorecord.ru/upload/stations_images/record_image600_white_fill.png"},"stations":[]}' "scripts/radio")
|
||||
(defvar radio_rev false)
|
||||
|
||||
(defwindow radio
|
||||
:monitor 0
|
||||
:geometry (geometry
|
||||
:x "0%"
|
||||
:y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "0px"
|
||||
:height "0px")
|
||||
(window (radio-win)))
|
||||
|
||||
(deflisten radio
|
||||
:initial '{"is_paused":1,"song":{"artist":"","song":"","image600":""},"radio":0,"stations":[],"media":{"player":"","status":"Stopped","artist":"","title":"","art":""}}'
|
||||
"scripts/radio")
|
||||
(defvar radio-vol 80)
|
||||
(defvar radio-muted false)
|
||||
|
||||
(defwidget radio-win []
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "h"
|
||||
(revealer
|
||||
:visible radio_rev
|
||||
:reveal radio_rev
|
||||
:transition "slideleft"
|
||||
(radio-selector))
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
(box :class "sys-win" :orientation "v" :space-evenly false
|
||||
|
||||
(box
|
||||
:class "album_art"
|
||||
:style "background-size:cover; background-image: url('${radio.song.image600?:'https://www.radiorecord.ru/upload/stations_images/record_image600_white_fill.png'}');")
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
(label
|
||||
:halign "center"
|
||||
:class "song"
|
||||
:wrap "true"
|
||||
:limit-width 18
|
||||
:text "${radio.song.song?:'...'}")
|
||||
(label
|
||||
:halign "center"
|
||||
:class "artist"
|
||||
:wrap "true"
|
||||
:limit-width 22
|
||||
:text "${radio.song.artist?:'...'}")
|
||||
(box
|
||||
:space-evenly true
|
||||
:orientation "h"
|
||||
:halign "center"
|
||||
:class "btn_bar"
|
||||
; --- Now Playing ---
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Media" :accent "radio-accent")
|
||||
(box :orientation "h" :space-evenly false :valign "center" :spacing 10 :class "radio-now-playing"
|
||||
(box :class "radio-art"
|
||||
:style "background-image: url('${radio.is_paused == 0 ? radio.song.image600 : (radio.media.status != 'Stopped' ? radio.media.art : radio.song.image600)}'); background-size: cover; background-position: center;"
|
||||
(label :class "radio-art-icon" :halign "center" :valign "center"
|
||||
:visible {radio.is_paused == 0
|
||||
? radio.song.image600 == ""
|
||||
: (radio.media.status != "Stopped"
|
||||
? radio.media.art == ""
|
||||
: radio.song.image600 == "")}
|
||||
:text ""))
|
||||
(box :orientation "v" :space-evenly false :hexpand true :valign "center"
|
||||
(label :class "radio-song" :halign "start" :wrap true :limit-width 20
|
||||
:text {radio.is_paused == 0
|
||||
? (radio.song.song != "" ? radio.song.song : "Tuning in...")
|
||||
: (radio.media.status != "Stopped"
|
||||
? (radio.media.title != "" ? radio.media.title : "Playing")
|
||||
: (radio.song.song != "" ? radio.song.song : "Nothing playing"))})
|
||||
(label :class "radio-artist" :halign "start" :wrap true :limit-width 22
|
||||
:text {radio.is_paused == 0
|
||||
? radio.song.artist
|
||||
: (radio.media.status != "Stopped"
|
||||
? (radio.media.artist != "" ? radio.media.artist : radio.media.player)
|
||||
: "")})))
|
||||
|
||||
(button
|
||||
:class "btn_left"
|
||||
:onclick "${EWW_CMD} update radio_rev=${!radio_rev}"
|
||||
(box ""))
|
||||
; Controls - hidden only in placeholder state
|
||||
(box :visible {radio.is_paused == 0 || radio.radio > 0 || radio.media.status != "Stopped"}
|
||||
:orientation "v" :space-evenly false :class "radio-controls"
|
||||
(box :orientation "h" :space-evenly true :halign "center"
|
||||
(button :visible {radio.is_paused == 1 && radio.media.status != "Stopped"}
|
||||
:class "radio-ctrl-btn" :timeout "2s" :onclick "playerctl previous"
|
||||
(label :text ""))
|
||||
(button :class "radio-ctrl-btn" :timeout "2s"
|
||||
:onclick {radio.is_paused == 1 && radio.media.status != "Stopped" ? "playerctl play-pause" : "scripts/radio toggle"}
|
||||
(label :text {radio.is_paused == 0 ? "" : (radio.media.status == "Playing" ? "" : "")}))
|
||||
(button :visible {radio.is_paused == 1 && radio.media.status != "Stopped"}
|
||||
:class "radio-ctrl-btn" :timeout "2s" :onclick "playerctl next"
|
||||
(label :text "")))
|
||||
(vol-row
|
||||
:icon ""
|
||||
:value {radio-vol}
|
||||
:onchange "scripts/radio vol {}"
|
||||
:onclick "scripts/radio mute"
|
||||
:muted {radio-muted})))
|
||||
|
||||
(button
|
||||
:class "btn_play"
|
||||
:timeout "2s"
|
||||
:onclick "scripts/radio toggle"
|
||||
"${radio.is_paused==1 ? "" : ""}")
|
||||
|
||||
(button
|
||||
:class "btn_right"
|
||||
:onclick ""
|
||||
(box :visible false ""))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(defwidget radio-selector []
|
||||
(scroll
|
||||
:active true
|
||||
:vscroll true
|
||||
:hscroll false
|
||||
|
||||
(box
|
||||
:class "station_list"
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
(box :class "section-sep")
|
||||
|
||||
; --- Stations ---
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Radio Stations" :accent "radio-accent")
|
||||
(scroll :vscroll true :hscroll false :height 130
|
||||
(box :class "station-list" :space-evenly false :orientation "v"
|
||||
(for station in {radio.stations}
|
||||
(button
|
||||
:class "station_art ${(radio.radio == station.id)?'station_sel':''}"
|
||||
:class "station-row ${radio.radio == station.id ? 'station-row-active' : ''}"
|
||||
:timeout "2s"
|
||||
:onclick "scripts/radio start ${station.id}"
|
||||
:tooltip "${station.title}"
|
||||
:style "background-size:cover; background-image: url('${station.icon_fill_white}');"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
:tooltip {station.title}
|
||||
(box :orientation "h" :space-evenly false :valign "center"
|
||||
(box :class "station-icon"
|
||||
:style "background-image: url('${station.icon_fill_white}'); background-size: contain; background-position: center;")
|
||||
(label :class "station-name" :text {station.title}
|
||||
:hexpand true :halign "start" :limit-width 16)))))))))
|
||||
|
||||
(defwidget radio-mod []
|
||||
(module
|
||||
(box
|
||||
:orientation "v"
|
||||
(button
|
||||
:onclick "(sleep 0.1 && eww-open-on-current-screen radio --toggle --no-daemonize)"
|
||||
(label
|
||||
:show-truncated false
|
||||
:class "icon-text"
|
||||
:text "")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(eventbox
|
||||
:onclick "(sleep 0.1 && scripts/panel-toggle radio)"
|
||||
(box :orientation "v"
|
||||
(label :show-truncated false :class "icon-text" :text "")))))
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "GPU" :accent "gpu-accent")
|
||||
(box :orientation "h" :space-evenly true
|
||||
; GFX — outer: activity%, inner: clock% of range
|
||||
; GFX - outer: activity%, inner: clock% of range
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
@@ -84,7 +84,7 @@
|
||||
(box :halign "center" :valign "center"
|
||||
(label :class "gpu-ring-value" :text "${round(gpu.gfx_pct, 0)}%")))
|
||||
(label :class "gpu-ring-label" :text "GFX" :halign "center"))
|
||||
; Memory — outer: activity%, inner: memory clock% of range
|
||||
; Memory - outer: activity%, inner: memory clock% of range
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
@@ -99,7 +99,7 @@
|
||||
(box :halign "center" :valign "center"
|
||||
(label :class "gpu-ring-value" :text "${round(gpu.mem_pct, 0)}%")))
|
||||
(label :class "gpu-ring-label" :text "Mem" :halign "center"))
|
||||
; Media — outer: activity%, inner: video clock% of GPU clock max
|
||||
; Media - outer: activity%, inner: video clock% of GPU clock max
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
|
||||
@@ -59,6 +59,8 @@ in {
|
||||
|
||||
$gaps-screen: ${config.colorScheme.palette.gaps-screen}px;
|
||||
$gaps-window: ${config.colorScheme.palette.gaps-window}px;
|
||||
|
||||
$panel-font-size: 10pt;
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ in {
|
||||
|
||||
brightnessctl
|
||||
awww
|
||||
playerctl
|
||||
];
|
||||
|
||||
xdg.mimeApps = {
|
||||
|
||||
Reference in New Issue
Block a user