liquidsoap-prettier 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.github/workflows/check-formatting.yml +32 -0
  2. package/README.md +31 -5
  3. package/package.json +1 -1
  4. package/src/cli.js +104 -9
  5. package/tests/liq/audio.liq +460 -0
  6. package/tests/liq/autocue.liq +1081 -0
  7. package/tests/liq/clock.liq +14 -0
  8. package/tests/liq/cron.liq +74 -0
  9. package/tests/liq/error.liq +48 -0
  10. package/tests/liq/extra/audio.liq +677 -0
  11. package/tests/liq/extra/audioscrobbler.liq +482 -0
  12. package/tests/liq/extra/deprecations.liq +976 -0
  13. package/tests/liq/extra/externals.liq +196 -0
  14. package/tests/liq/extra/fades.liq +260 -0
  15. package/tests/liq/extra/file.liq +66 -0
  16. package/tests/liq/extra/http.liq +160 -0
  17. package/tests/liq/extra/interactive.liq +917 -0
  18. package/tests/liq/extra/metadata.liq +75 -0
  19. package/tests/liq/extra/native.liq +201 -0
  20. package/tests/liq/extra/openai.liq +150 -0
  21. package/tests/liq/extra/server.liq +177 -0
  22. package/tests/liq/extra/source.liq +476 -0
  23. package/tests/liq/extra/spinitron.liq +272 -0
  24. package/tests/liq/extra/telnet.liq +266 -0
  25. package/tests/liq/extra/video.liq +59 -0
  26. package/tests/liq/extra/visualization.liq +68 -0
  27. package/tests/liq/fades.liq +941 -0
  28. package/tests/liq/ffmpeg.liq +605 -0
  29. package/tests/liq/file.liq +387 -0
  30. package/tests/liq/getter.liq +74 -0
  31. package/tests/liq/hls.liq +329 -0
  32. package/tests/liq/http.liq +1048 -0
  33. package/tests/liq/http_codes.liq +447 -0
  34. package/tests/liq/icecast.liq +58 -0
  35. package/tests/liq/io.liq +106 -0
  36. package/tests/liq/liquidsoap.liq +31 -0
  37. package/tests/liq/list.liq +440 -0
  38. package/tests/liq/log.liq +47 -0
  39. package/tests/liq/lufs.liq +295 -0
  40. package/tests/liq/math.liq +23 -0
  41. package/tests/liq/medialib.liq +752 -0
  42. package/tests/liq/metadata.liq +253 -0
  43. package/tests/liq/nfo.liq +258 -0
  44. package/tests/liq/null.liq +71 -0
  45. package/tests/liq/playlist.liq +1347 -0
  46. package/tests/liq/predicate.liq +106 -0
  47. package/tests/liq/process.liq +93 -0
  48. package/tests/liq/profiler.liq +5 -0
  49. package/tests/liq/protocols.liq +1139 -0
  50. package/tests/liq/ref.liq +28 -0
  51. package/tests/liq/replaygain.liq +135 -0
  52. package/tests/liq/request.liq +467 -0
  53. package/tests/liq/resolvers.liq +33 -0
  54. package/tests/liq/runtime.liq +70 -0
  55. package/tests/liq/server.liq +99 -0
  56. package/tests/liq/settings.liq +41 -0
  57. package/tests/liq/socket.liq +33 -0
  58. package/tests/liq/source.liq +362 -0
  59. package/tests/liq/sqlite.liq +161 -0
  60. package/tests/liq/stdlib.liq +172 -0
  61. package/tests/liq/string.liq +476 -0
  62. package/tests/liq/switches.liq +197 -0
  63. package/tests/liq/testing.liq +37 -0
  64. package/tests/liq/thread.liq +161 -0
  65. package/tests/liq/tracks.liq +100 -0
  66. package/tests/liq/utils.liq +81 -0
  67. package/tests/liq/video.liq +918 -0
@@ -0,0 +1,161 @@
1
+ %ifdef sqlite
2
+ # @docof sqlite
3
+ def replaces sqlite(file) =
4
+ db = sqlite(file)
5
+
6
+ # Insert a list of key / value pairs, where all the values are
7
+ # strings.
8
+ def db.insert.list(~table, entries) =
9
+ let (columns, values) =
10
+ list.fold(
11
+ fun (result, entry) ->
12
+ begin
13
+ let (columns, values) = result
14
+ let (column, value) = entry
15
+ ([...columns, column], [...values, sqlite.escape(value)])
16
+ end,
17
+ ([], []),
18
+ entries
19
+ )
20
+
21
+ columns =
22
+ string.concat(
23
+ separator=", ",
24
+ columns
25
+ )
26
+ values =
27
+ string.concat(
28
+ separator=", ",
29
+ values
30
+ )
31
+ sql =
32
+ "INSERT INTO #{sqlite.escape(table)} (#{columns}) VALUES (#{values})"
33
+
34
+ db.exec(sql)
35
+ end
36
+
37
+ def db.select(~table, what="*", ~where="", ~limit=null) =
38
+ where =
39
+ if
40
+ where == ""
41
+ then
42
+ ""
43
+ else
44
+ " WHERE #{where}"
45
+ end
46
+ limit =
47
+ if
48
+ null.defined(limit)
49
+ then
50
+ " LIMIT #{null.get(limit)}"
51
+ else
52
+ ""
53
+ end
54
+ db.query(
55
+ "SELECT #{what} FROM #{table}#{where}#{limit}"
56
+ )
57
+ end
58
+
59
+ def db.select.iter(f, ~table, what="*", ~where="") =
60
+ where =
61
+ if
62
+ where == ""
63
+ then
64
+ ""
65
+ else
66
+ " WHERE #{where}"
67
+ end
68
+ db.iter(
69
+ f,
70
+ "SELECT #{what} FROM #{table}#{where}"
71
+ )
72
+ end
73
+
74
+ def db.delete(~table, ~where="") =
75
+ where =
76
+ if
77
+ where == ""
78
+ then
79
+ ""
80
+ else
81
+ " WHERE #{where}"
82
+ end
83
+ db.exec(
84
+ "DELETE FROM #{table}#{where}"
85
+ )
86
+ end
87
+
88
+ # Count the number of items matching a condition.
89
+ def db.count(~table, ~where="") =
90
+ where =
91
+ if
92
+ where == ""
93
+ then
94
+ ""
95
+ else
96
+ " WHERE " ^
97
+ where
98
+ end
99
+ let sqlite.query ([{count}] : [{count: int}]) =
100
+ db.query(
101
+ "SELECT COUNT(*) AS count FROM #{table}#{where}"
102
+ )
103
+ count
104
+ end
105
+
106
+ # Operations on tables.
107
+ let db.table = ()
108
+
109
+ def db.table.drop(table, ~existing=true) =
110
+ existing =
111
+ if
112
+ existing
113
+ then
114
+ " IF EXISTS"
115
+ else
116
+ ""
117
+ end
118
+ db.exec(
119
+ "DROP TABLE#{existing} #{table}"
120
+ )
121
+ end
122
+
123
+ # Create a table with given fields.
124
+ # @param ~preserve Preserve previous table if one already exists under the same name.
125
+ def db.table.create(table, ~preserve=false, fields) =
126
+ preserve =
127
+ if
128
+ preserve
129
+ then
130
+ " IF NOT EXISTS"
131
+ else
132
+ ""
133
+ end
134
+ fields =
135
+ string.concat(
136
+ separator=", ",
137
+ list.map(
138
+ fun (lt) ->
139
+ "#{fst(lt)} #{snd(lt)}",
140
+ fields
141
+ )
142
+ )
143
+ db.exec(
144
+ "CREATE TABLE#{preserve} #{table} (#{fields})"
145
+ )
146
+ end
147
+
148
+ # Check whether a table exists.
149
+ def db.table.exists(name) =
150
+ let sqlite.query ([{name}] : [{name: string}]) =
151
+ db.query(
152
+ "SELECT name FROM sqlite_master WHERE type='table' AND name=#{
153
+ sqlite.escape(name)
154
+ }"
155
+ )
156
+ name
157
+ end
158
+
159
+ db
160
+ end
161
+ %endif
@@ -0,0 +1,172 @@
1
+ %include "error.liq"
2
+ %include "null.liq"
3
+ %include "ref.liq"
4
+ %include "list.liq"
5
+ %include "math.liq"
6
+ %include "getter.liq"
7
+ %include "predicate.liq"
8
+ %include "settings.liq"
9
+ %include "log.liq"
10
+ %include "thread.liq"
11
+ %include "process.liq"
12
+ %include "string.liq"
13
+ %include "socket.liq"
14
+ %include "cron.liq"
15
+ %include "file.liq"
16
+ %include "switches.liq"
17
+ %include "utils.liq"
18
+ %include "clock.liq"
19
+ %include "metadata.liq"
20
+ %include "nfo.liq"
21
+ %include "playlist.liq"
22
+ %include "source.liq"
23
+ %include "tracks.liq"
24
+ %include "request.liq"
25
+ %include "audio.liq"
26
+ %include "fades.liq"
27
+ %include "autocue.liq"
28
+ %include "replaygain.liq"
29
+ %include "lufs.liq"
30
+ %include "http_codes.liq"
31
+ %include "http.liq"
32
+ %include "protocols.liq"
33
+ %include "resolvers.liq"
34
+ %include "icecast.liq"
35
+ %include "hls.liq"
36
+ %include "video.liq"
37
+ %include "ffmpeg.liq"
38
+ %include "profiler.liq"
39
+ %include "io.liq"
40
+ %include "sqlite.liq"
41
+ %include "medialib.liq"
42
+ %include "runtime.liq"
43
+ %include "server.liq"
44
+ %include "sqlite.liq"
45
+ %include "testing.liq"
46
+ %include "liquidsoap.liq"
47
+
48
+ %include_extra "extra/file.liq"
49
+ %include_extra "extra/native.liq"
50
+ %include_extra "extra/audio.liq"
51
+ %include_extra "extra/source.liq"
52
+ %include_extra "extra/http.liq"
53
+ %include_extra "extra/externals.liq"
54
+ %include_extra "extra/audioscrobbler.liq"
55
+ %include_extra "extra/server.liq"
56
+ %include_extra "extra/telnet.liq"
57
+ %include_extra "extra/interactive.liq"
58
+ %include_extra "extra/visualization.liq"
59
+ %include_extra "extra/openai.liq"
60
+ %include_extra "extra/spinitron.liq"
61
+ %include_extra "extra/metadata.liq"
62
+ %include_extra "extra/fades.liq"
63
+ %include_extra "extra/video.liq"
64
+
65
+ set_settings_ref(settings)
66
+
67
+ # Default on_select for both file and live composition profiles. When `ending`
68
+ # is non-null (the ending source was preempted mid-track), fades it out (up to
69
+ # 1s or remaining time). When `replay_metadata` is true, replays the latest
70
+ # metadata on the starting source.
71
+ def source.composition.default_on_select({starting, ending, replay_metadata}) =
72
+ let {id, insert_metadata, last_metadata} = source.methods(starting)
73
+
74
+ # starting can be an active source to insert metadata when the
75
+ # source is about to be used.
76
+ def starting() =
77
+ if
78
+ replay_metadata
79
+ then
80
+ last_metadata = last_metadata()
81
+ if
82
+ null.defined(last_metadata)
83
+ then
84
+ log.important(
85
+ label=id(),
86
+ "Switching to #{id()}: inserting latest metadata"
87
+ )
88
+ insert_metadata(null.get(last_metadata))
89
+ else
90
+ log.important(
91
+ label=id(),
92
+ "Switching to #{id()}: no latest metadata to insert"
93
+ )
94
+ end
95
+ end
96
+ starting
97
+ end
98
+
99
+ if
100
+ null.defined(ending)
101
+ then
102
+ leaving = null.get(ending)
103
+
104
+ let {id} = source.methods(leaving)
105
+
106
+ max_fade = 1.
107
+ rem = source.remaining(leaving)
108
+ if
109
+ rem == 0.
110
+ then
111
+ starting()
112
+ else
113
+ effective_fade = if rem >= 0. then min(rem, max_fade) else max_fade end
114
+ log.important(
115
+ label=id(),
116
+ "Ending #{id()} with a effective_fade #{effective_fade} fade out.."
117
+ )
118
+
119
+ leaving =
120
+ fade.out(
121
+ duration=effective_fade,
122
+ max_duration(effective_fade, sequence([leaving, switch([])]))
123
+ )
124
+
125
+ count = ref(0)
126
+ def next() =
127
+ c = count()
128
+ ref.incr(count)
129
+ if c == 0 then leaving elsif c == 1 then starting() else null end
130
+ end
131
+
132
+ source.dynamic(track_sensitive=true, next)
133
+ end
134
+ else
135
+ starting()
136
+ end
137
+ end
138
+
139
+ source.composition.file(
140
+ {
141
+ on_leave =
142
+ # skip the source when it is preempted mid-track (track_sensitive=false),
143
+ # so it starts fresh on next selection. When switching at a track
144
+ # boundary (track_sensitive=true), the source has finished naturally and
145
+ # no skip is needed.
146
+
147
+ fun ({source = s, track_sensitive}) ->
148
+ if
149
+ not track_sensitive
150
+ then
151
+ log.important(
152
+ label=source.id(s),
153
+ "Source left in the middle of a track: skipping current track"
154
+ )
155
+ let {skip, clear_last_metadata} = source.methods(s)
156
+ clear_last_metadata()
157
+ skip()
158
+ end,
159
+ on_select = source.composition.default_on_select,
160
+ track_sensitive = true,
161
+ replay_metadata = true
162
+ }
163
+ )
164
+
165
+ source.composition.live(
166
+ {
167
+ on_leave = fun (_) -> (),
168
+ on_select = source.composition.default_on_select,
169
+ track_sensitive = false,
170
+ replay_metadata = true
171
+ }
172
+ )