-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpiradio
executable file
·248 lines (227 loc) · 6.47 KB
/
piradio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#!/usr/bin/env bash
#######################################################################
# Made by : E. Dronkert
# Licence : GNU GPL v3
# Platform : Raspberry Pi
# Requires : bash, mpd, mpc, at
# : User pi in group audio
# : mpd executed as group audio, see /etc/mpd.conf
# : No-pwd access to at and shutdown for user www-data:
# add with 'sudo visudo' (this is probably a giant security hole)
# www-data ALL=(ALL) NOPASSWD: /usr/bin/at, /sbin/shutdown
# Location : /usr/local/bin/
# Name : piradio
# Version : 1.3.2
# Date : 2021-09-06
# Purpose : Play radio streams via local mpd audio server
# Use station abbreviations from user file radio.txt
# Shutdown (auto-off) after 3 hours using 'at'
# Parameters : <none> | <station> | list |
# vol [ + | = | - | min | max | def | 0..100 ] |
# on | off | help
# Exit 0 : success
# 1 : help displayed
# 2 : radio.txt local user file not found
# 3 : station abbreviation not recognised
# 4 : mpc or 'at' executables not found
#######################################################################
# Variables
PLAYER=/usr/bin/mpc
ATBIN=/usr/bin/at
ATCMD="$PLAYER stop"
PIHOME=$(cat /etc/passwd | grep -e '^pi:' | cut -d':' -f6)
DBFILE=$PIHOME/radio.txt
DEFVOL=25
ADJVOL=5
# Error codes
declare -i ERR_OK=0
declare -i ERR_HELP=1
declare -i ERR_DBNOTFOUND=2
declare -i ERR_IDNOTFOUND=3
declare -i ERR_APPNOTFOUND=4
# Copy/redirect output to stderr
function StdErr () {
cat - 1>&2
}
if [ ! -x "$PLAYER" ]; then
echo | StdErr
echo " Radio player not found: $PLAYER" | StdErr
echo | StdErr
exit $ERR_APPNOTFOUND
fi
if [ ! -x "$ATBIN" ]; then
echo | StdErr
echo " Scheduler for snooze not found: $ATBIN" | StdErr
echo | StdErr
exit $ERR_APPNOTFOUND
fi
# "at" with sudo to catch scheduled times across all users
# Requires visudo: add /usr/bin/at for user www-data
function SnoozeClear () {
for i in $(sudo $ATBIN -l | grep -oP '^\d+' | sort | xargs); do
j=$(sudo $ATBIN -c $i | tail -n 1)
if [[ "$j" == "$ATCMD" ]]; then
sudo $ATBIN -r $i &> /dev/null
fi
done
}
function SnoozeReset () {
SnoozeClear
echo -n "$ATCMD" | sudo $ATBIN -M now + 3 hours &> /dev/null
}
# Return earliest snooze time via standard out
function SnoozeFind () {
for i in $(sudo $ATBIN -l | grep -oP '^\d+' | sort | xargs); do
j=$(sudo $ATBIN -c $i | tail -n 1)
if [[ "$j" == "$ATCMD" ]]; then
sudo $ATBIN -l | grep -P "^$i\t" | grep -oP '\d\d:\d\d'
fi
done
}
# Returns volume as a percentage 0-100 via standard out
function GetVolume () {
$PLAYER volume | grep -oE '[0-9]+'
}
# Required argument: volume as a percentage 0-100
function SetVolume () {
VOL="${1//[^0-9]/}"
LEN=${#VOL}
if (( LEN >= 1 && LEN <= 3 && VOL >= 0 && VOL <= 100 )); then
$PLAYER -q volume $VOL
fi
}
# Help
if [[ "$1" == "help" || "$1" == "--help" || "$1" == "/help" || \
"$1" == "-h" || "$1" == "/h" || \
"$1" == "?" || "$1" == "-?" || "$1" == "/?" ]]; then
echo | StdErr
echo " Usage:" | StdErr
echo " - Which station is on? : piradio" | StdErr
echo " - Tune to a station : piradio <station-id>" | StdErr
echo " - List all stations : piradio list" | StdErr
echo " - Show or adjust volume : piradio vol [ + | = | - | min | max | def | 0..100 ]" | StdErr
echo " - Mute or unmute : piradio mute" | StdErr
echo " - Turn radio on or off : piradio on | off" | StdErr
echo | StdErr
exit $ERR_HELP
fi
# Display current station/stream/volume if no argument
if [ -z "$1" ]; then
curvolume=$(GetVolume)
curstream=$($PLAYER -f "%file%" current)
if [ -z "$curstream" ]; then
curstation="(no stream found)"
else
if [ -f $DBFILE ]; then
curstation=$(cat $DBFILE \
| grep --colour=never -m 1 -F "$curstream" \
| grep --colour=never -oP '^\S+')
if [ -z "$curstation" ]; then
curstation="(station not found)"
fi
else
curstation="(station database not found at \"$DBFILE\")"
fi
fi
snooze=$(SnoozeFind)
echo
[ -z "$curstation" ] || echo " Station : $curstation"
[ -z "$curstream" ] || echo " Stream : $curstream"
[ -z "$curvolume" ] || echo " Volume : $curvolume"
[ -z "$snooze" ] || echo " Snooze : $snooze"
echo
exit $ERR_OK
fi
# List station IDs from station database
if [[ "$1" == "list" ]]; then
if [ -f $DBFILE ]; then
echo
echo " List of all stations:"
cat $DBFILE | grep --color=never -oP "^\S+" | sort | sed s/^/\\t/
echo
exit $ERR_OK
else
echo | StdErr
echo " Station database not found at \"$DBFILE\"" | StdErr
echo | StdErr
exit $ERR_DBNOTFOUND
fi
fi
# Turn radio on
if [[ "$1" == "on" || "$1" == "play" ]]; then
# TODO: check if a radio stream is lined up
$PLAYER play > /dev/null
SnoozeReset
exit $ERR_OK
fi
# Turn radio off
if [[ "$1" == "off" || "$1" == "stop" ]]; then
$PLAYER stop > /dev/null
SnoozeClear
exit $ERR_OK
fi
# Display volume, optionally set or adjust or mute/unmute
if [[ "$1" == "vol" || "$1" == "mute" ]]; then
declare -i curvol=$(GetVolume)
declare -i newvol=$curvol
declare -i minvol=$ADJVOL
declare -i maxvol=100
if [[ "$1" == "mute" || "$2" == "mute" ]]; then
if (( curvol > minvol )); then
# mute
newvol=$minvol
else
# unmute
newvol=$DEFVOL
fi
else
if [ -n "$2" ]; then
case "$2" in
min) newvol=$minvol;;
max) newvol=$maxvol;;
def) newvol=$DEFVOL;;
+) (( newvol = curvol + ADJVOL ));;
=) (( newvol = curvol + ADJVOL ));;
-) (( newvol = curvol - ADJVOL ));;
*) newvol="$2";;
esac
if (( newvol >= maxvol )); then
newvol=$maxvol
elif (( newvol <= minvol )); then
newvol=$minvol
fi
fi
fi
if (( newvol != curvol )); then
# volume adjustment
SetVolume $newvol
curvol=$newvol
fi
echo
echo " Volume: $curvol"
echo
exit $ERR_OK
fi
# Argument is a Station ID
# Escape argument for use with grep -P
# Is it really safe? Not sure. Couldn't make escaping ] work, for instance.
safe=$(echo "$1" \
| sed -e 's/\s*//g' \
| sed -e 's/[\[\\^$.*?"-]/\\\0/g')
[ -f $DBFILE ] && stream=$(cat $DBFILE \
| grep --color=never -m 1 -P "^$safe\s" \
| grep --color=never -oP '\S+$')
if [ -z "$stream" ]; then
echo | StdErr
echo " Station \"$1\" not found." | StdErr
echo " List stations : piradio list" | StdErr
echo " Usage info : piradio help" | StdErr
echo | StdErr
exit $ERR_IDNOTFOUND
fi
$PLAYER stop > /dev/null
$PLAYER clear > /dev/null
$PLAYER add $stream > /dev/null
$PLAYER play > /dev/null
SnoozeReset
exit $ERR_OK