diff options
-rw-r--r-- | COPYING | 7 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rwxr-xr-x | radio | 116 |
3 files changed, 148 insertions, 0 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..4d13a5b --- /dev/null +++ b/COPYING | |||
@@ -0,0 +1,7 @@ | |||
1 | Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
2 | |||
3 | Usage of the works is permitted provided that this instrument is retained with | ||
4 | the works, so that any entity that uses the works is notified of this | ||
5 | instrument. | ||
6 | |||
7 | DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. | ||
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..66e6c52 --- /dev/null +++ b/Makefile | |||
@@ -0,0 +1,25 @@ | |||
1 | # Radio | ||
2 | |||
3 | DESTDIR = | ||
4 | PREFIX = /usr/local | ||
5 | |||
6 | .PHONY: help | ||
7 | help: | ||
8 | @echo "radio : Play online radio" | ||
9 | @echo "(C) 2022 Case Duckworth <acdw@acdw.net>" | ||
10 | @echo "Licensed under the Fair License; see COPYING for details." | ||
11 | @echo | ||
12 | @echo "TARGETS:" | ||
13 | @echo " install Install radio to $(DESTDIR)$(PREFIX)/radio." | ||
14 | @echo " An example configuration is at $(DESTDIR)$(PREFIX)/share/radio/stations." | ||
15 | @echo " uninstall Uninstall radio-related files." | ||
16 | |||
17 | .PHONY: install | ||
18 | install: radio radio.stations | ||
19 | install -D radio $(PREFIX)/bin/radio | ||
20 | install -D radio.stations $(PREFIX)/share/radio/stations | ||
21 | |||
22 | .PHONY: uninstall | ||
23 | uninstall: | ||
24 | rm $(PREFIX)/bin/radio | ||
25 | rm -r $(PREFIX)/share/radio/ | ||
diff --git a/radio b/radio new file mode 100755 index 0000000..dc1297a --- /dev/null +++ b/radio | |||
@@ -0,0 +1,116 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | # -*- sh -*- | ||
3 | |||
4 | : "${RADIO_STATIONS:=${XDG_CONFIG_HOME:-$HOME/.config}/radio/stations}" | ||
5 | : "${RADIO_PLAYER:=$(command -v mpv 2>/dev/null)}" | ||
6 | |||
7 | _radio_url=1 | ||
8 | _radio_desc=2 | ||
9 | _radio_tags=3 | ||
10 | |||
11 | RADIO_PID_FILE=/tmp/radio.pid | ||
12 | |||
13 | usage() { | ||
14 | cat <<EOF | ||
15 | RADIO: play the radio | ||
16 | USAGE: radio -h | ||
17 | radio -k | ||
18 | radio -l [QUERY] | ||
19 | radio [STATION] | ||
20 | |||
21 | PARAMETERS: | ||
22 | STATION Radio station to play. Stations are defined in | ||
23 | \$RADIO_STATIONS (default: $RADIO_STATIONS). | ||
24 | If STATION matches more than one station, or if it | ||
25 | isn't present, radio will display a menu to select | ||
26 | from. | ||
27 | |||
28 | FLAGS: | ||
29 | -h Show this help. | ||
30 | -k Kill the currently-playing radio invocation. | ||
31 | -e Edit \$RADIO_STATIONS using \$EDITOR. | ||
32 | -l [QUERY] List all known stations and exit. | ||
33 | If QUERY is present, filter the list to those stations | ||
34 | matching QUERY. | ||
35 | |||
36 | See radio(1) and radio.stations(5) for more details. (TODO) | ||
37 | EOF | ||
38 | exit ${1:-0} | ||
39 | } | ||
40 | |||
41 | _radio_play() { | ||
42 | candidates="$(sed -e 1d -e '/^#/d' "$RADIO_STATIONS" | grep -i "$1")" | ||
43 | if [ -z "$candidates" ]; then | ||
44 | candidates="$(sed -e 1d -e '/^#/d' "$RADIO_STATIONS")" | ||
45 | fi | ||
46 | if [ "$(printf '%s\n' "$candidates" | wc -l)" -gt 1 ]; then | ||
47 | printf '%s\n' "$candidates" | cut -f $_radio_desc | cat -n - | ||
48 | read -p "Radio> " radio | ||
49 | if ! (echo "$radio" | grep -qE '^[0-9]+$'); then | ||
50 | exit 1 | ||
51 | fi | ||
52 | station="$(printf '%s\n' "$candidates" | head -n "$radio" | tail -n 1)" | ||
53 | else | ||
54 | station="$candidates" | ||
55 | fi | ||
56 | echo >&2 "Playing $(echo "$station" | cut -f $_radio_desc)..." | ||
57 | "$RADIO_PLAYER" "$(echo "$station" | cut -f $_radio_url)" & | ||
58 | echo $! >"$RADIO_PID_FILE" | ||
59 | exit | ||
60 | } | ||
61 | |||
62 | _radio_kill() { | ||
63 | if ! xargs -a "$RADIO_PID_FILE" kill; then | ||
64 | echo >&2 "I don't think radio is running." | ||
65 | exit 1 | ||
66 | fi | ||
67 | exit | ||
68 | } | ||
69 | |||
70 | _radio_edit() { | ||
71 | exec $EDITOR "$RADIO_STATIONS" | ||
72 | } | ||
73 | |||
74 | _radio_list() { | ||
75 | sed 1d "$RADIO_STATIONS" | | ||
76 | grep "$1" | | ||
77 | awk ' | ||
78 | BEGIN { FS="\t"; } | ||
79 | $0 !~ /^#/ { | ||
80 | descstr = $'$_radio_desc'; | ||
81 | urlstr = $'$_radio_url'; | ||
82 | tagstr = $'$_radio_tags'; | ||
83 | printf "%-23s\t", substr(descstr,1,20) (length(descstr)>20?"...":""); | ||
84 | printf "%-23s\t", substr(tagstr,1,20) (length(tagstr)>20?"...":""); | ||
85 | printf "%-23s\n", substr(urlstr,1,20) (length(urlstr)>20?"...":""); | ||
86 | }' | ||
87 | exit | ||
88 | } | ||
89 | |||
90 | main() { | ||
91 | while getopts :khel: opt; do | ||
92 | case $opt in | ||
93 | h) usage ;; | ||
94 | k) _radio_kill ;; | ||
95 | e) _radio_edit ;; | ||
96 | l) _radio_list "$OPTARG" ;; | ||
97 | :) | ||
98 | case "$OPTARG" in | ||
99 | l) _radio_list ;; | ||
100 | *) | ||
101 | echo >&2 "Option -$OPTARG requires an argument" | ||
102 | exit 1 | ||
103 | ;; | ||
104 | esac | ||
105 | ;; | ||
106 | \?) | ||
107 | echo >&2 "Uknown option: -$OPTARG" | ||
108 | exit 1 | ||
109 | ;; | ||
110 | esac | ||
111 | done | ||
112 | shift $((OPTIND - 1)) | ||
113 | _radio_play "$@" | ||
114 | } | ||
115 | |||
116 | main "$@" | ||