diff options
-rw-r--r-- | lib.fnl | 24 | ||||
-rwxr-xr-x | radish | 33 | ||||
-rw-r--r-- | radish.fnl | 47 | ||||
-rw-r--r-- | src/lib.fnl | 44 | ||||
-rw-r--r-- | src/main.fnl | 51 | ||||
-rw-r--r-- | src/mpv.fnl | 4 | ||||
-rw-r--r-- | src/pls.fnl | 51 | ||||
-rw-r--r-- | src/test.pls | 18 | ||||
-rw-r--r-- | src/util.fnl (renamed from pls.fnl) | 9 | ||||
-rw-r--r-- | util.fnl | 13 |
10 files changed, 199 insertions, 95 deletions
diff --git a/lib.fnl b/lib.fnl deleted file mode 100644 index a08fcc8..0000000 --- a/lib.fnl +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | ;;; LIB.fnl | ||
2 | ;; Radish library | ||
3 | |||
4 | (local util (require :util)) | ||
5 | |||
6 | (local radish {}) | ||
7 | |||
8 | (lambda radish.play [?station] | ||
9 | (print "play")) | ||
10 | |||
11 | (lambda radish.kill [] | ||
12 | (print "kill")) | ||
13 | |||
14 | (lambda radish.add [?station] | ||
15 | (print "add")) | ||
16 | |||
17 | (lambda radish.del [?station] | ||
18 | (print "del")) | ||
19 | |||
20 | (lambda radish.edit [?station] | ||
21 | (print "edit")) | ||
22 | |||
23 | radish | ||
24 | |||
diff --git a/radish b/radish index 3cc4eb7..a5d5d07 100755 --- a/radish +++ b/radish | |||
@@ -6,7 +6,7 @@ | |||
6 | usage() { | 6 | usage() { |
7 | cat <<EOF | 7 | cat <<EOF |
8 | RADISH: radio, music, static | 8 | RADISH: radio, music, static |
9 | USAGE: radish [-h|-k|-r|-s|-S] | 9 | USAGE: radish [-h|-k|-r|-s|-S|-i] |
10 | radish -l [NAME] | 10 | radish -l [NAME] |
11 | radish [STATION] | 11 | radish [STATION] |
12 | 12 | ||
@@ -16,6 +16,7 @@ FLAGS: | |||
16 | -S Show radish's status indefinitely. | 16 | -S Show radish's status indefinitely. |
17 | -k Kill the currently-playing radish invocation. | 17 | -k Kill the currently-playing radish invocation. |
18 | -r Replay most recently-played station. | 18 | -r Replay most recently-played station. |
19 | -i Show information about currently-playing station. | ||
19 | 20 | ||
20 | OPTIONS: | 21 | OPTIONS: |
21 | -l [NAME] List available stations. | 22 | -l [NAME] List available stations. |
@@ -40,7 +41,7 @@ config() { | |||
40 | 41 | ||
41 | main() { | 42 | main() { |
42 | config | 43 | config |
43 | while getopts :hkrsSl: opt; do | 44 | while getopts :hkrsSl:L:i opt; do |
44 | case "$opt" in | 45 | case "$opt" in |
45 | h) usage ;; | 46 | h) usage ;; |
46 | k) radish_kill ;; | 47 | k) radish_kill ;; |
@@ -48,9 +49,12 @@ main() { | |||
48 | s) radish_status ;; | 49 | s) radish_status ;; |
49 | S) radish_status -follow ;; | 50 | S) radish_status -follow ;; |
50 | l) radish_list "$OPTARG" ;; | 51 | l) radish_list "$OPTARG" ;; |
52 | L) radish_list -r "$OPTARG" ;; | ||
53 | i) radish_info ;; | ||
51 | :) | 54 | :) |
52 | case "$OPTARG" in | 55 | case "$OPTARG" in |
53 | l) radish_list ;; | 56 | l) radish_list ;; |
57 | L) radish_list -r ;; | ||
54 | *) | 58 | *) |
55 | echo >&2 "Option -$OPTARG requires an argument" | 59 | echo >&2 "Option -$OPTARG requires an argument" |
56 | usage 1 | 60 | usage 1 |
@@ -127,6 +131,12 @@ echo() { printf '%s\n' "$*"; } | |||
127 | 131 | ||
128 | ### Main functionality | 132 | ### Main functionality |
129 | 133 | ||
134 | radish_info() { | ||
135 | url="$(cat "$RADISH_LP_FILE")" | ||
136 | grep "$url" "$RADISH_STATION_FILE" | ||
137 | exit | ||
138 | } | ||
139 | |||
130 | radish_kill() { | 140 | radish_kill() { |
131 | if [ -f "$RADISH_PID_FILE" ]; then | 141 | if [ -f "$RADISH_PID_FILE" ]; then |
132 | printf >&2 '%s' "Killing radish..." | 142 | printf >&2 '%s' "Killing radish..." |
@@ -151,14 +161,25 @@ radish_status() { | |||
151 | } | 161 | } |
152 | 162 | ||
153 | radish_list() { | 163 | radish_list() { |
154 | _radish_stations | grep -i "${1:-}" | awk -F '\t' '{ | 164 | if [ "x$1" = x-r ]; then |
155 | desc = $'$_schema_desc' | 165 | raw=true |
156 | url = $'$_schema_url' | 166 | shift |
157 | tags = $'$_schema_tags' | 167 | else |
168 | raw=false | ||
169 | fi | ||
170 | _radish_stations | grep -i "${1:-}" | | ||
171 | if "$raw"; then | ||
172 | awk 'BEGIN{FS="\t";OFS="\t"}{print $2, $1, $3}' | ||
173 | else | ||
174 | awk -F '\t' '{ | ||
175 | desc = $2 | ||
176 | url = $1 | ||
177 | tags = $3 | ||
158 | printf "%-23s |", substr(desc,1,20) (length(desc)>20?"...":"") | 178 | printf "%-23s |", substr(desc,1,20) (length(desc)>20?"...":"") |
159 | printf "%-23s |", substr(tags,1,20) (length(tags)>20?"...":"") | 179 | printf "%-23s |", substr(tags,1,20) (length(tags)>20?"...":"") |
160 | printf "%-23s\n", substr(url,1,20) (length(url)>20?"...":"") | 180 | printf "%-23s\n", substr(url,1,20) (length(url)>20?"...":"") |
161 | }' | 181 | }' |
182 | fi | ||
162 | exit | 183 | exit |
163 | } | 184 | } |
164 | 185 | ||
diff --git a/radish.fnl b/radish.fnl deleted file mode 100644 index acba83f..0000000 --- a/radish.fnl +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | ;;; RADISH | ||
2 | ;; A tuner for various streams | ||
3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
4 | ;; License: Good Choices (https://acdw.casa/gcl) | ||
5 | |||
6 | (local util (require :util)) | ||
7 | (local pls (require :pls)) | ||
8 | (local radish (require :lib)) | ||
9 | |||
10 | (fn usage [] | ||
11 | (util.printlns "RADISH: a tuner for various streams" | ||
12 | "Copyright (C) 2022 Case Duckworth <acdw@acdw.net>" | ||
13 | "License: Good Choices (https://acdw.casa/gcl)" | ||
14 | "" | ||
15 | "Commands" | ||
16 | " radish [STATION]" | ||
17 | " Begin playing STATION. If STATION is not" | ||
18 | " provided, display a list of favorites and" | ||
19 | " allow the user to choose one to play." | ||
20 | " radish play [STATION]" | ||
21 | " Begin playing STATION. If STATION is not" | ||
22 | " provided, play the most recently-played." | ||
23 | " radish kill" | ||
24 | " Kill the currently-playing station." | ||
25 | " radish add [STATION]" | ||
26 | " Add STATION or the currently-playing one" | ||
27 | " to the favorites list." | ||
28 | " radish del [STATION]" | ||
29 | " Remove STATION or the currently-playing" | ||
30 | " one from the favorites list." | ||
31 | " radish edit [STATION]" | ||
32 | " Edit the information of STATION, or the" | ||
33 | " current one if not given." | ||
34 | "" | ||
35 | "See radish(1) for more details.")) | ||
36 | |||
37 | (fn main [args] | ||
38 | (match args | ||
39 | [:play ?station] (radish.play ?station) | ||
40 | [:kill] (radish.kill) | ||
41 | [:add ?station] (radish.add ?station) | ||
42 | [:del ?station] (radish.del ?station) | ||
43 | [:edit ?station] (radish.edit ?station) | ||
44 | [station] (radish.play station) | ||
45 | _ (usage))) | ||
46 | |||
47 | (main arg) | ||
diff --git a/src/lib.fnl b/src/lib.fnl new file mode 100644 index 0000000..de7bf31 --- /dev/null +++ b/src/lib.fnl | |||
@@ -0,0 +1,44 @@ | |||
1 | ;;; LIB.fnl | ||
2 | ;; Radish library | ||
3 | |||
4 | (local util (require :util)) | ||
5 | (local pls (require :pls)) | ||
6 | (local mpv (require :mpv)) | ||
7 | |||
8 | (local protocols {:http (fn [url] | ||
9 | (mpv.play)) | ||
10 | :https :find | ||
11 | :shuf :noise}) | ||
12 | |||
13 | (local radish-config (.. (or (os.getenv :XDG_CONFIG_HOME) | ||
14 | (.. (os.getenv :HOME) :/.config)) | ||
15 | :/radish/stations)) | ||
16 | |||
17 | (local radish-pid :/tmp/radish.pid) | ||
18 | (local radish-lp (.. (or (os.getenv :XDG_CACHE_HOME) | ||
19 | (.. (os.getenv :HOME) :/.cache)) | ||
20 | :/radish.lastplayed)) | ||
21 | |||
22 | (local radish-status :/tmp/radish.status) | ||
23 | |||
24 | (fn play [?station] | ||
25 | "Begin playing STATION. | ||
26 | STATION can be a stream using one of `protocols', which see. If it's not | ||
27 | present, or if STATION doesn't match a protocol in `protocols', allow the user | ||
28 | to choose one from their favorites.") | ||
29 | |||
30 | (fn kill [] | ||
31 | "Kill the current invocation of `radish'." | ||
32 | (let [pid ()])) | ||
33 | |||
34 | (fn add [?station] | ||
35 | (print :add)) | ||
36 | |||
37 | (fn del [?station] | ||
38 | (print :del)) | ||
39 | |||
40 | (fn edit [?station] | ||
41 | (print :edit)) | ||
42 | |||
43 | {: play : kill : add : del : edit} | ||
44 | |||
diff --git a/src/main.fnl b/src/main.fnl new file mode 100644 index 0000000..79fed85 --- /dev/null +++ b/src/main.fnl | |||
@@ -0,0 +1,51 @@ | |||
1 | ;;; RADISH | ||
2 | ;; A tuner for various streams | ||
3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
4 | ;; License: Good Choices (https://acdw.casa/gcl) | ||
5 | |||
6 | (local util (require :util)) | ||
7 | (local pls (require :pls)) | ||
8 | (local radish (require :lib)) | ||
9 | |||
10 | (fn usage [?exit-code] | ||
11 | (print "RADISH: a tuner for various streams | ||
12 | Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
13 | License: Good Choices (https://acdw.casa/gcl) | ||
14 | |||
15 | Commands | ||
16 | radish [STATION] | ||
17 | Begin playing STATION. If STATION is not | ||
18 | provided, display a list of favorites and | ||
19 | allow the user to choose one to play. | ||
20 | radish play [STATION] | ||
21 | Begin playing STATION. If STATION is not | ||
22 | provided, play the most recently-played. | ||
23 | radish kill | ||
24 | Kill the currently-playing station. | ||
25 | radish add [STATION] | ||
26 | Add STATION or the currently-playing one | ||
27 | to the favorites list. | ||
28 | radish del [STATION] | ||
29 | Remove STATION or the currently-playing | ||
30 | one from the favorites list. | ||
31 | radish edit [STATION] | ||
32 | Edit the information of STATION, or the | ||
33 | current one if not given. | ||
34 | |||
35 | See radish(1) for more details.") | ||
36 | (os.exit (or ?exit-code 0))) | ||
37 | |||
38 | (fn main [...] | ||
39 | "Program entry point. | ||
40 | See `usage' for usage details." | ||
41 | (match [...] | ||
42 | [:help] (usage) | ||
43 | [:play ?station] (radish.play ?station) | ||
44 | [:kill] (radish.kill) | ||
45 | [:add ?station] (radish.add ?station) | ||
46 | [:del ?station] (radish.del ?station) | ||
47 | [:edit ?station] (radish.edit ?station) | ||
48 | [station] (radish.play ?station))) | ||
49 | |||
50 | (main ...) | ||
51 | |||
diff --git a/src/mpv.fnl b/src/mpv.fnl new file mode 100644 index 0000000..11510a8 --- /dev/null +++ b/src/mpv.fnl | |||
@@ -0,0 +1,4 @@ | |||
1 | ;;; MPV.fnl | ||
2 | ;; bad bindings to mpv | ||
3 | |||
4 | (fn ) | ||
diff --git a/src/pls.fnl b/src/pls.fnl new file mode 100644 index 0000000..b3bc575 --- /dev/null +++ b/src/pls.fnl | |||
@@ -0,0 +1,51 @@ | |||
1 | ;;; PLS.fnl | ||
2 | ;; a parser for *.pls files | ||
3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
4 | ;; License: Good Choices (https://acdw.casa/gcl) | ||
5 | |||
6 | ;; https://en.wikipedia.org/wiki/PLS_(file_format) | ||
7 | |||
8 | (fn split-lines [str] | ||
9 | "Split STR into a list of lines." | ||
10 | (icollect [ln (: str :gmatch "([^\n]*)\n?")] | ||
11 | ln)) | ||
12 | |||
13 | (fn parse [str] | ||
14 | "Parse a list of LINES into a playlist." | ||
15 | ;; This /maybe/ should take a string, I suppose. | ||
16 | (let [t []] | ||
17 | (each [_ l (ipairs (split-lines str))] | ||
18 | (let [(ltype num title) (: l :match "^(.*)([0-9]+)=(.*)")] | ||
19 | (when (and ltype num title) | ||
20 | (let [ltype (string.lower ltype) | ||
21 | num (tonumber num)] | ||
22 | (if (. t num) | ||
23 | (tset t num ltype title) | ||
24 | (tset t num {ltype title})))))) | ||
25 | t)) | ||
26 | |||
27 | (fn read [file] | ||
28 | "Read a .pls FILE into a playlist." | ||
29 | (with-open [p (io.open file)] | ||
30 | (parse (: p :read :*a)))) | ||
31 | |||
32 | (fn serialize [playlist] | ||
33 | "Serialize a PLAYLIST into a .pls-formatted string." | ||
34 | (let [s (icollect [n i (ipairs playlist)] | ||
35 | (.. (string.format "File%d=%s\n" n (. i :file)) | ||
36 | (if (. i :title) | ||
37 | (string.format "Title%d=%s\n" n (. i :title)) | ||
38 | "") | ||
39 | (if (. i :length) | ||
40 | (string.format "Length%d=%s\n" n (. i :length)) | ||
41 | "")))] | ||
42 | (.. "[playlist]\n\n" (table.concat s "\n") "\n\n" :NumberOfEntries= | ||
43 | (length s) "\n" "Version=2\n"))) | ||
44 | |||
45 | (fn write [playlist file] | ||
46 | "Write PLAYLIST to FILE." | ||
47 | (with-open [p (io.open file :w)] | ||
48 | (: p :write (serialize playlist)))) | ||
49 | |||
50 | {: parse : read : serialize : write} | ||
51 | |||
diff --git a/src/test.pls b/src/test.pls new file mode 100644 index 0000000..8192fe9 --- /dev/null +++ b/src/test.pls | |||
@@ -0,0 +1,18 @@ | |||
1 | [playlist] | ||
2 | |||
3 | File1=http://relay5.181.fm:8068 | ||
4 | Length1=-1 | ||
5 | |||
6 | File2=example2.mp3 | ||
7 | Title2=Just some local audio that is 2mins long | ||
8 | Length2=120 | ||
9 | |||
10 | File3=F:\Music\whatever.m4a | ||
11 | Title3=absolute path on Windows | ||
12 | |||
13 | File4=%UserProfile%\Music\short.ogg | ||
14 | Title4=example for an Environment variable | ||
15 | Length4=5 | ||
16 | |||
17 | NumberOfEntries=4 | ||
18 | Version=2 | ||
diff --git a/pls.fnl b/src/util.fnl index 4d55dd5..9801154 100644 --- a/pls.fnl +++ b/src/util.fnl | |||
@@ -1,10 +1,9 @@ | |||
1 | ;;; PLS.fnl | 1 | ;;; UTIL.fnl |
2 | ;; a parser for *.pls files | 2 | ;; Utility functions |
3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | 3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> |
4 | ;; License: Good Choices (https://acdw.casa/gcl) | 4 | ;; License: Good Choices (https://acdw.casa/gcl) |
5 | 5 | ||
6 | (local pls {}) | 6 | (local util {}) |
7 | 7 | ||
8 | util | ||
8 | 9 | ||
9 | |||
10 | pls | ||
diff --git a/util.fnl b/util.fnl deleted file mode 100644 index c884a01..0000000 --- a/util.fnl +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | ;;; UTIL.fnl | ||
2 | ;; Utility functions | ||
3 | ;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net> | ||
4 | ;; License: Good Choices (https://acdw.casa/gcl) | ||
5 | |||
6 | (local util {}) | ||
7 | |||
8 | (lambda util.printlns [?sep ...] | ||
9 | "Print arguments as strings, delimited by ?SEP. | ||
10 | ?SEP defaults to '\n', but can be anything." | ||
11 | (print (table.concat [...] (or ?sep "\n")))) | ||
12 | |||
13 | util | ||