Radio
This commit is contained in:
@@ -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"
|
||||
|
||||
STATIONS="[]"
|
||||
STATION_IDS='[507,522,523,536,537,42532,42602]'
|
||||
|
||||
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 ))
|
||||
# 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)
|
||||
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}'
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
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 ))
|
||||
get_stream_url() {
|
||||
echo "$STATIONS" | jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].stream_hls // empty'
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
mpv "$RADIO_URL" & echo $! > "$MPV_PID_FILE"
|
||||
echo $RADIO_ID > "$RADIO_ID_FILE"
|
||||
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)
|
||||
if [ "$PID" -gt 0 ] && ! kill -0 "$PID" 2>/dev/null; then
|
||||
PID=0
|
||||
rm -f "$MPV_PID_FILE"
|
||||
fi
|
||||
PAUSED=$(( PID == 0 ? 1 : 0 ))
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
echo $RADIO_ID $PID
|
||||
start
|
||||
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}'
|
||||
}
|
||||
|
||||
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
|
||||
fi
|
||||
last_time=$current_time
|
||||
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
|
||||
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
|
||||
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
|
||||
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_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
|
||||
last_time_info=$current_time
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user