@norskvideo/norsk-studio-built-ins 1.11.6 → 1.12.0-2025-01-28-397642d6

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 (238) hide show
  1. package/README.md +16 -0
  2. package/client/info.js +1402 -782
  3. package/client/output.whep/styles.css +9 -0
  4. package/client/style.css +520 -858
  5. package/lib/info.js +4 -8
  6. package/lib/info.js.map +1 -1
  7. package/lib/input.rtmp/info.js +2 -1
  8. package/lib/input.rtmp/info.js.map +1 -1
  9. package/lib/input.rtmp/runtime.d.ts +24 -5
  10. package/lib/input.rtmp/runtime.js +166 -60
  11. package/lib/input.rtmp/runtime.js.map +1 -1
  12. package/lib/input.rtmp/summary-view.d.ts +3 -5
  13. package/lib/input.rtmp/summary-view.js +26 -6
  14. package/lib/input.rtmp/summary-view.js.map +1 -1
  15. package/lib/input.rtmp/types.d.ts +133 -0
  16. package/lib/input.rtmp/types.js +3 -0
  17. package/lib/input.rtmp/types.js.map +1 -0
  18. package/lib/input.rtmp/types.yaml +99 -0
  19. package/lib/input.silence/info.js +3 -2
  20. package/lib/input.silence/info.js.map +1 -1
  21. package/lib/input.srt-caller/info.js +6 -5
  22. package/lib/input.srt-caller/info.js.map +1 -1
  23. package/lib/input.srt-caller/runtime.d.ts +1 -1
  24. package/lib/input.srt-listener/info.js +14 -6
  25. package/lib/input.srt-listener/info.js.map +1 -1
  26. package/lib/input.srt-listener/runtime.d.ts +42 -6
  27. package/lib/input.srt-listener/runtime.js +237 -57
  28. package/lib/input.srt-listener/runtime.js.map +1 -1
  29. package/lib/input.srt-listener/summary-view.d.ts +3 -5
  30. package/lib/input.srt-listener/summary-view.js +81 -5
  31. package/lib/input.srt-listener/summary-view.js.map +1 -1
  32. package/lib/input.srt-listener/types.d.ts +193 -0
  33. package/lib/input.srt-listener/types.js +3 -0
  34. package/lib/input.srt-listener/types.js.map +1 -0
  35. package/lib/input.srt-listener/types.yaml +145 -0
  36. package/lib/input.udp-ts/info.d.ts +1 -1
  37. package/lib/input.udp-ts/info.js +5 -4
  38. package/lib/input.udp-ts/info.js.map +1 -1
  39. package/lib/input.udp-ts/runtime.d.ts +1 -1
  40. package/lib/input.videoTestCard/info.d.ts +1 -1
  41. package/lib/input.videoTestCard/info.js +14 -4
  42. package/lib/input.videoTestCard/info.js.map +1 -1
  43. package/lib/output.autoCmaf/info.d.ts +2 -2
  44. package/lib/output.autoCmaf/info.js +65 -7
  45. package/lib/output.autoCmaf/info.js.map +1 -1
  46. package/lib/output.autoCmaf/runtime.d.ts +29 -9
  47. package/lib/output.autoCmaf/runtime.js +198 -60
  48. package/lib/output.autoCmaf/runtime.js.map +1 -1
  49. package/lib/output.autoCmaf/summary.js +26 -1
  50. package/lib/output.autoCmaf/summary.js.map +1 -1
  51. package/lib/output.autoCmaf/types.d.ts +101 -0
  52. package/lib/output.autoCmaf/types.js +3 -0
  53. package/lib/output.autoCmaf/types.js.map +1 -0
  54. package/lib/output.autoCmaf/types.yaml +28 -0
  55. package/lib/output.preview/info.js +5 -2
  56. package/lib/output.preview/info.js.map +1 -1
  57. package/lib/output.preview/inline-view.d.ts +2 -4
  58. package/lib/output.preview/inline-view.js +41 -7
  59. package/lib/output.preview/inline-view.js.map +1 -1
  60. package/lib/output.preview/runtime.d.ts +5 -3
  61. package/lib/output.preview/runtime.js +29 -18
  62. package/lib/output.preview/runtime.js.map +1 -1
  63. package/lib/output.rtmp/info.js +1 -0
  64. package/lib/output.rtmp/info.js.map +1 -1
  65. package/lib/output.rtmp/inline-view.js +2 -2
  66. package/lib/output.rtmp/runtime.d.ts +2 -2
  67. package/lib/output.rtmp/runtime.js.map +1 -1
  68. package/lib/output.srt/info.d.ts +2 -2
  69. package/lib/output.srt/info.js +26 -5
  70. package/lib/output.srt/info.js.map +1 -1
  71. package/lib/output.srt/runtime.d.ts +30 -5
  72. package/lib/output.srt/runtime.js +139 -5
  73. package/lib/output.srt/runtime.js.map +1 -1
  74. package/lib/output.srt/types.d.ts +101 -0
  75. package/lib/output.srt/types.js +3 -0
  76. package/lib/output.srt/types.js.map +1 -0
  77. package/lib/output.srt/types.yaml +31 -0
  78. package/lib/output.statistics/info.js +1 -0
  79. package/lib/output.statistics/info.js.map +1 -1
  80. package/lib/output.statistics/inline-view.js +3 -2
  81. package/lib/output.statistics/inline-view.js.map +1 -1
  82. package/lib/output.statistics/runtime.d.ts +1 -1
  83. package/lib/output.statistics/runtime.js.map +1 -1
  84. package/lib/output.udpTs/info.d.ts +1 -1
  85. package/lib/output.udpTs/info.js +4 -3
  86. package/lib/output.udpTs/info.js.map +1 -1
  87. package/lib/output.udpTs/runtime.d.ts +1 -1
  88. package/lib/output.whep/info.d.ts +2 -2
  89. package/lib/output.whep/info.js +50 -1
  90. package/lib/output.whep/info.js.map +1 -1
  91. package/lib/output.whep/inline-view.d.ts +4 -0
  92. package/lib/output.whep/inline-view.js +57 -0
  93. package/lib/output.whep/inline-view.js.map +1 -0
  94. package/lib/output.whep/runtime.d.ts +27 -5
  95. package/lib/output.whep/runtime.js +64 -13
  96. package/lib/output.whep/runtime.js.map +1 -1
  97. package/lib/output.whep/types.d.ts +101 -0
  98. package/lib/output.whep/types.js +3 -0
  99. package/lib/output.whep/types.js.map +1 -0
  100. package/lib/output.whep/types.yaml +30 -0
  101. package/lib/processor.browserOverlay/info.d.ts +2 -2
  102. package/lib/processor.browserOverlay/info.js +56 -2
  103. package/lib/processor.browserOverlay/info.js.map +1 -1
  104. package/lib/processor.browserOverlay/inline-view.d.ts +6 -0
  105. package/lib/processor.browserOverlay/inline-view.js +8 -0
  106. package/lib/processor.browserOverlay/inline-view.js.map +1 -0
  107. package/lib/processor.browserOverlay/runtime.d.ts +40 -6
  108. package/lib/processor.browserOverlay/runtime.js +151 -23
  109. package/lib/processor.browserOverlay/runtime.js.map +1 -1
  110. package/lib/processor.browserOverlay/summary-view.d.ts +4 -0
  111. package/lib/processor.browserOverlay/summary-view.js +27 -0
  112. package/lib/processor.browserOverlay/summary-view.js.map +1 -0
  113. package/lib/processor.browserOverlay/types.d.ts +174 -0
  114. package/lib/processor.browserOverlay/types.js +3 -0
  115. package/lib/processor.browserOverlay/types.js.map +1 -0
  116. package/lib/processor.browserOverlay/types.yaml +65 -0
  117. package/lib/processor.cascadingSwitch/info.js +4 -3
  118. package/lib/processor.cascadingSwitch/info.js.map +1 -1
  119. package/lib/processor.cascadingSwitch/inline-view.js +3 -3
  120. package/lib/processor.cascadingSwitch/runtime.d.ts +1 -1
  121. package/lib/processor.cascadingSwitch/runtime.js +2 -2
  122. package/lib/processor.cascadingSwitch/runtime.js.map +1 -1
  123. package/lib/processor.fixedLadder/codec-editor.js +1 -1
  124. package/lib/processor.fixedLadder/codec-editor.js.map +1 -1
  125. package/lib/processor.fixedLadder/codec-view.js +1 -1
  126. package/lib/processor.fixedLadder/codec-view.js.map +1 -1
  127. package/lib/processor.fixedLadder/info.js +4 -2
  128. package/lib/processor.fixedLadder/info.js.map +1 -1
  129. package/lib/processor.fixedLadder/rung-view.js +1 -1
  130. package/lib/processor.fixedLadder/rung-view.js.map +1 -1
  131. package/lib/processor.onscreenGraphic/image-selection.d.ts +9 -0
  132. package/lib/{processor.dynamicBug/bug-selection.js → processor.onscreenGraphic/image-selection.js} +10 -10
  133. package/lib/processor.onscreenGraphic/image-selection.js.map +1 -0
  134. package/lib/processor.onscreenGraphic/info.d.ts +3 -0
  135. package/lib/{processor.dynamicBug → processor.onscreenGraphic}/info.js +23 -16
  136. package/lib/processor.onscreenGraphic/info.js.map +1 -0
  137. package/lib/processor.onscreenGraphic/runtime.d.ts +91 -0
  138. package/lib/processor.onscreenGraphic/runtime.js +503 -0
  139. package/lib/processor.onscreenGraphic/runtime.js.map +1 -0
  140. package/lib/processor.onscreenGraphic/summary-view.d.ts +4 -0
  141. package/lib/processor.onscreenGraphic/summary-view.js +343 -0
  142. package/lib/processor.onscreenGraphic/summary-view.js.map +1 -0
  143. package/lib/processor.onscreenGraphic/types.d.ts +271 -0
  144. package/lib/processor.onscreenGraphic/types.js +3 -0
  145. package/lib/processor.onscreenGraphic/types.js.map +1 -0
  146. package/lib/processor.onscreenGraphic/types.yaml +211 -0
  147. package/lib/processor.streamKeyOverride/info.d.ts +3 -0
  148. package/lib/processor.streamKeyOverride/info.js +150 -0
  149. package/lib/processor.streamKeyOverride/info.js.map +1 -0
  150. package/lib/processor.streamKeyOverride/runtime.d.ts +54 -0
  151. package/lib/processor.streamKeyOverride/runtime.js +226 -0
  152. package/lib/processor.streamKeyOverride/runtime.js.map +1 -0
  153. package/lib/shared/drm/axinom.d.ts +2 -0
  154. package/lib/shared/drm/axinom.js +120 -0
  155. package/lib/shared/drm/axinom.js.map +1 -0
  156. package/lib/shared/drm/cpix.d.ts +24 -0
  157. package/lib/shared/drm/cpix.js +97 -0
  158. package/lib/shared/drm/cpix.js.map +1 -0
  159. package/lib/shared/drm/ezdrm.d.ts +2 -0
  160. package/lib/shared/drm/ezdrm.js +26 -0
  161. package/lib/shared/drm/ezdrm.js.map +1 -0
  162. package/lib/shared/srt-socket-options.js +6 -6
  163. package/lib/shared/srt-socket-options.js.map +1 -1
  164. package/lib/test/auto-cmaf.js +25 -17
  165. package/lib/test/auto-cmaf.js.map +1 -1
  166. package/lib/test/browser-overlay.js +1 -0
  167. package/lib/test/browser-overlay.js.map +1 -1
  168. package/lib/test/{dynamic-bug.js → onscreen-graphic.js} +139 -106
  169. package/lib/test/onscreen-graphic.js.map +1 -0
  170. package/lib/test/preview.js +3 -3
  171. package/lib/test/preview.js.map +1 -1
  172. package/lib/test/rtmp-input.js +6 -3
  173. package/lib/test/rtmp-input.js.map +1 -1
  174. package/lib/test/srt-input-caller.js +5 -5
  175. package/lib/test/srt-input-caller.js.map +1 -1
  176. package/lib/test/srt-input-listener.js +99 -18
  177. package/lib/test/srt-input-listener.js.map +1 -1
  178. package/lib/test/srt-output.js +2 -2
  179. package/lib/test/srt-output.js.map +1 -1
  180. package/lib/test/udp-output.js +2 -2
  181. package/lib/test/udp-output.js.map +1 -1
  182. package/lib/test/udp-ts-input.js +2 -2
  183. package/lib/test/udp-ts-input.js.map +1 -1
  184. package/lib/test/whep-output.js +8 -2
  185. package/lib/test/whep-output.js.map +1 -1
  186. package/lib/{util.latency → util.stats.latency}/info.js +2 -1
  187. package/lib/util.stats.latency/info.js.map +1 -0
  188. package/lib/util.stats.latency/inline-view.js.map +1 -0
  189. package/lib/{util.latency → util.stats.latency}/runtime.d.ts +1 -1
  190. package/lib/{util.latency → util.stats.latency}/runtime.js +2 -2
  191. package/lib/util.stats.latency/runtime.js.map +1 -0
  192. package/lib/util.stats.latency/source-node-selection.js.map +1 -0
  193. package/package.json +12 -5
  194. package/lib/processor.dynamicBug/bug-selection.d.ts +0 -9
  195. package/lib/processor.dynamicBug/bug-selection.js.map +0 -1
  196. package/lib/processor.dynamicBug/info.d.ts +0 -3
  197. package/lib/processor.dynamicBug/info.js.map +0 -1
  198. package/lib/processor.dynamicBug/runtime.d.ts +0 -64
  199. package/lib/processor.dynamicBug/runtime.js +0 -297
  200. package/lib/processor.dynamicBug/runtime.js.map +0 -1
  201. package/lib/processor.dynamicBug/summary-view.d.ts +0 -4
  202. package/lib/processor.dynamicBug/summary-view.js +0 -60
  203. package/lib/processor.dynamicBug/summary-view.js.map +0 -1
  204. package/lib/processor.whisper-transcribe/info.d.ts +0 -3
  205. package/lib/processor.whisper-transcribe/info.js +0 -43
  206. package/lib/processor.whisper-transcribe/info.js.map +0 -1
  207. package/lib/processor.whisper-transcribe/runtime.d.ts +0 -29
  208. package/lib/processor.whisper-transcribe/runtime.js +0 -83
  209. package/lib/processor.whisper-transcribe/runtime.js.map +0 -1
  210. package/lib/test/dynamic-bug.js.map +0 -1
  211. package/lib/util.latency/info.js.map +0 -1
  212. package/lib/util.latency/inline-view.js.map +0 -1
  213. package/lib/util.latency/runtime.js.map +0 -1
  214. package/lib/util.latency/source-node-selection.js.map +0 -1
  215. package/lib/util.ma35d/info.d.ts +0 -3
  216. package/lib/util.ma35d/info.js +0 -78
  217. package/lib/util.ma35d/info.js.map +0 -1
  218. package/lib/util.ma35d/inline-view.d.ts +0 -6
  219. package/lib/util.ma35d/inline-view.js +0 -76
  220. package/lib/util.ma35d/inline-view.js.map +0 -1
  221. package/lib/util.ma35d/runtime.d.ts +0 -21
  222. package/lib/util.ma35d/runtime.js +0 -49
  223. package/lib/util.ma35d/runtime.js.map +0 -1
  224. package/lib/util.timestamps/info.d.ts +0 -5
  225. package/lib/util.timestamps/info.js +0 -86
  226. package/lib/util.timestamps/info.js.map +0 -1
  227. package/lib/util.timestamps/inline-view.d.ts +0 -6
  228. package/lib/util.timestamps/inline-view.js +0 -94
  229. package/lib/util.timestamps/inline-view.js.map +0 -1
  230. package/lib/util.timestamps/runtime.d.ts +0 -29
  231. package/lib/util.timestamps/runtime.js +0 -40
  232. package/lib/util.timestamps/runtime.js.map +0 -1
  233. /package/lib/test/{dynamic-bug.d.ts → onscreen-graphic.d.ts} +0 -0
  234. /package/lib/{util.latency → util.stats.latency}/info.d.ts +0 -0
  235. /package/lib/{util.latency → util.stats.latency}/inline-view.d.ts +0 -0
  236. /package/lib/{util.latency → util.stats.latency}/inline-view.js +0 -0
  237. /package/lib/{util.latency → util.stats.latency}/source-node-selection.d.ts +0 -0
  238. /package/lib/{util.latency → util.stats.latency}/source-node-selection.js +0 -0
package/client/info.js CHANGED
@@ -75,7 +75,7 @@ var summary_view_exports = {};
75
75
  __export(summary_view_exports, {
76
76
  default: () => summary_view_default
77
77
  });
78
- function SummaryView({ state, config }) {
78
+ function SummaryView({ state, config, urls, sendCommand }) {
79
79
  const connectedSources = [];
80
80
  const disconnectedSources = [];
81
81
  config.streamNames.forEach((streamName) => {
@@ -85,11 +85,30 @@ function SummaryView({ state, config }) {
85
85
  disconnectedSources.push(streamName);
86
86
  }
87
87
  });
88
- return (0, import_jsx_runtime2.jsxs)("div", { className: "dark:text-white text-black mb-3 w-60", children: [(0, import_jsx_runtime2.jsxs)("div", { id: "rtmp-sources-connected", children: [(0, import_jsx_runtime2.jsx)("span", { children: "Sources connected" }), (0, import_jsx_runtime2.jsx)("ul", { children: connectedSources.map((streamId) => {
89
- return (0, import_jsx_runtime2.jsx)("li", { className: "text-green-300", children: streamId });
90
- }) })] }), (0, import_jsx_runtime2.jsxs)("div", { id: "rtmp-sources-disconnected", className: "mt-3", children: [(0, import_jsx_runtime2.jsx)("span", { children: "Sources disconnected" }), (0, import_jsx_runtime2.jsx)("ul", { children: disconnectedSources.map((streamId) => {
91
- return (0, import_jsx_runtime2.jsx)("li", { className: "text-orange-300", children: streamId });
92
- }) })] })] });
88
+ const handleDisconnectStream = (streamName) => {
89
+ void disconnectStream(streamName);
90
+ };
91
+ const disconnectStream = async (streamName) => {
92
+ try {
93
+ const response = await fetch(`${urls.componentUrl}/disconnect`, {
94
+ method: "POST",
95
+ headers: {
96
+ "Content-Type": "application/json"
97
+ },
98
+ body: JSON.stringify({ streamName })
99
+ });
100
+ if (!response.ok) {
101
+ console.error("Stream failed to disconnect");
102
+ }
103
+ sendCommand({
104
+ type: "disconnect-source",
105
+ streamName
106
+ });
107
+ } catch (error) {
108
+ console.error("Failed to disconnect stream:", error);
109
+ }
110
+ };
111
+ return (0, import_jsx_runtime2.jsxs)("div", { className: "dark:text-white text-black mb-3 w-60", children: [(0, import_jsx_runtime2.jsxs)("div", { id: "rtmp-sources-connected", children: [(0, import_jsx_runtime2.jsx)("span", { children: "Sources connected" }), (0, import_jsx_runtime2.jsx)("ul", { children: connectedSources.map((streamName) => (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-center justify-between", children: [(0, import_jsx_runtime2.jsx)("span", { className: "text-green-300", children: streamName }), (0, import_jsx_runtime2.jsx)("button", { onClick: () => handleDisconnectStream(streamName), className: "ml-2 px-2 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded", children: "Disconnect" })] }, streamName)) })] }), (0, import_jsx_runtime2.jsxs)("div", { id: "rtmp-sources-disconnected", className: "mt-3", children: [(0, import_jsx_runtime2.jsx)("span", { children: "Sources disconnected" }), (0, import_jsx_runtime2.jsx)("ul", { children: disconnectedSources.map((streamName) => (0, import_jsx_runtime2.jsx)("li", { className: "flex items-center justify-between", children: (0, import_jsx_runtime2.jsx)("span", { className: "text-orange-300", children: streamName }) }, streamName)) })] })] });
93
112
  }
94
113
  var import_jsx_runtime2, summary_view_default;
95
114
  var init_summary_view = __esm({
@@ -147,20 +166,90 @@ var summary_view_exports2 = {};
147
166
  __export(summary_view_exports2, {
148
167
  default: () => summary_view_default2
149
168
  });
150
- function SummaryView3({ state, config }) {
169
+ function SummaryView3({ state, config, urls, sendCommand }) {
151
170
  const connectedSources = [];
152
171
  const disconnectedSources = [];
172
+ const resetStream = async (streamId) => {
173
+ try {
174
+ const response = await fetch(`${urls.nodeUrl}/disconnect`, {
175
+ method: "POST",
176
+ headers: {
177
+ "Content-Type": "application/json"
178
+ },
179
+ body: JSON.stringify({ streamId })
180
+ });
181
+ if (!response.ok) {
182
+ console.error("Stream failed to disconnect");
183
+ }
184
+ sendCommand({
185
+ type: "reset-source",
186
+ streamId
187
+ });
188
+ } catch (error) {
189
+ console.error("Failed to disconnect stream:", error);
190
+ }
191
+ };
192
+ const disableStream = async (streamId) => {
193
+ try {
194
+ const response = await fetch(`${urls.nodeUrl}/disable`, {
195
+ method: "POST",
196
+ headers: {
197
+ "Content-Type": "application/json"
198
+ },
199
+ body: JSON.stringify({ streamId })
200
+ });
201
+ if (!response.ok) {
202
+ console.error("Failed to disable stream");
203
+ }
204
+ sendCommand({
205
+ type: "reset-source",
206
+ streamId
207
+ });
208
+ } catch (error) {
209
+ console.error("Failed to disable stream:", error);
210
+ }
211
+ };
212
+ const enableStream = async (streamId) => {
213
+ try {
214
+ const response = await fetch(`${urls.nodeUrl}/enable`, {
215
+ method: "POST",
216
+ headers: {
217
+ "Content-Type": "application/json"
218
+ },
219
+ body: JSON.stringify({ streamId })
220
+ });
221
+ if (!response.ok) {
222
+ console.error("Failed to enable stream");
223
+ }
224
+ sendCommand({
225
+ type: "reset-source",
226
+ streamId
227
+ });
228
+ } catch (error) {
229
+ console.error("Failed to enable stream:", error);
230
+ }
231
+ };
232
+ const handleResetStream = (streamId) => {
233
+ void resetStream(streamId);
234
+ };
235
+ const handleDisableStream = (streamId) => {
236
+ void disableStream(streamId);
237
+ };
238
+ const handleEnableStream = (streamId) => {
239
+ void enableStream(streamId);
240
+ };
153
241
  config.streamIds.forEach((streamId) => {
242
+ console.log(config.streamIds, state);
154
243
  if (state.connectedStreams.includes(streamId)) {
155
244
  connectedSources.push(streamId);
156
245
  } else {
157
246
  disconnectedSources.push(streamId);
158
247
  }
159
248
  });
160
- return (0, import_jsx_runtime5.jsxs)("div", { className: "dark:text-white text-black mb-3 w-60", children: [(0, import_jsx_runtime5.jsxs)("div", { id: "srt-sources-connected", children: [(0, import_jsx_runtime5.jsx)("span", { children: "Sources connected" }), (0, import_jsx_runtime5.jsx)("ul", { children: connectedSources.map((streamId) => {
161
- return (0, import_jsx_runtime5.jsx)("li", { className: "text-green-300", children: streamId }, streamId);
162
- }) })] }), (0, import_jsx_runtime5.jsxs)("div", { id: "srt-sources-disconnected", className: "mt-3", children: [(0, import_jsx_runtime5.jsx)("span", { children: "Sources disconnected" }), (0, import_jsx_runtime5.jsx)("ul", { children: disconnectedSources.map((streamId) => {
163
- return (0, import_jsx_runtime5.jsx)("li", { className: "text-orange-300", children: streamId }, streamId);
249
+ return (0, import_jsx_runtime5.jsxs)("div", { className: "dark:text-white text-black mb-3 w-60", children: [(0, import_jsx_runtime5.jsxs)("div", { id: "srt-sources-connected", children: [(0, import_jsx_runtime5.jsx)("span", { children: "Connected Sources" }), (0, import_jsx_runtime5.jsx)("ul", { children: connectedSources.map((streamId) => {
250
+ return (0, import_jsx_runtime5.jsxs)("li", { className: "text-green-300", children: [streamId, (0, import_jsx_runtime5.jsx)("button", { onClick: () => handleResetStream(streamId), className: "ml-2 px-2 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded", children: "Reset" }), (0, import_jsx_runtime5.jsx)("button", { onClick: () => handleDisableStream(streamId), className: "ml-2 px-2 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded", children: "Disable" })] }, streamId);
251
+ }) })] }), (0, import_jsx_runtime5.jsxs)("div", { id: "srt-sources-disconnected", className: "mt-3", children: [(0, import_jsx_runtime5.jsx)("span", { children: "Disconnected Sources" }), (0, import_jsx_runtime5.jsx)("ul", { children: disconnectedSources.map((streamId) => {
252
+ return (0, import_jsx_runtime5.jsxs)("li", { className: "text-orange-300", children: [streamId, state.disabledStreams.includes(streamId) ? (0, import_jsx_runtime5.jsx)("button", { onClick: () => handleEnableStream(streamId), className: "ml-2 px-2 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded", children: "Enable" }) : (0, import_jsx_runtime5.jsx)("button", { onClick: () => handleDisableStream(streamId), className: "ml-2 px-2 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded", children: "Disable" })] }, streamId);
164
253
  }) })] })] });
165
254
  }
166
255
  var import_jsx_runtime5, summary_view_default2;
@@ -172,117 +261,24 @@ var init_summary_view2 = __esm({
172
261
  }
173
262
  });
174
263
 
175
- // external-global-plugin:hls.js
176
- var require_hls = __commonJS({
177
- "external-global-plugin:hls.js"(exports, module) {
178
- module.exports = window.HlsJs;
179
- }
180
- });
181
-
182
- // build/output.autoCmaf/summary.js
183
- var summary_exports = {};
184
- __export(summary_exports, {
185
- default: () => summary_default
186
- });
187
- function InlineView5({ state, config }) {
188
- const url = state.url;
189
- const id = config.id;
190
- const previewVideo = (0, import_react4.useRef)(null);
191
- (0, import_react4.useEffect)(() => {
192
- if (!url)
193
- return;
194
- if (!previewVideo.current)
195
- return;
196
- if (import_hls.default.isSupported()) {
197
- const hls = new import_hls.default();
198
- hls.loadSource(url);
199
- hls.attachMedia(previewVideo.current);
200
- } else if (previewVideo.current.canPlayType("application/vnd.apple.mpegurl")) {
201
- previewVideo.current.src = url;
202
- }
203
- }, [state.url]);
204
- if (!url)
205
- return (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: "..." });
206
- return (0, import_jsx_runtime6.jsx)("div", { className: "mb-5", children: (0, import_jsx_runtime6.jsx)("video", { ref: previewVideo, autoPlay: true, muted: true, id: `${id}-video` }) });
207
- }
208
- var import_jsx_runtime6, import_react4, import_hls, summary_default;
209
- var init_summary = __esm({
210
- "build/output.autoCmaf/summary.js"() {
211
- "use strict";
212
- import_jsx_runtime6 = __toESM(require_jsx_runtime());
213
- import_react4 = __toESM(require_react());
214
- import_hls = __toESM(require_hls());
215
- summary_default = InlineView5;
216
- }
217
- });
218
-
219
- // build/output.autoCmaf/fullscreen.js
220
- var fullscreen_exports = {};
221
- __export(fullscreen_exports, {
222
- default: () => fullscreen_default
223
- });
224
- function FullscreenView({ state, config }) {
225
- const url = state.url;
226
- const id = config.id;
227
- (0, import_react5.useEffect)(() => {
228
- if (!url)
229
- return;
230
- const element = document.getElementById(`${id}-video`);
231
- if (import_hls2.default.isSupported()) {
232
- const hls = new import_hls2.default();
233
- hls.loadSource(url);
234
- hls.attachMedia(element);
235
- } else if (element.canPlayType("application/vnd.apple.mpegurl")) {
236
- element.src = url;
237
- }
238
- }, [state.url]);
239
- if (!url)
240
- return (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: "..." });
241
- {
242
- }
243
- return (0, import_jsx_runtime7.jsx)("div", { children: (0, import_jsx_runtime7.jsx)("video", { controls: true, autoPlay: true, muted: true, id: `${id}-video` }) });
244
- }
245
- var import_jsx_runtime7, import_react5, import_hls2, fullscreen_default;
246
- var init_fullscreen = __esm({
247
- "build/output.autoCmaf/fullscreen.js"() {
248
- "use strict";
249
- import_jsx_runtime7 = __toESM(require_jsx_runtime());
250
- import_react5 = __toESM(require_react());
251
- import_hls2 = __toESM(require_hls());
252
- fullscreen_default = FullscreenView;
253
- }
254
- });
255
-
256
- // build/output.autoCmaf/form-views.js
257
- var form_views_exports = {};
258
- __export(form_views_exports, {
259
- S3Destination: () => S3Destination,
260
- SegmentConfiguration: () => SegmentConfiguration
261
- });
262
- function S3Destination(destination) {
263
- return (0, import_jsx_runtime8.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Host" }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-2", children: destination.host }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Path" }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-2", children: destination.prefix }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Include Ads" }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-2", children: destination.includeAdInsertions ? "yes" : "no" })] });
264
- }
265
- function SegmentConfiguration(cfg) {
266
- return (0, import_jsx_runtime8.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Segments" }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-2", children: cfg.defaultSegmentCount == 0 ? "all" : cfg.defaultSegmentCount }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Segment Target" }), (0, import_jsx_runtime8.jsxs)("div", { className: "col-span-2", children: [cfg.targetSegmentDuration, "s"] }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Part Target" }), (0, import_jsx_runtime8.jsxs)("div", { className: "col-span-2", children: [cfg.targetPartDuration, "s"] }), (0, import_jsx_runtime8.jsx)("div", { className: "col-span-1", children: "Retention" }), (0, import_jsx_runtime8.jsxs)("div", { className: "col-span-2", children: [cfg.retentionPeriod, "s"] })] });
267
- }
268
- var import_jsx_runtime8;
269
- var init_form_views = __esm({
270
- "build/output.autoCmaf/form-views.js"() {
271
- "use strict";
272
- import_jsx_runtime8 = __toESM(require_jsx_runtime());
273
- }
274
- });
275
-
276
264
  // ../../node_modules/@norskvideo/norsk-studio/lib/shared/shared-views.js
277
265
  var require_shared_views = __commonJS({
278
266
  "../../node_modules/@norskvideo/norsk-studio/lib/shared/shared-views.js"(exports) {
279
267
  "use strict";
280
268
  Object.defineProperty(exports, "__esModule", { value: true });
281
269
  exports.GlobalIceServerView = GlobalIceServerView;
270
+ exports.EzDrmConfigView = EzDrmConfigView;
271
+ exports.AxinomConfigView = AxinomConfigView;
282
272
  var jsx_runtime_1 = require_jsx_runtime();
283
273
  function GlobalIceServerView(i) {
284
274
  return (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "URL" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2", children: i.url }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Reported URL" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2", children: i.reportedUrl ?? "" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Username" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2", children: i.username ?? "" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Password" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2", children: i.credential ?? "" })] });
285
275
  }
276
+ function EzDrmConfigView(i) {
277
+ return (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-2 text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "col-span-2 node-editor-helper-text", children: "For Encryption (required)" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Token" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.token?.trim() ? "Yes" : "No" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2 node-editor-helper-text", children: "For Local Preview (optional)" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "pX" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.pX?.trim() ? "Yes" : "No" })] });
278
+ }
279
+ function AxinomConfigView(i) {
280
+ return (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-2 text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "col-span-2 node-editor-helper-text", children: "For Encryption (required)" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Tenant ID" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.tenantId?.trim() ? "Yes" : "No" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Management Key" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.managementKey?.trim() ? "Yes" : "No" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-2 node-editor-helper-text", children: "For Local Preview (optional)" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Communication ID" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.comKeyId?.trim() ? "Yes" : "No" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: "Communication Key" }), (0, jsx_runtime_1.jsx)("div", { className: "col-span-1", children: i.comKey?.trim() ? "Yes" : "No" })] });
281
+ }
286
282
  }
287
283
  });
288
284
 
@@ -327,6 +323,8 @@ var require_config = __commonJS({
327
323
  };
328
324
  Object.defineProperty(exports, "__esModule", { value: true });
329
325
  exports.GlobalIceServers = GlobalIceServers3;
326
+ exports.GlobalEzDrmConfig = GlobalEzDrmConfig2;
327
+ exports.GlobalAxinomConfig = GlobalAxinomConfig2;
330
328
  exports.contractHardwareAcceleration = contractHardwareAcceleration;
331
329
  exports.HardwareSelection = HardwareSelection5;
332
330
  exports.RootDataDir = RootDataDir;
@@ -356,7 +354,8 @@ var require_config = __commonJS({
356
354
  help: "Optional URL of the STUN/TURN server as accessed by the client (if different to the above)",
357
355
  hint: {
358
356
  type: "text",
359
- validation: f.validation.IceServer
357
+ validation: Z.union([Z.literal(""), f.validation.IceServer]).optional(),
358
+ optional: true
360
359
  }
361
360
  },
362
361
  username: {
@@ -382,6 +381,90 @@ var require_config = __commonJS({
382
381
  }
383
382
  };
384
383
  }
384
+ function GlobalEzDrmConfig2(_f) {
385
+ const EzDrmConfigView = react_1.default.lazy(async () => {
386
+ const views = await Promise.resolve().then(() => __importStar(require_shared_views()));
387
+ return { default: views.EzDrmConfigView };
388
+ });
389
+ return {
390
+ id: "ezdrm-config",
391
+ form: {
392
+ help: "Configuration for EZDRM",
393
+ hint: {
394
+ envOverride: true,
395
+ type: "form-item",
396
+ optional: true,
397
+ form: {
398
+ token: {
399
+ help: "Token for EZDRM",
400
+ hint: {
401
+ envOverride: true,
402
+ type: "text"
403
+ }
404
+ },
405
+ pX: {
406
+ help: "The last six digits of your Widevine Profile ID",
407
+ hint: {
408
+ envOverride: true,
409
+ defaultValue: "",
410
+ type: "text"
411
+ }
412
+ }
413
+ },
414
+ view: EzDrmConfigView
415
+ }
416
+ }
417
+ };
418
+ }
419
+ function GlobalAxinomConfig2(_f) {
420
+ const AxinomConfigView = react_1.default.lazy(async () => {
421
+ const views = await Promise.resolve().then(() => __importStar(require_shared_views()));
422
+ return { default: views.AxinomConfigView };
423
+ });
424
+ return {
425
+ id: "axinom-config",
426
+ form: {
427
+ help: "Configuration for Axinom DRM",
428
+ hint: {
429
+ envOverride: true,
430
+ type: "form-item",
431
+ form: {
432
+ tenantId: {
433
+ help: "Tenant ID from your Axinom DRM account",
434
+ hint: {
435
+ envOverride: true,
436
+ type: "text"
437
+ }
438
+ },
439
+ managementKey: {
440
+ help: "Management Key from your Axinom DRM account",
441
+ hint: {
442
+ envOverride: true,
443
+ type: "text"
444
+ }
445
+ },
446
+ comKeyId: {
447
+ help: "Communication Key ID from your Axinom DRM account",
448
+ hint: {
449
+ envOverride: true,
450
+ defaultValue: "",
451
+ type: "text"
452
+ }
453
+ },
454
+ comKey: {
455
+ help: "Communication Key from your Axinom DRM account",
456
+ hint: {
457
+ envOverride: true,
458
+ defaultValue: "",
459
+ type: "text"
460
+ }
461
+ }
462
+ },
463
+ view: AxinomConfigView
464
+ }
465
+ }
466
+ };
467
+ }
385
468
  function contractHardwareAcceleration(value, accepted) {
386
469
  if (!value)
387
470
  return void 0;
@@ -424,6 +507,70 @@ var require_config = __commonJS({
424
507
  }
425
508
  });
426
509
 
510
+ // external-global-plugin:hls.js
511
+ var require_hls = __commonJS({
512
+ "external-global-plugin:hls.js"(exports, module) {
513
+ module.exports = window.HlsJs;
514
+ }
515
+ });
516
+
517
+ // build/output.autoCmaf/fullscreen.js
518
+ var fullscreen_exports = {};
519
+ __export(fullscreen_exports, {
520
+ default: () => fullscreen_default
521
+ });
522
+ function FullscreenView({ state, config }) {
523
+ const url = state.url;
524
+ const id = config.id;
525
+ (0, import_react4.useEffect)(() => {
526
+ if (!url)
527
+ return;
528
+ const element = document.getElementById(`${id}-video`);
529
+ if (import_hls.default.isSupported()) {
530
+ const hls = new import_hls.default();
531
+ hls.loadSource(url);
532
+ hls.attachMedia(element);
533
+ } else if (element.canPlayType("application/vnd.apple.mpegurl")) {
534
+ element.src = url;
535
+ }
536
+ }, [state.url]);
537
+ if (!url)
538
+ return (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: "..." });
539
+ {
540
+ }
541
+ return (0, import_jsx_runtime6.jsx)("div", { children: (0, import_jsx_runtime6.jsx)("video", { controls: true, autoPlay: true, muted: true, id: `${id}-video` }) });
542
+ }
543
+ var import_jsx_runtime6, import_react4, import_hls, fullscreen_default;
544
+ var init_fullscreen = __esm({
545
+ "build/output.autoCmaf/fullscreen.js"() {
546
+ "use strict";
547
+ import_jsx_runtime6 = __toESM(require_jsx_runtime());
548
+ import_react4 = __toESM(require_react());
549
+ import_hls = __toESM(require_hls());
550
+ fullscreen_default = FullscreenView;
551
+ }
552
+ });
553
+
554
+ // build/output.autoCmaf/form-views.js
555
+ var form_views_exports = {};
556
+ __export(form_views_exports, {
557
+ S3Destination: () => S3Destination,
558
+ SegmentConfiguration: () => SegmentConfiguration
559
+ });
560
+ function S3Destination(destination) {
561
+ return (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Host" }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-2", children: destination.host }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Path" }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-2", children: destination.prefix }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Include Ads" }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-2", children: destination.includeAdInsertions ? "yes" : "no" })] });
562
+ }
563
+ function SegmentConfiguration(cfg) {
564
+ return (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Segments" }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-2", children: cfg.defaultSegmentCount == 0 ? "all" : cfg.defaultSegmentCount }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Segment Target" }), (0, import_jsx_runtime7.jsxs)("div", { className: "col-span-2", children: [cfg.targetSegmentDuration, "s"] }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Part Target" }), (0, import_jsx_runtime7.jsxs)("div", { className: "col-span-2", children: [cfg.targetPartDuration, "s"] }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Retention" }), (0, import_jsx_runtime7.jsxs)("div", { className: "col-span-2", children: [cfg.retentionPeriod, "s"] })] });
565
+ }
566
+ var import_jsx_runtime7;
567
+ var init_form_views = __esm({
568
+ "build/output.autoCmaf/form-views.js"() {
569
+ "use strict";
570
+ import_jsx_runtime7 = __toESM(require_jsx_runtime());
571
+ }
572
+ });
573
+
427
574
  // external-global-plugin:@norskvideo/webrtc-client
428
575
  var require_webrtc_client = __commonJS({
429
576
  "external-global-plugin:@norskvideo/webrtc-client"(exports, module) {
@@ -436,17 +583,49 @@ var inline_view_exports3 = {};
436
583
  __export(inline_view_exports3, {
437
584
  default: () => inline_view_default3
438
585
  });
439
- function InlineView6({ state, config }) {
586
+ function InlineView5({ state, config, raise }) {
440
587
  const url = state.url;
441
588
  const id = config.id;
442
- (0, import_react7.useEffect)(() => {
443
- if (!url)
589
+ const [showPreview, setShowPreview] = (0, import_react6.useState)(config.showPreview ?? true);
590
+ const [client, setClient] = (0, import_react6.useState)(null);
591
+ const createClient = (url2) => {
592
+ const client2 = new import_webrtc_client.WhepClient({
593
+ url: url2,
594
+ container: document.getElementById(`preview-${id}`) ?? void 0
595
+ });
596
+ client2.start().catch(console.error);
597
+ return client2;
598
+ };
599
+ const cleanupClient = (client2) => {
600
+ client2.outputVideoTracks.forEach((track) => track.stop());
601
+ if (client2.outputAudioTrack) {
602
+ client2.outputAudioTrack.stop();
603
+ }
604
+ client2.videoElements.forEach((video) => {
605
+ video.srcObject = null;
606
+ video.remove();
607
+ });
608
+ };
609
+ (0, import_react6.useEffect)(() => {
610
+ if (!url || !showPreview) {
611
+ if (client) {
612
+ cleanupClient(client);
613
+ setClient(null);
614
+ }
444
615
  return;
445
- const client = new import_webrtc_client.WhepClient({ url, container: document.getElementById(`preview-${id}`) ?? void 0 });
446
- void client.start();
447
- }, [state.url]);
616
+ }
617
+ const newClient = createClient(url);
618
+ setClient(newClient);
619
+ return () => {
620
+ cleanupClient(newClient);
621
+ };
622
+ }, [state.url, showPreview]);
623
+ (0, import_react6.useEffect)(() => {
624
+ setShowPreview(config.showPreview ?? true);
625
+ }, [config.showPreview]);
626
+ raise && (0, import_react6.useEffect)(raise, []);
448
627
  if (!url)
449
- return (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: "..." });
628
+ return (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: "..." });
450
629
  function percentage(levels) {
451
630
  if (!levels) {
452
631
  return 0;
@@ -456,16 +635,18 @@ function InlineView6({ state, config }) {
456
635
  const snapped = Math.floor(capped * 10) * 10;
457
636
  return Math.max(0, 100 - snapped);
458
637
  }
459
- return (0, import_jsx_runtime9.jsxs)("div", { className: "preview-outer-container", children: [(0, import_jsx_runtime9.jsx)("div", { className: "preview-video", id: `preview-${id}` }), (0, import_jsx_runtime9.jsx)("div", { className: "preview-levels", children: (0, import_jsx_runtime9.jsx)("div", { className: `preview-level clip-${percentage(state.levels)}-preview` }) })] });
638
+ return (0, import_jsx_runtime8.jsxs)("div", { className: "preview-outer-container", children: [(0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, import_jsx_runtime8.jsx)("input", { type: "checkbox", id: `video-toggle-${id}`, checked: showPreview, onChange: (e) => setShowPreview(e.target.checked), className: "h-4 w-4" }), (0, import_jsx_runtime8.jsx)("label", { htmlFor: `video-toggle-${id}`, className: "text-sm", children: "Show Preview" })] }), showPreview ? (0, import_jsx_runtime8.jsx)("div", { className: "preview-video", id: `preview-${id}`, children: (0, import_jsx_runtime8.jsx)("style", { children: `
639
+ #preview-${id} video::-webkit-media-controls-play-button { display: none; },
640
+ ` }) }) : (0, import_jsx_runtime8.jsx)("div", { className: "preview-video bg-black flex items-center justify-center text-white h-full", children: "Preview turned off" }), (0, import_jsx_runtime8.jsx)("div", { className: "preview-levels", children: (0, import_jsx_runtime8.jsx)("div", { className: `preview-level clip-${percentage(state.levels)}-preview` }) })] });
460
641
  }
461
- var import_jsx_runtime9, import_react7, import_webrtc_client, inline_view_default3;
642
+ var import_jsx_runtime8, import_react6, import_webrtc_client, inline_view_default3;
462
643
  var init_inline_view3 = __esm({
463
644
  "build/output.preview/inline-view.js"() {
464
645
  "use strict";
465
- import_jsx_runtime9 = __toESM(require_jsx_runtime());
466
- import_react7 = __toESM(require_react());
646
+ import_jsx_runtime8 = __toESM(require_jsx_runtime());
647
+ import_react6 = __toESM(require_react());
467
648
  import_webrtc_client = __toESM(require_webrtc_client());
468
- inline_view_default3 = InlineView6;
649
+ inline_view_default3 = InlineView5;
469
650
  }
470
651
  });
471
652
 
@@ -474,17 +655,92 @@ var inline_view_exports4 = {};
474
655
  __export(inline_view_exports4, {
475
656
  default: () => inline_view_default4
476
657
  });
477
- function InlineView7({ state, config }) {
478
- const connected = (0, import_jsx_runtime10.jsx)("div", { className: "active text-green-300 dark:text-green-300", children: "Connected and publishing" });
479
- const disconnected = (0, import_jsx_runtime10.jsxs)("div", { className: "inactive text-orange-300 dark:text-orange-300", children: ["Disconnected ", state.connectRetries > 0 ? `- retrying(${state.connectRetries})` : ""] });
480
- return (0, import_jsx_runtime10.jsx)("div", { className: "rtmp-output", id: `rtmp-output-${config.id}`, children: state.connected ? connected : disconnected });
658
+ function InlineView6({ state, config }) {
659
+ const connected = (0, import_jsx_runtime9.jsx)("div", { className: "active text-green-500 dark:text-green-300", children: "Connected and publishing" });
660
+ const disconnected = (0, import_jsx_runtime9.jsxs)("div", { className: "inactive text-orange-500 dark:text-orange-300", children: ["Disconnected ", state.connectRetries > 0 ? `- retrying(${state.connectRetries})` : ""] });
661
+ return (0, import_jsx_runtime9.jsx)("div", { className: "rtmp-output", id: `rtmp-output-${config.id}`, children: state.connected ? connected : disconnected });
481
662
  }
482
- var import_jsx_runtime10, inline_view_default4;
663
+ var import_jsx_runtime9, inline_view_default4;
483
664
  var init_inline_view4 = __esm({
484
665
  "build/output.rtmp/inline-view.js"() {
485
666
  "use strict";
486
- import_jsx_runtime10 = __toESM(require_jsx_runtime());
487
- inline_view_default4 = InlineView7;
667
+ import_jsx_runtime9 = __toESM(require_jsx_runtime());
668
+ inline_view_default4 = InlineView6;
669
+ }
670
+ });
671
+
672
+ // ../../node_modules/@norskvideo/norsk-studio/lib/shared/util.js
673
+ var require_util = __commonJS({
674
+ "../../node_modules/@norskvideo/norsk-studio/lib/shared/util.js"(exports) {
675
+ "use strict";
676
+ Object.defineProperty(exports, "__esModule", { value: true });
677
+ exports.nodeApiUrl = nodeApiUrl;
678
+ exports.componentApiUrl = componentApiUrl;
679
+ exports.findObjectByType = findObjectByType;
680
+ exports.getObjectByType = getObjectByType;
681
+ exports.getObjectByPath = getObjectByPath;
682
+ exports.displayNodeId = displayNodeId;
683
+ exports.assertUnreachable = assertUnreachable15;
684
+ exports.waitForCondition = waitForCondition;
685
+ function nodeApiUrl(nodeId) {
686
+ return new URL(`${document.location.protocol}//${document.location.host}/live/api/${encodeURIComponent(nodeId)}`);
687
+ }
688
+ function componentApiUrl(indentifier) {
689
+ return new URL(`${document.location.protocol}//${document.location.host}/components/${encodeURIComponent(indentifier)}`);
690
+ }
691
+ function findObjectByType(potentials, t) {
692
+ for (const v of potentials) {
693
+ const potential = getObjectByType(v, t);
694
+ if (potential) {
695
+ return potential;
696
+ }
697
+ }
698
+ return null;
699
+ }
700
+ function getObjectByType(acc, t) {
701
+ const paths = t.split(".");
702
+ return getObjectByPath(acc, paths);
703
+ }
704
+ function getObjectByPath(acc, paths) {
705
+ if (paths.length == 0) {
706
+ return acc;
707
+ }
708
+ if (!acc) {
709
+ return null;
710
+ }
711
+ const head = paths[0];
712
+ const tail = paths.slice(1);
713
+ const result2 = Object.entries(acc).find(([k, _]) => k == head);
714
+ if (!result2) {
715
+ return null;
716
+ }
717
+ return getObjectByPath(result2[1], tail);
718
+ }
719
+ function displayNodeId(id, document2) {
720
+ if (!id) {
721
+ return "";
722
+ }
723
+ return document2.components[id]?.config?.displayName ?? id;
724
+ }
725
+ function assertUnreachable15(_) {
726
+ throw new Error("Didn't expect to get here");
727
+ }
728
+ async function waitForCondition(condition, timeout, interval) {
729
+ return new Promise((r, f) => {
730
+ const i = setInterval(async () => {
731
+ const success = await condition();
732
+ if (success) {
733
+ clearInterval(i);
734
+ clearTimeout(t);
735
+ r();
736
+ }
737
+ }, interval ?? 10);
738
+ const t = setTimeout(() => {
739
+ clearInterval(i);
740
+ f(new Error("Timeout on condition wait"));
741
+ }, timeout ?? 2e3);
742
+ });
743
+ }
488
744
  }
489
745
  });
490
746
 
@@ -493,49 +749,51 @@ var inline_view_exports5 = {};
493
749
  __export(inline_view_exports5, {
494
750
  default: () => inline_view_default5
495
751
  });
496
- function InlineView8({ state }) {
752
+ function InlineView7({ state }) {
497
753
  if (!state.previous)
498
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
499
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: state.previous.allStreams.map((s, i) => {
754
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
755
+ const format = (stat) => Math.floor(stat).toLocaleString("en-US", { maximumFractionDigits: 0 });
756
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: state.previous.allStreams.map((s, i) => {
500
757
  const metaCase = s.metadata.case;
501
758
  switch (metaCase) {
502
759
  case "audio":
503
- return (0, import_jsx_runtime11.jsxs)("div", { children: [(0, import_jsx_runtime11.jsxs)("div", { children: ["StreamKey: ", streamKey(s.streamKey)] }), (0, import_jsx_runtime11.jsxs)("div", { children: ["Bitrate: ", Math.floor(s.bitrate), "bps"] })] }, i);
760
+ return (0, import_jsx_runtime10.jsxs)("div", { children: [(0, import_jsx_runtime10.jsxs)("div", { children: ["StreamKey: ", streamKey(s.streamKey)] }), (0, import_jsx_runtime10.jsxs)("div", { children: ["Bitrate: ", format(s.bitrate), "bps"] })] }, i);
504
761
  case "video":
505
- return (0, import_jsx_runtime11.jsxs)("div", { children: [(0, import_jsx_runtime11.jsxs)("div", { children: ["StreamKey: ", streamKey(s.streamKey)] }), (0, import_jsx_runtime11.jsxs)("div", { children: ["Bitrate: ", Math.floor(s.bitrate), "bps"] })] }, i);
762
+ return (0, import_jsx_runtime10.jsxs)("div", { children: [(0, import_jsx_runtime10.jsxs)("div", { children: ["StreamKey: ", streamKey(s.streamKey)] }), (0, import_jsx_runtime10.jsxs)("div", { children: ["Bitrate: ", format(s.bitrate), "bps"] })] }, i);
506
763
  case "ancillary":
507
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
764
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
508
765
  case "subtitle":
509
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
766
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
510
767
  case "playlist":
511
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
768
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
512
769
  case void 0:
513
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
770
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
514
771
  default:
515
- assertUnreachable6(metaCase);
772
+ assertUnreachable7(metaCase);
516
773
  }
517
774
  }) });
518
775
  }
519
776
  function streamKey(streamKey2) {
520
777
  return streamKey2.streamId.toString();
521
778
  }
522
- var import_jsx_runtime11, inline_view_default5;
779
+ var import_jsx_runtime10, inline_view_default5;
523
780
  var init_inline_view5 = __esm({
524
781
  "build/output.statistics/inline-view.js"() {
525
782
  "use strict";
526
- import_jsx_runtime11 = __toESM(require_jsx_runtime());
783
+ import_jsx_runtime10 = __toESM(require_jsx_runtime());
527
784
  init_info();
528
- inline_view_default5 = InlineView8;
785
+ inline_view_default5 = InlineView7;
529
786
  }
530
787
  });
531
788
 
532
789
  // build/output.statistics/info.js
533
790
  function info_default11({ defineComponent, All }) {
534
- const InlineView13 = import_react11.default.lazy(async () => Promise.resolve().then(() => (init_inline_view5(), inline_view_exports5)));
791
+ const InlineView13 = import_react10.default.lazy(async () => Promise.resolve().then(() => (init_inline_view5(), inline_view_exports5)));
535
792
  return defineComponent({
536
793
  identifier: "output.statistics",
537
794
  category: "output",
538
795
  name: "Statistics",
796
+ description: "This component accepts multiple media streams, captures and reports metrics or statistical data related to the media streams.",
539
797
  subscription: {
540
798
  // No validation required
541
799
  accepts: {
@@ -555,7 +813,7 @@ function info_default11({ defineComponent, All }) {
555
813
  state.previous = ev.summary;
556
814
  break;
557
815
  default:
558
- assertUnreachable6(evType);
816
+ assertUnreachable7(evType);
559
817
  }
560
818
  return { ...state };
561
819
  },
@@ -566,14 +824,132 @@ function info_default11({ defineComponent, All }) {
566
824
  }
567
825
  });
568
826
  }
569
- function assertUnreachable6(_) {
827
+ function assertUnreachable7(_) {
570
828
  throw new Error("Didn't expect to get here");
571
829
  }
572
- var import_react11;
830
+ var import_react10;
573
831
  var init_info = __esm({
574
832
  "build/output.statistics/info.js"() {
575
833
  "use strict";
834
+ import_react10 = __toESM(require_react());
835
+ }
836
+ });
837
+
838
+ // build/output.whep/inline-view.js
839
+ var inline_view_exports6 = {};
840
+ __export(inline_view_exports6, {
841
+ default: () => inline_view_default6
842
+ });
843
+ function InlineView8({ state, config, raise }) {
844
+ const url = state.url;
845
+ const id = config.id;
846
+ const [showPreview, setShowPreview] = (0, import_react11.useState)(config.showPreview ?? true);
847
+ const [client, setClient] = (0, import_react11.useState)(null);
848
+ const createClient = (url2) => {
849
+ const newClient = new import_webrtc_client2.WhepClient({
850
+ url: url2,
851
+ container: document.getElementById(`whep-${id}`) ?? void 0
852
+ });
853
+ newClient.start().catch(console.error);
854
+ return newClient;
855
+ };
856
+ const cleanupClient = (client2) => {
857
+ client2.outputVideoTracks.forEach((track) => track.stop());
858
+ if (client2.outputAudioTrack) {
859
+ client2.outputAudioTrack.stop();
860
+ }
861
+ client2.videoElements.forEach((video) => {
862
+ video.srcObject = null;
863
+ video.remove();
864
+ });
865
+ };
866
+ (0, import_react11.useEffect)(() => {
867
+ if (!url || !showPreview) {
868
+ if (client) {
869
+ cleanupClient(client);
870
+ setClient(null);
871
+ }
872
+ return;
873
+ }
874
+ const newClient = createClient(url);
875
+ setClient(newClient);
876
+ return () => {
877
+ cleanupClient(newClient);
878
+ };
879
+ }, [state.url, showPreview]);
880
+ (0, import_react11.useEffect)(() => {
881
+ setShowPreview(config.showPreview ?? true);
882
+ }, [config.showPreview]);
883
+ raise && (0, import_react11.useEffect)(raise, []);
884
+ if (!url)
885
+ return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: "..." });
886
+ const videoStyles = `
887
+ #whep-${id} video::-webkit-media-controls-play-button {
888
+ display: none;
889
+ }
890
+ `;
891
+ return (0, import_jsx_runtime11.jsxs)("div", { className: "whep-container", children: [(0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, import_jsx_runtime11.jsx)("input", { type: "checkbox", id: `video-toggle-${id}`, checked: showPreview, onChange: (e) => setShowPreview(e.target.checked), className: "h-4 w-4" }), (0, import_jsx_runtime11.jsx)("label", { htmlFor: `video-toggle-${id}`, className: "text-sm", children: "Show Preview" })] }), showPreview ? (0, import_jsx_runtime11.jsx)("div", { className: "whep-video", id: `whep-${id}`, children: (0, import_jsx_runtime11.jsx)("style", { children: videoStyles }) }) : (0, import_jsx_runtime11.jsx)("div", { className: "whep-video bg-black flex items-center justify-center text-white h-full", children: "Preview turned off" })] });
892
+ }
893
+ var import_jsx_runtime11, import_react11, import_webrtc_client2, inline_view_default6;
894
+ var init_inline_view6 = __esm({
895
+ "build/output.whep/inline-view.js"() {
896
+ "use strict";
897
+ import_jsx_runtime11 = __toESM(require_jsx_runtime());
576
898
  import_react11 = __toESM(require_react());
899
+ import_webrtc_client2 = __toESM(require_webrtc_client());
900
+ inline_view_default6 = InlineView8;
901
+ }
902
+ });
903
+
904
+ // build/processor.browserOverlay/summary-view.js
905
+ var summary_view_exports3 = {};
906
+ __export(summary_view_exports3, {
907
+ default: () => summary_view_default3
908
+ });
909
+ function SummaryView5({ state, sendCommand }) {
910
+ const [url, setUrl] = (0, import_react13.useState)(state.currentUrl);
911
+ const [enabled, setEnabled] = (0, import_react13.useState)(state.enabled);
912
+ const stateChanged = (0, import_react13.useMemo)(() => {
913
+ return url !== state.currentUrl || enabled !== state.enabled;
914
+ }, [url, enabled]);
915
+ const buttonClass = "mt-2 mb-5 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800";
916
+ return (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-3 mb-5", children: [(0, import_jsx_runtime12.jsx)("h2", { className: "text-xl font-bold text-gray-900 dark:text-white", children: "Controls" }), (0, import_jsx_runtime12.jsxs)("div", { className: "mb-5", children: [(0, import_jsx_runtime12.jsx)("label", { htmlFor: "url", className: "mb-2 mr-2 text-sm font-medium text-gray-900 dark:text-white", children: "URL" }), (0, import_jsx_runtime12.jsx)("input", { type: "email", id: "url", className: "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500", value: url, onChange: (e) => setUrl(e.target.value), required: true })] }), (0, import_jsx_runtime12.jsx)("div", { className: "mb-5", children: (0, import_jsx_runtime12.jsxs)("label", { className: "inline-flex items-center cursor-pointer", children: [(0, import_jsx_runtime12.jsx)("span", { className: "me-3 text-sm font-medium text-gray-900 dark:text-gray-300", children: "Enabled" }), (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", checked: enabled, onChange: (e) => setEnabled(e.target.checked), className: "sr-only peer" }), (0, import_jsx_runtime12.jsx)("div", { className: "relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600" })] }) }), (0, import_jsx_runtime12.jsx)("button", { type: "button", className: `${buttonClass} ${!stateChanged ? "opacity-50 cursor-not-allowed" : ""}`, disabled: !stateChanged, onClick: () => {
917
+ if (url !== state.currentUrl) {
918
+ sendCommand({ type: "change-url", url });
919
+ }
920
+ if (enabled !== state.enabled) {
921
+ if (enabled) {
922
+ sendCommand({ type: "enable" });
923
+ } else {
924
+ sendCommand({ type: "disable" });
925
+ }
926
+ }
927
+ }, children: "Commit" })] });
928
+ }
929
+ var import_jsx_runtime12, import_react13, summary_view_default3;
930
+ var init_summary_view3 = __esm({
931
+ "build/processor.browserOverlay/summary-view.js"() {
932
+ "use strict";
933
+ import_jsx_runtime12 = __toESM(require_jsx_runtime());
934
+ import_react13 = __toESM(require_react());
935
+ summary_view_default3 = SummaryView5;
936
+ }
937
+ });
938
+
939
+ // build/processor.browserOverlay/inline-view.js
940
+ var inline_view_exports7 = {};
941
+ __export(inline_view_exports7, {
942
+ default: () => inline_view_default7
943
+ });
944
+ function InlineView9({ state, config }) {
945
+ return (0, import_jsx_runtime13.jsx)("div", { id: `browser-overlay-${config.id}`, children: (0, import_jsx_runtime13.jsxs)("div", { className: "w-64 grid grid-cols-[min-content,1fr] gap-2", children: [(0, import_jsx_runtime13.jsx)("div", { children: "URL:" }), (0, import_jsx_runtime13.jsx)("div", { className: "truncate", children: state.currentUrl }), (0, import_jsx_runtime13.jsx)("div", { children: "Enabled:" }), (0, import_jsx_runtime13.jsx)("div", { children: (0, import_jsx_runtime13.jsxs)("label", { className: "inline-flex items-center cursor-pointer", children: [(0, import_jsx_runtime13.jsx)("input", { type: "checkbox", checked: state.enabled, disabled: true, className: "sr-only peer" }), (0, import_jsx_runtime13.jsx)("div", { className: "relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600" })] }) })] }) });
946
+ }
947
+ var import_jsx_runtime13, inline_view_default7;
948
+ var init_inline_view7 = __esm({
949
+ "build/processor.browserOverlay/inline-view.js"() {
950
+ "use strict";
951
+ import_jsx_runtime13 = __toESM(require_jsx_runtime());
952
+ inline_view_default7 = InlineView9;
577
953
  }
578
954
  });
579
955
 
@@ -583,15 +959,15 @@ __export(source_selection_exports, {
583
959
  default: () => source_selection_default
584
960
  });
585
961
  function OrderInput(props) {
586
- (0, import_react12.useEffect)(() => {
962
+ (0, import_react15.useEffect)(() => {
587
963
  props.onChanged(props.defaultValue ?? []);
588
964
  }, [props.defaultValue]);
589
- const [value, setValue] = (0, import_react12.useState)(props.defaultValue ?? []);
965
+ const [value, setValue] = (0, import_react15.useState)(props.defaultValue ?? []);
590
966
  if (value.length == 0) {
591
- return (0, import_jsx_runtime12.jsx)("p", { className: "node-editor-helper-text", children: "Sources will appear here when subscriptions have been added to this node" });
967
+ return (0, import_jsx_runtime14.jsx)("p", { className: "node-editor-helper-text", children: "Sources will appear here when subscriptions have been added to this node" });
592
968
  } else {
593
- return (0, import_jsx_runtime12.jsx)("div", { id: props.id, children: (0, import_jsx_runtime12.jsx)("ul", { children: value.map((v, ix) => {
594
- return (0, import_jsx_runtime12.jsxs)("li", { className: "flex", children: [(0, import_jsx_runtime12.jsx)("span", { className: "node-editor-label flex-grow", children: v }), ix == 0 ? (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, {}) : (0, import_jsx_runtime12.jsx)("svg", { onClick: moveUp(ix), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18" }) }), ix == value.length - 1 ? (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, {}) : (0, import_jsx_runtime12.jsx)("svg", { onClick: moveDown(ix), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime12.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3" }) })] }, v);
969
+ return (0, import_jsx_runtime14.jsx)("div", { id: props.id, children: (0, import_jsx_runtime14.jsx)("ul", { children: value.map((v, ix) => {
970
+ return (0, import_jsx_runtime14.jsxs)("li", { className: "flex", children: [(0, import_jsx_runtime14.jsx)("span", { className: "node-editor-label flex-grow", children: v }), ix == 0 ? (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, {}) : (0, import_jsx_runtime14.jsx)("svg", { onClick: moveUp(ix), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime14.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18" }) }), ix == value.length - 1 ? (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, {}) : (0, import_jsx_runtime14.jsx)("svg", { onClick: moveDown(ix), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime14.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3" }) })] }, v);
595
971
  }) }) });
596
972
  }
597
973
  function moveUp(ix) {
@@ -613,146 +989,33 @@ function OrderInput(props) {
613
989
  };
614
990
  }
615
991
  }
616
- var import_jsx_runtime12, import_react12, source_selection_default;
992
+ var import_jsx_runtime14, import_react15, source_selection_default;
617
993
  var init_source_selection = __esm({
618
994
  "build/processor.cascadingSwitch/source-selection.js"() {
619
995
  "use strict";
620
- import_jsx_runtime12 = __toESM(require_jsx_runtime());
621
- import_react12 = __toESM(require_react());
996
+ import_jsx_runtime14 = __toESM(require_jsx_runtime());
997
+ import_react15 = __toESM(require_react());
622
998
  source_selection_default = OrderInput;
623
999
  }
624
1000
  });
625
1001
 
626
1002
  // build/processor.cascadingSwitch/inline-view.js
627
- var inline_view_exports6 = {};
628
- __export(inline_view_exports6, {
629
- default: () => inline_view_default6
1003
+ var inline_view_exports8 = {};
1004
+ __export(inline_view_exports8, {
1005
+ default: () => inline_view_default8
630
1006
  });
631
- function InlineView9({ state, config }) {
632
- return (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [(0, import_jsx_runtime13.jsx)("h5", { children: "Sources" }), (0, import_jsx_runtime13.jsxs)("ul", { children: [config.sources.map((s, i) => state.activeSource == s ? (0, import_jsx_runtime13.jsxs)("li", { className: activeClasses, children: [s, " <--"] }, i) : state.availableSources.includes(s) ? (0, import_jsx_runtime13.jsxs)("li", { className: availableClasses, children: [s, " (available)"] }, i) : (0, import_jsx_runtime13.jsxs)("li", { className: inactiveClasses, children: [s, " (inactive)"] }, i)), (0, import_jsx_runtime13.jsx)("li", { className: state.activeSource == "fallback" ? activeClasses : availableClasses, children: "fallback" }, "fallback")] })] });
1007
+ function InlineView11({ state, config }) {
1008
+ return (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [(0, import_jsx_runtime15.jsx)("h5", { children: "Sources" }), (0, import_jsx_runtime15.jsxs)("ul", { children: [config.sources.map((s, i) => state.activeSource == s ? (0, import_jsx_runtime15.jsxs)("li", { className: activeClasses, children: [s, " <--"] }, i) : state.availableSources.includes(s) ? (0, import_jsx_runtime15.jsxs)("li", { className: availableClasses, children: [s, " (available)"] }, i) : (0, import_jsx_runtime15.jsxs)("li", { className: inactiveClasses, children: [s, " (inactive)"] }, i)), (0, import_jsx_runtime15.jsx)("li", { className: state.activeSource == "fallback" ? activeClasses : availableClasses, children: "fallback" }, "fallback")] })] });
633
1009
  }
634
- var import_jsx_runtime13, activeClasses, availableClasses, inactiveClasses, inline_view_default6;
635
- var init_inline_view6 = __esm({
1010
+ var import_jsx_runtime15, activeClasses, availableClasses, inactiveClasses, inline_view_default8;
1011
+ var init_inline_view8 = __esm({
636
1012
  "build/processor.cascadingSwitch/inline-view.js"() {
637
- "use strict";
638
- import_jsx_runtime13 = __toESM(require_jsx_runtime());
639
- activeClasses = "active text-green-300 dark:text-green-300";
640
- availableClasses = "available text-green-300 dark:text-green-300";
641
- inactiveClasses = "inactive text-orange-300 dark:text-orange-300";
642
- inline_view_default6 = InlineView9;
643
- }
644
- });
645
-
646
- // build/processor.dynamicBug/bug-selection.js
647
- var bug_selection_exports = {};
648
- __export(bug_selection_exports, {
649
- default: () => bug_selection_default
650
- });
651
- function BugSelection(props) {
652
- const [loading, setLoading] = (0, import_react13.useState)(true);
653
- (0, import_react13.useEffect)(() => {
654
- const fn = async () => {
655
- const result2 = await fetch("components/processor.dynamicBug/bugs");
656
- if (result2.ok && result2.body) {
657
- const bugs2 = await result2.json();
658
- setBugs(bugs2);
659
- setLoading(false);
660
- if (props.defaultValue)
661
- props.onChanged(props.defaultValue);
662
- } else {
663
- const text = await result2.text();
664
- throw new Error(text);
665
- }
666
- };
667
- fn().catch(console.error);
668
- }, []);
669
- const [bugs, setBugs] = (0, import_react13.useState)([]);
670
- if (loading) {
671
- return (0, import_jsx_runtime14.jsx)("div", { children: "Loading.." });
672
- }
673
- if (bugs.length == 0) {
674
- return (0, import_jsx_runtime14.jsx)("div", { children: "No bugs loaded" });
675
- }
676
- return (0, import_jsx_runtime14.jsx)("div", { children: (0, import_jsx_runtime14.jsxs)("select", { defaultValue: props.defaultValue, className: `node-editor-select-input`, id: props.id, onChange: myOnChange, onBlur: myOnChange, children: [(0, import_jsx_runtime14.jsx)("option", { value: "", children: "---" }, "empty"), bugs.map((o, i) => {
677
- return (0, import_jsx_runtime14.jsx)("option", { value: o, children: o }, i);
678
- })] }) });
679
- function myOnChange(e) {
680
- props.onChanged(e.target.value);
681
- }
682
- }
683
- var import_jsx_runtime14, import_react13, bug_selection_default;
684
- var init_bug_selection = __esm({
685
- "build/processor.dynamicBug/bug-selection.js"() {
686
- "use strict";
687
- import_jsx_runtime14 = __toESM(require_jsx_runtime());
688
- import_react13 = __toESM(require_react());
689
- bug_selection_default = BugSelection;
690
- }
691
- });
692
-
693
- // build/processor.dynamicBug/summary-view.js
694
- var summary_view_exports3 = {};
695
- __export(summary_view_exports3, {
696
- default: () => summary_view_default3
697
- });
698
- function SummaryView5({ state, sendCommand, httpApi }) {
699
- const [bug, setBug] = (0, import_react14.useState)(state.activeBug?.file);
700
- const [position, setPosition] = (0, import_react14.useState)(state.activeBug?.position);
701
- const [bugs, setBugs] = (0, import_react14.useState)([]);
702
- const [fileToUpload, setFileToUpload] = (0, import_react14.useState)(void 0);
703
- async function updateBugs() {
704
- const result2 = await fetch("components/processor.dynamicBug/bugs");
705
- if (result2.ok && result2.body) {
706
- const bugs2 = await result2.json();
707
- setBugs(bugs2);
708
- } else {
709
- const text = await result2.text();
710
- throw new Error(text);
711
- }
712
- }
713
- (0, import_react14.useEffect)(() => {
714
- const fn = async () => {
715
- await updateBugs();
716
- };
717
- fn().catch(console.error);
718
- }, []);
719
- function onFileChange(e) {
720
- if (e.target.files?.[0])
721
- setFileToUpload(e.target.files[0]);
722
- }
723
- return (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [(0, import_jsx_runtime15.jsx)("h2", { children: "Controls" }), (0, import_jsx_runtime15.jsx)("label", { htmlFor: "select-preview", className: "mt-2", children: "Source" }), (0, import_jsx_runtime15.jsxs)("select", { id: "select-bug", className: "mt-2 node-editor-select-input", onChange: (e) => {
724
- setBug(e.currentTarget.value === "" ? void 0 : e.currentTarget.value);
725
- }, children: [(0, import_jsx_runtime15.jsx)("option", { value: "", selected: bug === void 0, children: "---" }), (0, import_jsx_runtime15.jsx)("option", { value: "new", selected: bug === "new", children: "New" }), bugs.map((s, i) => (0, import_jsx_runtime15.jsx)("option", { selected: bug == s, value: s, children: s }, i))] }), (0, import_jsx_runtime15.jsx)("form", { style: { display: bug === "new" ? "block" : "none" }, onSubmit: (e) => e.preventDefault(), children: (0, import_jsx_runtime15.jsx)("input", { type: "file", id: "file", name: "filename", onChange: onFileChange }) }), (0, import_jsx_runtime15.jsxs)("select", { style: { display: bug ? "block" : "none" }, id: "select-position", className: "mt-2 node-editor-select-input", onChange: (e) => {
726
- setPosition(e.currentTarget.value);
727
- }, children: [(0, import_jsx_runtime15.jsx)("option", { value: "topleft", selected: position === "topleft", children: "Top Left" }), (0, import_jsx_runtime15.jsx)("option", { value: "topright", selected: position === "topright", children: "Top Right" }), (0, import_jsx_runtime15.jsx)("option", { value: "bottomleft", selected: position === "bottomleft", children: "Bottom Left" }), (0, import_jsx_runtime15.jsx)("option", { value: "bottomright", selected: position === "bottomright", children: "Bottom Right" })] }), bug != state.activeBug?.file || position != state.activeBug?.position || fileToUpload ? (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "mt-2 mb-2 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800", onClick: async (e) => {
728
- e.preventDefault();
729
- if (fileToUpload && bug === "new") {
730
- const form = new FormData();
731
- const url = httpApi.toString() + "/bugs";
732
- form.append("file", fileToUpload);
733
- await fetch(url, {
734
- method: "POST",
735
- body: form
736
- });
737
- setTimeout(async () => {
738
- await updateBugs();
739
- sendCommand({ type: "change-bug", file: fileToUpload.name, position });
740
- setBug(fileToUpload.name);
741
- setFileToUpload(void 0);
742
- return;
743
- }, 500);
744
- } else {
745
- sendCommand({ type: "change-bug", file: bug, position });
746
- }
747
- }, children: "Commit" }) : (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, {})] });
748
- }
749
- var import_jsx_runtime15, import_react14, summary_view_default3;
750
- var init_summary_view3 = __esm({
751
- "build/processor.dynamicBug/summary-view.js"() {
752
1013
  "use strict";
753
1014
  import_jsx_runtime15 = __toESM(require_jsx_runtime());
754
- import_react14 = __toESM(require_react());
755
- summary_view_default3 = SummaryView5;
1015
+ activeClasses = "active text-green-500 dark:text-green-300";
1016
+ availableClasses = "available text-green-500 dark:text-green-300";
1017
+ inactiveClasses = "inactive text-orange-500 dark:text-orange-300";
1018
+ inline_view_default8 = InlineView11;
756
1019
  }
757
1020
  });
758
1021
 
@@ -762,7 +1025,7 @@ __export(rung_view_exports, {
762
1025
  default: () => rung_view_default
763
1026
  });
764
1027
  function rung_view_default(rung) {
765
- return (0, import_jsx_runtime16.jsx)("div", { className: "", children: rung.name });
1028
+ return (0, import_jsx_runtime16.jsx)("div", { className: "text-gray-900 dark:text-white", children: rung.name });
766
1029
  }
767
1030
  var import_jsx_runtime16;
768
1031
  var init_rung_view = __esm({
@@ -791,7 +1054,7 @@ function CodecEditor(props) {
791
1054
  target.style.height = target.scrollHeight + "px";
792
1055
  }
793
1056
  }, []);
794
- return (0, import_jsx_runtime17.jsx)("textarea", { ref: textAreaRef, className: "w-full min-h-fit dark:text-white dark:bg-black", onChange: (e) => {
1057
+ return (0, import_jsx_runtime17.jsx)("textarea", { ref: textAreaRef, className: "w-full min-h-fit bg-white text-gray-900 dark:text-white dark:bg-black", onChange: (e) => {
795
1058
  const target = e.currentTarget;
796
1059
  try {
797
1060
  const codec = JSON.parse(target.value);
@@ -816,7 +1079,7 @@ __export(codec_view_exports, {
816
1079
  default: () => CodecEditor2
817
1080
  });
818
1081
  function CodecEditor2(props) {
819
- return (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [props.width, "x", props.height] });
1082
+ return (0, import_jsx_runtime18.jsxs)("div", { className: "text-gray-900 dark:text-white", children: [props.width, "x", props.height] });
820
1083
  }
821
1084
  var import_jsx_runtime18;
822
1085
  var init_codec_view = __esm({
@@ -826,6 +1089,384 @@ var init_codec_view = __esm({
826
1089
  }
827
1090
  });
828
1091
 
1092
+ // build/processor.onscreenGraphic/image-selection.js
1093
+ var image_selection_exports = {};
1094
+ __export(image_selection_exports, {
1095
+ default: () => image_selection_default
1096
+ });
1097
+ function GraphicSelection(props) {
1098
+ const [loading, setLoading] = (0, import_react18.useState)(true);
1099
+ (0, import_react18.useEffect)(() => {
1100
+ const fn = async () => {
1101
+ const result2 = await fetch("components/processor.onscreenGraphic/graphics");
1102
+ if (result2.ok && result2.body) {
1103
+ const graphics = await result2.json();
1104
+ setGraphics(graphics);
1105
+ setLoading(false);
1106
+ if (props.defaultValue)
1107
+ props.onChanged(props.defaultValue);
1108
+ } else {
1109
+ const text = await result2.text();
1110
+ throw new Error(text);
1111
+ }
1112
+ };
1113
+ fn().catch(console.error);
1114
+ }, []);
1115
+ const [graphcs, setGraphics] = (0, import_react18.useState)([]);
1116
+ if (loading) {
1117
+ return (0, import_jsx_runtime19.jsx)("div", { children: "Loading.." });
1118
+ }
1119
+ if (graphcs.length == 0) {
1120
+ return (0, import_jsx_runtime19.jsx)("div", { children: "No graphics loaded" });
1121
+ }
1122
+ return (0, import_jsx_runtime19.jsx)("div", { children: (0, import_jsx_runtime19.jsxs)("select", { defaultValue: props.defaultValue, className: `node-editor-select-input`, id: props.id, onChange: myOnChange, onBlur: myOnChange, children: [(0, import_jsx_runtime19.jsx)("option", { value: "", children: "---" }, "empty"), graphcs.map((o, i) => {
1123
+ return (0, import_jsx_runtime19.jsx)("option", { value: o, children: o }, i);
1124
+ })] }) });
1125
+ function myOnChange(e) {
1126
+ props.onChanged(e.target.value);
1127
+ }
1128
+ }
1129
+ var import_jsx_runtime19, import_react18, image_selection_default;
1130
+ var init_image_selection = __esm({
1131
+ "build/processor.onscreenGraphic/image-selection.js"() {
1132
+ "use strict";
1133
+ import_jsx_runtime19 = __toESM(require_jsx_runtime());
1134
+ import_react18 = __toESM(require_react());
1135
+ image_selection_default = GraphicSelection;
1136
+ }
1137
+ });
1138
+
1139
+ // build/processor.onscreenGraphic/summary-view.js
1140
+ var summary_view_exports4 = {};
1141
+ __export(summary_view_exports4, {
1142
+ default: () => summary_view_default4
1143
+ });
1144
+ function SummaryView7({ state, sendCommand, urls }) {
1145
+ const [graphic, setGraphic] = (0, import_react19.useState)(state.activeGraphic?.file);
1146
+ const [position, setPosition] = (0, import_react19.useState)(state.activeGraphic?.position ?? { type: "named", position: "topleft" });
1147
+ const [graphics, setGraphics] = (0, import_react19.useState)([]);
1148
+ const [fileToUpload, setFileToUpload] = (0, import_react19.useState)(void 0);
1149
+ const [showFileInput, setShowFileInput] = (0, import_react19.useState)(false);
1150
+ const [showUploadButton, setShowUploadButton] = (0, import_react19.useState)(false);
1151
+ const [uploadStatus, setUploadStatus] = (0, import_react19.useState)({ success: false, message: null });
1152
+ const [showDeleteDropdown, setShowDeleteDropdown] = (0, import_react19.useState)(false);
1153
+ const [graphicToDelete, setGraphicToDelete] = (0, import_react19.useState)("");
1154
+ const updateGraphics = (0, import_react19.useCallback)(async () => {
1155
+ try {
1156
+ const result2 = await fetch(`${urls.componentUrl}/graphics`);
1157
+ if (result2.ok) {
1158
+ const newGraphics = await result2.json();
1159
+ setGraphics(newGraphics);
1160
+ } else {
1161
+ throw new Error(await result2.text());
1162
+ }
1163
+ } catch (error) {
1164
+ console.error("Failed to update graphics:", error);
1165
+ setUploadStatus({
1166
+ success: false,
1167
+ message: "Failed to update graphic list."
1168
+ });
1169
+ }
1170
+ }, [urls.componentUrl]);
1171
+ (0, import_react19.useEffect)(() => {
1172
+ updateGraphics().catch(console.error);
1173
+ }, [updateGraphics]);
1174
+ const onFileChange = (e) => {
1175
+ const file = e.target.files?.[0];
1176
+ setFileToUpload(file);
1177
+ setShowUploadButton(!!file);
1178
+ setUploadStatus({ success: false, message: null });
1179
+ };
1180
+ const uploadFileHandle = async () => {
1181
+ if (!fileToUpload)
1182
+ return;
1183
+ try {
1184
+ const form = new FormData();
1185
+ form.append("file", fileToUpload);
1186
+ const response = await fetch(`${urls.componentUrl}/graphics`, {
1187
+ method: "POST",
1188
+ body: form
1189
+ });
1190
+ if (response.status === 409) {
1191
+ const errorData = await response.json();
1192
+ setUploadStatus({
1193
+ success: false,
1194
+ message: `${errorData.error}. Delete the existing graphic first if you want to replace it.`
1195
+ });
1196
+ } else if (!response.ok) {
1197
+ throw new Error("Upload failed");
1198
+ } else {
1199
+ setFileToUpload(void 0);
1200
+ setShowFileInput(false);
1201
+ setUploadStatus({
1202
+ success: true,
1203
+ message: "Graphic uploaded successfully!"
1204
+ });
1205
+ await updateGraphics();
1206
+ }
1207
+ } catch (error) {
1208
+ console.error("Failed to upload file:", error);
1209
+ setUploadStatus({ success: false, message: "Failed to upload graphic." });
1210
+ }
1211
+ setTimeout(() => setUploadStatus({ success: false, message: null }), 5e3);
1212
+ };
1213
+ const uploadFile = () => {
1214
+ void uploadFileHandle();
1215
+ };
1216
+ const deleteBugHandle = async () => {
1217
+ if (!graphicToDelete)
1218
+ return;
1219
+ try {
1220
+ console.log(`${urls.componentUrl}`);
1221
+ const response = await fetch(`${urls.componentUrl}/graphic`, {
1222
+ method: "DELETE",
1223
+ headers: {
1224
+ "Content-Type": "application/json"
1225
+ },
1226
+ body: JSON.stringify({ filename: graphicToDelete })
1227
+ });
1228
+ if (response.ok) {
1229
+ setUploadStatus({
1230
+ success: true,
1231
+ message: "Graphic deleted successfully!"
1232
+ });
1233
+ await updateGraphics();
1234
+ if (graphic === graphicToDelete) {
1235
+ setGraphic(void 0);
1236
+ sendCommand({
1237
+ type: "change-graphic",
1238
+ file: void 0,
1239
+ position: void 0
1240
+ });
1241
+ }
1242
+ setGraphicToDelete("");
1243
+ setShowDeleteDropdown(false);
1244
+ } else {
1245
+ const errorData = await response.json();
1246
+ setUploadStatus({
1247
+ success: false,
1248
+ message: errorData.error || "Failed to delete graphic"
1249
+ });
1250
+ }
1251
+ } catch (error) {
1252
+ console.error("Failed to delete graphic:", error);
1253
+ setUploadStatus({ success: false, message: "Failed to delete graphic" });
1254
+ }
1255
+ setTimeout(() => setUploadStatus({ success: false, message: null }), 3e3);
1256
+ };
1257
+ const deleteBug = () => {
1258
+ void deleteBugHandle();
1259
+ };
1260
+ const eqPosition = (l, r) => {
1261
+ if (!r)
1262
+ return false;
1263
+ if (l.type === "named") {
1264
+ if (r.type !== "named")
1265
+ return false;
1266
+ return l.position === r.position;
1267
+ }
1268
+ if (r.type === "named")
1269
+ return false;
1270
+ if (l.type !== r.type)
1271
+ return false;
1272
+ return l.x === r.x && l.y === r.y;
1273
+ };
1274
+ const graphicChanged = graphic !== state.activeGraphic?.file;
1275
+ const stateChanged = graphicChanged || !eqPosition(position, state.activeGraphic?.position);
1276
+ const buttonClass = "mt-2 mb-5 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800";
1277
+ const deleteButtonClass = "mt-2 text-white w-full justify-center bg-red-600 hover:bg-red-700 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-red-700 dark:hover:bg-red-800 dark:focus:ring-red-900";
1278
+ const fileInputClass = "block w-full text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400";
1279
+ return (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-3", children: [(0, import_jsx_runtime20.jsx)("h2", { className: "text-xl font-bold text-gray-900 dark:text-white", children: "Controls" }), (0, import_jsx_runtime20.jsxs)("div", { children: [(0, import_jsx_runtime20.jsx)("label", { htmlFor: "select-graphic", className: "block text-gray-900 dark:text-white mb-1", children: "Source" }), (0, import_jsx_runtime20.jsxs)("select", { id: "select-graphic", className: "w-full node-editor-select-input", value: graphic || "", onChange: (e) => setGraphic(e.target.value || void 0), children: [(0, import_jsx_runtime20.jsx)("option", { value: "", children: "---" }), graphics.map((s) => (0, import_jsx_runtime20.jsx)("option", { value: s, children: s }, s))] })] }), graphic && (0, import_jsx_runtime20.jsxs)("div", { children: [(0, import_jsx_runtime20.jsx)("label", { htmlFor: "select-position", className: "block text-gray-900 dark:text-white mb-1", children: "Graphic position" }), (0, import_jsx_runtime20.jsx)(PositionSelector, { initialPosition: position, onChange: setPosition, graphicChanged, ...state })] }), (0, import_jsx_runtime20.jsx)("button", { type: "button", className: `${buttonClass} ${!stateChanged ? "opacity-50 cursor-not-allowed" : ""}`, onClick: () => sendCommand({ type: "change-graphic", file: graphic, position }), disabled: !stateChanged, children: "Commit" }), !showFileInput && !uploadStatus.success && (0, import_jsx_runtime20.jsx)("button", { type: "button", className: buttonClass, onClick: () => setShowFileInput(true), style: { marginBottom: "1rem" }, children: "Upload Graphic" }), showFileInput && (0, import_jsx_runtime20.jsxs)("form", { style: { display: "block", marginBottom: "1rem" }, children: [(0, import_jsx_runtime20.jsx)("input", { type: "file", id: "file", name: "filename", onChange: onFileChange, className: fileInputClass }), showUploadButton && (0, import_jsx_runtime20.jsx)("button", { type: "button", className: buttonClass, onClick: uploadFile, children: "Upload" })] }), (0, import_jsx_runtime20.jsx)("button", { type: "button", className: deleteButtonClass, onClick: () => setShowDeleteDropdown(!showDeleteDropdown), style: { marginBottom: "1rem" }, children: showDeleteDropdown ? "Hide Delete Options" : "Delete Graphics" }), showDeleteDropdown && (0, import_jsx_runtime20.jsxs)("div", { className: "mt-2 p-2 bg-gray-100 dark:bg-gray-800 rounded-lg", children: [(0, import_jsx_runtime20.jsx)("h3", { className: "text-lg font-semibold mb-2 text-gray-900 dark:text-white", children: "Select Graphic to Delete" }), (0, import_jsx_runtime20.jsxs)("select", { className: "w-full mb-2 node-editor-select-input", value: graphicToDelete, onChange: (e) => setGraphicToDelete(e.target.value), children: [(0, import_jsx_runtime20.jsx)("option", { value: "", children: " Select a graphic" }), graphics.map((graphicName) => (0, import_jsx_runtime20.jsx)("option", { value: graphicName, children: graphicName }, graphicName))] }), (0, import_jsx_runtime20.jsx)("button", { onClick: deleteBug, disabled: !graphicToDelete, className: `${deleteButtonClass} ${!graphicToDelete ? "opacity-50 cursor-not-allowed" : ""}`, children: "Delete Selected Graphic" })] }), uploadStatus.message && (0, import_jsx_runtime20.jsx)("div", { className: `mt-2 text-center ${uploadStatus.success ? "text-green-600" : "text-red-600"}`, children: uploadStatus.message })] });
1280
+ }
1281
+ function convertPosition(givenPosition, currentVideo, currentGraphic) {
1282
+ if (!givenPosition)
1283
+ givenPosition = { type: "named", position: "topleft" };
1284
+ if (givenPosition.type === "named") {
1285
+ let xy;
1286
+ if (givenPosition.position === "topleft") {
1287
+ xy = { x: 0, y: 0 };
1288
+ } else if (givenPosition.position === "topright") {
1289
+ xy = { x: 100, y: 0 };
1290
+ } else if (givenPosition.position === "bottomleft") {
1291
+ xy = { x: 0, y: 100 };
1292
+ } else if (givenPosition.position === "bottomright") {
1293
+ xy = { x: 100, y: 100 };
1294
+ } else if (givenPosition.position === "center") {
1295
+ xy = { x: 50, y: 50 };
1296
+ } else {
1297
+ assertUnreachable12(givenPosition.position);
1298
+ }
1299
+ return { ...givenPosition, ...xy, xPct: xy.x, yPct: xy.y };
1300
+ }
1301
+ if (givenPosition.type === "coordinate") {
1302
+ if (!currentVideo || !currentGraphic) {
1303
+ return { ...givenPosition, xPct: 0, yPct: 0 };
1304
+ }
1305
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1306
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1307
+ const maxX = videoWidth - graphicWidth;
1308
+ const maxY = videoHeight - graphicHeight;
1309
+ return {
1310
+ ...givenPosition,
1311
+ x: clamp(0, givenPosition.x, maxX),
1312
+ xPct: clamp(0, givenPosition.x * 100 / maxX, 100),
1313
+ y: clamp(0, givenPosition.y, maxY),
1314
+ yPct: clamp(0, givenPosition.y * 100 / maxY, 100)
1315
+ };
1316
+ }
1317
+ return { ...givenPosition, xPct: givenPosition.x, yPct: givenPosition.y };
1318
+ }
1319
+ function clamp(min, num, max) {
1320
+ return num < min ? min : num > max ? max : num;
1321
+ }
1322
+ function assertUnreachable12(_) {
1323
+ throw new Error("Didn't expect to get here");
1324
+ }
1325
+ var import_jsx_runtime20, import_react19, PositionSelector, summary_view_default4;
1326
+ var init_summary_view4 = __esm({
1327
+ "build/processor.onscreenGraphic/summary-view.js"() {
1328
+ "use strict";
1329
+ import_jsx_runtime20 = __toESM(require_jsx_runtime());
1330
+ import_react19 = __toESM(require_react());
1331
+ PositionSelector = ({ initialPosition: givenPosition = { type: "named", position: "topleft" }, onChange, currentVideo, currentGraphic, graphicChanged }) => {
1332
+ const convertPos = (pos) => convertPosition(pos, currentVideo, currentGraphic);
1333
+ const initialPosition = convertPos(givenPosition);
1334
+ const [position, setLocalPosition] = (0, import_react19.useState)(initialPosition);
1335
+ const setPosition = (v) => {
1336
+ setLocalPosition(v);
1337
+ onChange(v);
1338
+ };
1339
+ const [positionUnit, setPositionUnit] = (0, import_react19.useState)(position.type === "coordinate" ? "px" : "%");
1340
+ const [isDragging, setIsDragging] = (0, import_react19.useState)(false);
1341
+ const [dragStart, setDragStart] = (0, import_react19.useState)({ xPct: 0, yPct: 0, cx: 0, cy: 0 });
1342
+ const previewAreaRef = (0, import_react19.useRef)(null);
1343
+ const previewTargetRef = (0, import_react19.useRef)(null);
1344
+ const handleMouseDown = (e) => {
1345
+ setIsDragging(true);
1346
+ setDragStart({
1347
+ ...position,
1348
+ cx: e.clientX,
1349
+ cy: e.clientY
1350
+ });
1351
+ handleMouseMove(e);
1352
+ };
1353
+ const handleMouseMove = (e) => {
1354
+ if (!isDragging)
1355
+ return;
1356
+ const boundingBox = previewAreaRef.current?.getBoundingClientRect() ?? { width: 0, height: 0 };
1357
+ const bbTarget = previewTargetRef.current?.getBoundingClientRect() ?? { width: 0, height: 0 };
1358
+ const clientWidth = boundingBox.width - bbTarget.width;
1359
+ const clientHeight = boundingBox.height - bbTarget.height;
1360
+ const newX = clamp(0, dragStart.xPct + (e.clientX - dragStart.cx) * (100 / clientWidth), 100);
1361
+ const newY = clamp(0, dragStart.yPct + (e.clientY - dragStart.cy) * (100 / clientHeight), 100);
1362
+ if (positionUnit === "px" && currentVideo && currentGraphic) {
1363
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1364
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1365
+ const maxX = videoWidth - graphicWidth;
1366
+ const maxY = videoHeight - graphicHeight;
1367
+ setPosition({
1368
+ type: "coordinate",
1369
+ x: newX * maxX / 100,
1370
+ y: newY * maxY / 100,
1371
+ xPct: newX,
1372
+ yPct: newY
1373
+ });
1374
+ } else {
1375
+ setPosition({
1376
+ type: "percentage",
1377
+ x: newX,
1378
+ y: newY,
1379
+ xPct: newX,
1380
+ yPct: newY
1381
+ });
1382
+ }
1383
+ };
1384
+ const handleMouseUp = () => {
1385
+ setIsDragging(false);
1386
+ };
1387
+ (0, import_react19.useEffect)(() => {
1388
+ if (isDragging) {
1389
+ window.addEventListener("mousemove", handleMouseMove);
1390
+ window.addEventListener("mouseup", handleMouseUp);
1391
+ }
1392
+ return () => {
1393
+ window.removeEventListener("mousemove", handleMouseMove);
1394
+ window.removeEventListener("mouseup", handleMouseUp);
1395
+ };
1396
+ }, [isDragging]);
1397
+ return (0, import_jsx_runtime20.jsxs)("div", { className: "relative w-full max-w-lg mx-auto mt-4 mb-8", children: [(0, import_jsx_runtime20.jsxs)("div", { className: "mb-4 flex items-center gap-2", children: [(0, import_jsx_runtime20.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Position Type:" }), (0, import_jsx_runtime20.jsxs)("select", { value: position.type, onChange: (e) => {
1398
+ const newType = e.target.value;
1399
+ if (newType === "named") {
1400
+ setPosition(convertPos({ type: "named", position: "topleft" }));
1401
+ } else {
1402
+ setPositionUnit("%");
1403
+ setPosition({ ...convertPos(position), type: "percentage" });
1404
+ }
1405
+ }, className: "node-editor-select-input", children: [(0, import_jsx_runtime20.jsx)("option", { value: "coordinate", children: "Custom Position" }), (0, import_jsx_runtime20.jsx)("option", { value: "named", children: "Preset Position" })] })] }), position.type === "named" ? (0, import_jsx_runtime20.jsx)("div", { className: "mb-4", children: (0, import_jsx_runtime20.jsxs)("select", { value: position.position, onChange: (e) => {
1406
+ setPosition(convertPos({
1407
+ type: "named",
1408
+ position: e.target.value
1409
+ }));
1410
+ }, className: "w-full node-editor-select-input", children: [(0, import_jsx_runtime20.jsx)("option", { value: "topleft", children: "Top Left" }), (0, import_jsx_runtime20.jsx)("option", { value: "topright", children: "Top Right" }), (0, import_jsx_runtime20.jsx)("option", { value: "bottomleft", children: "Bottom Left" }), (0, import_jsx_runtime20.jsx)("option", { value: "bottomright", children: "Bottom Right" }), (0, import_jsx_runtime20.jsx)("option", { value: "center", children: "Centered" })] }) }) : (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [(0, import_jsx_runtime20.jsxs)("div", { className: "mb-4 flex items-center gap-2", children: [(0, import_jsx_runtime20.jsx)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Position Unit:" }), (0, import_jsx_runtime20.jsxs)("select", { value: positionUnit, onChange: (e) => {
1411
+ setPositionUnit(e.target.value);
1412
+ if (e.target.value === "px" && position.type !== "coordinate" && currentVideo && currentGraphic) {
1413
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1414
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1415
+ const maxX = videoWidth - graphicWidth;
1416
+ const maxY = videoHeight - graphicHeight;
1417
+ setPosition({
1418
+ ...position,
1419
+ type: "coordinate",
1420
+ x: position.xPct * maxX / 100,
1421
+ y: position.yPct * maxY / 100,
1422
+ xStr: void 0,
1423
+ yStr: void 0
1424
+ });
1425
+ } else if (e.target.value === "%") {
1426
+ setPosition({
1427
+ ...position,
1428
+ type: "percentage",
1429
+ x: position.xPct,
1430
+ y: position.yPct,
1431
+ xStr: void 0,
1432
+ yStr: void 0
1433
+ });
1434
+ }
1435
+ }, className: "node-editor-select-input", children: [(0, import_jsx_runtime20.jsx)("option", { value: "px", children: "Pixels" }), (0, import_jsx_runtime20.jsx)("option", { value: "%", children: "Percentage" })] })] }), (0, import_jsx_runtime20.jsxs)("div", { className: "relative bg-gray-200 dark:bg-gray-700 rounded-lg", style: {
1436
+ width: "100%",
1437
+ userSelect: "none",
1438
+ aspectRatio: currentVideo ? `${currentVideo.width} / ${currentVideo.height}` : `3 / 2`
1439
+ }, ref: previewAreaRef, children: [(0, import_jsx_runtime20.jsxs)("div", { className: "absolute inset-0 flex flex-col items-center justify-center text-gray-500 dark:text-gray-400", children: [(0, import_jsx_runtime20.jsx)("span", { children: currentVideo ? "Video Preview Area" : "Video Dimensions Unknown" }), " ", currentVideo ? (0, import_jsx_runtime20.jsxs)("span", { children: [currentVideo.width, "x", currentVideo.height, "px"] }) : ""] }), (0, import_jsx_runtime20.jsx)("div", { className: `absolute cursor-move ${currentGraphic && !graphicChanged ? "" : "p-2"} rounded-lg bg-primary-500 bg-opacity-50 hover:bg-opacity-75 transition-colors
1440
+ ${isDragging ? "bg-opacity-75" : ""}`, style: {
1441
+ left: `${position.xPct}%`,
1442
+ top: `${position.yPct}%`,
1443
+ transform: `translate(-${position.xPct}%, -${position.yPct}%)`,
1444
+ aspectRatio: currentGraphic && !graphicChanged ? `${currentGraphic.width} / ${currentGraphic.height}` : `1`,
1445
+ width: currentGraphic && currentVideo && !graphicChanged ? currentGraphic.width / currentVideo.width * 100 + "%" : void 0
1446
+ }, onMouseDown: handleMouseDown, ref: previewTargetRef, children: (0, import_jsx_runtime20.jsx)("svg", { className: `${currentGraphic && !graphicChanged ? "w-full h-full" : "w-6 h-6"} text-white`, "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: (0, import_jsx_runtime20.jsx)("path", { stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 6v12m-6-6h12m-6-6 1.5 1.5M12 6l-1.5 1.5m1.5 10.5L10.5 16.5M12 18l1.5-1.5M6 12l1.5-1.5M7.5 13.5 6 12m12 0-1.5-1.5M16.5 13.5 18 12" }) }) })] }), (0, import_jsx_runtime20.jsxs)("div", { className: "mt-2 text-sm text-gray-600 dark:text-gray-300 text-center", children: ["Position:", " ", position.type === "percentage" ? `${position.xPct.toFixed(1)}%, ${position.yPct.toFixed(1)}%` : `${Math.round(position.x)}px, ${Math.round(position.y)}px`] }), (0, import_jsx_runtime20.jsxs)("div", { className: "mt-2 flex gap-4", children: [(0, import_jsx_runtime20.jsxs)("div", { children: [(0, import_jsx_runtime20.jsxs)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: ["X Position ", positionUnit] }), (0, import_jsx_runtime20.jsx)("input", { type: "number", step: positionUnit === "%" ? "0.1" : "1", value: position.xStr ?? (positionUnit === "%" ? position.xPct.toFixed(1) : Math.round(position.x)), onChange: (e) => {
1447
+ const newX = Number(e.target.value);
1448
+ setPosition(convertPos({
1449
+ type: positionUnit === "%" ? "percentage" : "coordinate",
1450
+ x: newX,
1451
+ xStr: e.target.value,
1452
+ y: position.y,
1453
+ yStr: position.yStr
1454
+ }));
1455
+ }, className: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600" })] }), (0, import_jsx_runtime20.jsxs)("div", { children: [(0, import_jsx_runtime20.jsxs)("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: ["Y Position ", positionUnit] }), (0, import_jsx_runtime20.jsx)("input", { type: "number", step: positionUnit === "%" ? "0.1" : "1", value: position.yStr ?? (positionUnit === "%" ? position.yPct.toFixed(1) : Math.round(position.y)), onChange: (e) => {
1456
+ const newY = Number(e.target.value);
1457
+ setPosition(convertPos({
1458
+ type: positionUnit === "%" ? "percentage" : "coordinate",
1459
+ x: position.x,
1460
+ xStr: position.xStr,
1461
+ y: newY,
1462
+ yStr: e.target.value
1463
+ }));
1464
+ }, className: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600" })] })] })] })] });
1465
+ };
1466
+ summary_view_default4 = SummaryView7;
1467
+ }
1468
+ });
1469
+
829
1470
  // ../../node_modules/@kurkle/color/dist/color.esm.js
830
1471
  function round(v) {
831
1472
  return v + 0.5 | 0;
@@ -15144,14 +15785,14 @@ var init_auto = __esm({
15144
15785
  }
15145
15786
  });
15146
15787
 
15147
- // build/util.latency/inline-view.js
15148
- var inline_view_exports7 = {};
15149
- __export(inline_view_exports7, {
15150
- default: () => inline_view_default7
15788
+ // build/util.stats.latency/inline-view.js
15789
+ var inline_view_exports9 = {};
15790
+ __export(inline_view_exports9, {
15791
+ default: () => inline_view_default9
15151
15792
  });
15152
- function InlineView10({ state, config: _2 }) {
15153
- const chartContainer = (0, import_react18.useRef)(null);
15154
- const [chartControl, setChartControl] = (0, import_react18.useState)(void 0);
15793
+ function InlineView12({ state, config: _2 }) {
15794
+ const chartContainer = (0, import_react21.useRef)(null);
15795
+ const [chartControl, setChartControl] = (0, import_react21.useState)(void 0);
15155
15796
  function makeDataSet(key, color2, values) {
15156
15797
  return {
15157
15798
  label: key,
@@ -15168,7 +15809,7 @@ function InlineView10({ state, config: _2 }) {
15168
15809
  datasets: [makeDataSet("latency", "rgba(255, 0, 0, 255)", state2.values)]
15169
15810
  };
15170
15811
  }
15171
- (0, import_react18.useEffect)(() => {
15812
+ (0, import_react21.useEffect)(() => {
15172
15813
  if (!chartContainer.current)
15173
15814
  return;
15174
15815
  auto_default.defaults.color = "#FFF";
@@ -15206,237 +15847,47 @@ function InlineView10({ state, config: _2 }) {
15206
15847
  chart.update();
15207
15848
  }, 100);
15208
15849
  }, [chartContainer]);
15209
- (0, import_react18.useEffect)(() => {
15850
+ (0, import_react21.useEffect)(() => {
15210
15851
  if (!chartControl)
15211
15852
  return;
15212
15853
  chartControl.data = makeData(state);
15213
15854
  }, [state]);
15214
- return (0, import_jsx_runtime19.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: "200px", padding: "10px" }, children: (0, import_jsx_runtime19.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) });
15855
+ return (0, import_jsx_runtime21.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: "200px", padding: "10px" }, children: (0, import_jsx_runtime21.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) });
15215
15856
  }
15216
- var import_jsx_runtime19, import_react18, inline_view_default7;
15217
- var init_inline_view7 = __esm({
15218
- "build/util.latency/inline-view.js"() {
15857
+ var import_jsx_runtime21, import_react21, inline_view_default9;
15858
+ var init_inline_view9 = __esm({
15859
+ "build/util.stats.latency/inline-view.js"() {
15219
15860
  "use strict";
15220
- import_jsx_runtime19 = __toESM(require_jsx_runtime());
15221
- import_react18 = __toESM(require_react());
15861
+ import_jsx_runtime21 = __toESM(require_jsx_runtime());
15862
+ import_react21 = __toESM(require_react());
15222
15863
  init_auto();
15223
- inline_view_default7 = InlineView10;
15864
+ inline_view_default9 = InlineView12;
15224
15865
  }
15225
15866
  });
15226
15867
 
15227
- // build/util.latency/source-node-selection.js
15868
+ // build/util.stats.latency/source-node-selection.js
15228
15869
  var source_node_selection_exports = {};
15229
15870
  __export(source_node_selection_exports, {
15230
15871
  default: () => source_node_selection_default
15231
15872
  });
15232
15873
  function SourceNodeSelection(props) {
15233
- return (0, import_jsx_runtime20.jsx)("div", { children: (0, import_jsx_runtime20.jsxs)("select", { defaultValue: props.defaultValue, className: `node-editor-select-input`, id: props.id, onChange: myOnChange, onBlur: myOnChange, children: [(0, import_jsx_runtime20.jsx)("option", { value: "", children: "---" }, "empty"), Object.values(props.latestDocument.components).map((o, i) => {
15874
+ return (0, import_jsx_runtime22.jsx)("div", { children: (0, import_jsx_runtime22.jsxs)("select", { defaultValue: props.defaultValue, className: `node-editor-select-input`, id: props.id, onChange: myOnChange, onBlur: myOnChange, children: [(0, import_jsx_runtime22.jsx)("option", { value: "", children: "---" }, "empty"), Object.values(props.latestDocument.components).map((o, i) => {
15234
15875
  if (o.id == props.id)
15235
- return (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, {});
15876
+ return (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, {});
15236
15877
  if (o.info.category === "output")
15237
15878
  return;
15238
- return (0, import_jsx_runtime20.jsx)("option", { value: o.id, children: o.config.displayName }, i);
15879
+ return (0, import_jsx_runtime22.jsx)("option", { value: o.id, children: o.config.displayName }, i);
15239
15880
  })] }) });
15240
15881
  function myOnChange(e) {
15241
15882
  props.onChanged(e.target.value);
15242
15883
  }
15243
15884
  }
15244
- var import_jsx_runtime20, source_node_selection_default;
15885
+ var import_jsx_runtime22, source_node_selection_default;
15245
15886
  var init_source_node_selection = __esm({
15246
- "build/util.latency/source-node-selection.js"() {
15247
- "use strict";
15248
- import_jsx_runtime20 = __toESM(require_jsx_runtime());
15249
- source_node_selection_default = SourceNodeSelection;
15250
- }
15251
- });
15252
-
15253
- // build/util.ma35d/inline-view.js
15254
- var inline_view_exports8 = {};
15255
- __export(inline_view_exports8, {
15256
- default: () => inline_view_default8
15257
- });
15258
- function InlineView11({ state, config: _2 }) {
15259
- const chartContainer = (0, import_react20.useRef)(null);
15260
- const [chartControl, setChartControl] = (0, import_react20.useState)(void 0);
15261
- function makeDataSet(key, color2, values) {
15262
- return {
15263
- label: key,
15264
- fill: false,
15265
- borderColor: color2,
15266
- borderWidth: 1,
15267
- pointStyle: "dash",
15268
- data: values
15269
- };
15270
- }
15271
- function makeData(state2) {
15272
- return {
15273
- labels: new Array(state2.decoder.length).fill(0).map((_, i) => i).map((_) => ""),
15274
- datasets: [
15275
- makeDataSet("decoder", "rgba(255, 0, 0, 255)", state2.decoder),
15276
- makeDataSet("scaler", "rgba(0, 255, 0, 255)", state2.scaler),
15277
- makeDataSet("encoder", "rgba(0, 0, 255, 255)", state2.encoder)
15278
- ]
15279
- };
15280
- }
15281
- (0, import_react20.useEffect)(() => {
15282
- if (!chartContainer.current)
15283
- return;
15284
- auto_default.defaults.color = "#FFF";
15285
- const chart = new auto_default(chartContainer.current, {
15286
- type: "line",
15287
- options: {
15288
- plugins: {
15289
- legend: {
15290
- display: true
15291
- }
15292
- },
15293
- animation: false,
15294
- color: "#FFF",
15295
- scales: {
15296
- x: {
15297
- min: 0,
15298
- max: 200,
15299
- grid: {
15300
- display: false
15301
- }
15302
- },
15303
- y: {
15304
- min: 0,
15305
- max: 100,
15306
- grid: {
15307
- display: false
15308
- }
15309
- }
15310
- }
15311
- },
15312
- data: makeData(state)
15313
- });
15314
- setChartControl(chart);
15315
- setInterval(() => {
15316
- chart.update();
15317
- }, 100);
15318
- }, [chartContainer]);
15319
- (0, import_react20.useEffect)(() => {
15320
- if (!chartControl)
15321
- return;
15322
- chartControl.data = makeData(state);
15323
- }, [state]);
15324
- return (0, import_jsx_runtime21.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: "200px", padding: "10px" }, children: (0, import_jsx_runtime21.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) });
15325
- }
15326
- var import_jsx_runtime21, import_react20, inline_view_default8;
15327
- var init_inline_view8 = __esm({
15328
- "build/util.ma35d/inline-view.js"() {
15329
- "use strict";
15330
- import_jsx_runtime21 = __toESM(require_jsx_runtime());
15331
- import_react20 = __toESM(require_react());
15332
- init_auto();
15333
- inline_view_default8 = InlineView11;
15334
- }
15335
- });
15336
-
15337
- // build/util.timestamps/inline-view.js
15338
- var inline_view_exports9 = {};
15339
- __export(inline_view_exports9, {
15340
- default: () => inline_view_default9
15341
- });
15342
- function InlineView12({ state, config: _2 }) {
15343
- const chartContainer = (0, import_react22.useRef)(null);
15344
- const [chartControl, setChartControl] = (0, import_react22.useState)(void 0);
15345
- (0, import_react22.useEffect)(() => {
15346
- if (!chartContainer.current)
15347
- return;
15348
- if (state.timestamps.length < 2)
15349
- return;
15350
- auto_default.defaults.color = "#FFF";
15351
- const chart = new auto_default(chartContainer.current, {
15352
- type: "line",
15353
- options: {
15354
- plugins: {
15355
- legend: {
15356
- display: false
15357
- }
15358
- },
15359
- // spanGaps: true,
15360
- animation: false,
15361
- // backgroundColor: 'rgba(0,0,0, 255)',
15362
- color: "#FFF",
15363
- // borderColor: '#FFF',
15364
- // aspectRatio: 1,
15365
- scales: {
15366
- x: {
15367
- min: 0,
15368
- max: 200,
15369
- grid: {
15370
- display: false
15371
- }
15372
- },
15373
- y: {
15374
- min: 0,
15375
- max: 5e3,
15376
- grid: {
15377
- display: false
15378
- }
15379
- }
15380
- }
15381
- },
15382
- data: {
15383
- labels: new Array(200).fill(0).map((_, i) => i).map((_) => ""),
15384
- datasets: state.timestamps.map((t) => {
15385
- const mapped = t.timestamps.map((f) => {
15386
- const elapsedWall = f.wall - t.startTimeMs;
15387
- const elapsedTime = (f.ts - t.startTimestamp) * 1e3;
15388
- return Math.abs(elapsedTime - elapsedWall);
15389
- });
15390
- return {
15391
- label: t.key,
15392
- fill: false,
15393
- borderColor: "rgba(255, 0, 0, 255)",
15394
- borderWidth: 1,
15395
- pointStyle: "dash",
15396
- // backgroundColor: 'rgba(255, 128, 128, 255)',
15397
- data: mapped
15398
- };
15399
- })
15400
- }
15401
- });
15402
- setChartControl(chart);
15403
- setInterval(() => {
15404
- chart.update();
15405
- }, 100);
15406
- }, [chartContainer]);
15407
- (0, import_react22.useEffect)(() => {
15408
- if (!chartControl)
15409
- return;
15410
- chartControl.data = {
15411
- labels: new Array(200).fill(0).map((_, i) => i).map((_) => ""),
15412
- datasets: state.timestamps.map((t) => {
15413
- const mapped = t.timestamps.map((f) => {
15414
- const elapsedWall = f.wall - t.startTimeMs;
15415
- const elapsedTime = (f.ts - t.startTimestamp) * 1e3;
15416
- return Math.abs(elapsedTime - elapsedWall);
15417
- });
15418
- return {
15419
- label: t.key,
15420
- fill: false,
15421
- borderColor: "rgba(255, 0, 0, 255)",
15422
- borderWidth: 1,
15423
- pointStyle: "dash",
15424
- // backgroundColor: 'rgba(255, 128, 128, 255)',
15425
- data: mapped
15426
- };
15427
- })
15428
- };
15429
- }, [state]);
15430
- return (0, import_jsx_runtime22.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: "200px", padding: "10px" }, children: (0, import_jsx_runtime22.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) });
15431
- }
15432
- var import_jsx_runtime22, import_react22, inline_view_default9;
15433
- var init_inline_view9 = __esm({
15434
- "build/util.timestamps/inline-view.js"() {
15887
+ "build/util.stats.latency/source-node-selection.js"() {
15435
15888
  "use strict";
15436
15889
  import_jsx_runtime22 = __toESM(require_jsx_runtime());
15437
- import_react22 = __toESM(require_react());
15438
- init_auto();
15439
- inline_view_default9 = InlineView12;
15890
+ source_node_selection_default = SourceNodeSelection;
15440
15891
  }
15441
15892
  });
15442
15893
 
@@ -15450,6 +15901,7 @@ function info_default({ defineComponent, Av, validation: { Z, Port, SourceName,
15450
15901
  identifier: "input.rtmp",
15451
15902
  category: "input",
15452
15903
  name: "RTMP Ingest",
15904
+ description: "A component that listens for RTMP input on the address specified.",
15453
15905
  subscription: {
15454
15906
  accepts: void 0,
15455
15907
  produces: {
@@ -15494,7 +15946,7 @@ function info_default({ defineComponent, Av, validation: { Z, Port, SourceName,
15494
15946
  configForm: {
15495
15947
  form: {
15496
15948
  port: { help: "The port this RTMP input will listen on", hint: { type: "numeric", validation: Port, defaultValue: defaultPort, global: unique("port") } },
15497
- ssl: { help: "Optional: SSL", hint: { type: "boolean" } },
15949
+ ssl: { help: "Optional: SSL", hint: { type: "boolean", optional: true } },
15498
15950
  appName: { help: "Name of the app", hint: { type: "text", validation: Z.string().min(1), defaultValue: "norsk" } },
15499
15951
  streamNames: {
15500
15952
  help: "List of stream names to assign to the accepted streams",
@@ -15519,6 +15971,7 @@ function info_default2({ defineComponent, Audio }) {
15519
15971
  identifier: "input.silence",
15520
15972
  category: "input",
15521
15973
  name: "Silence Generator",
15974
+ description: "A component that produces silent audio streams with configurable sample rate and channel layout.",
15522
15975
  subscription: {
15523
15976
  produces: {
15524
15977
  type: "single-stream",
@@ -15527,14 +15980,14 @@ function info_default2({ defineComponent, Audio }) {
15527
15980
  },
15528
15981
  display: (desc) => {
15529
15982
  return {
15530
- sampleRate: desc.config.sampleRate.toString() + "khz",
15983
+ sampleRate: desc.config.sampleRate.toString() + "Hz",
15531
15984
  channelLayout: desc.config.channelLayout.toString()
15532
15985
  };
15533
15986
  },
15534
15987
  configForm: {
15535
15988
  form: {
15536
15989
  sampleRate: {
15537
- help: "Samplerate in khz of the generated audio",
15990
+ help: "Samplerate in Hz of the generated audio",
15538
15991
  hint: {
15539
15992
  type: "select",
15540
15993
  options: [
@@ -15566,6 +16019,7 @@ var result = ({ Z }) => ({
15566
16019
  help: "The latency value in the receiving direction of the socket (SRTO_RCVLATENCY)",
15567
16020
  hint: {
15568
16021
  type: "numeric",
16022
+ optional: true,
15569
16023
  validation: Z.optional(Z.number())
15570
16024
  }
15571
16025
  },
@@ -15573,13 +16027,15 @@ var result = ({ Z }) => ({
15573
16027
  help: "The latency value provided by the sender side as a minimum value for the receiver (SRTO_PEERLATENCY)",
15574
16028
  hint: {
15575
16029
  type: "numeric",
16030
+ optional: true,
15576
16031
  validation: Z.optional(Z.number())
15577
16032
  }
15578
16033
  },
15579
16034
  inputBandwidth: {
15580
- help: "Input bandwidth (SRTO_INPUTBW xxx",
16035
+ help: "Input bandwidth (SRTO_INPUTBW)",
15581
16036
  hint: {
15582
16037
  type: "numeric",
16038
+ optional: true,
15583
16039
  validation: Z.optional(Z.number())
15584
16040
  }
15585
16041
  },
@@ -15587,6 +16043,7 @@ var result = ({ Z }) => ({
15587
16043
  help: "Overhead bandwidth (SRTO_OHEADBW)",
15588
16044
  hint: {
15589
16045
  type: "numeric",
16046
+ optional: true,
15590
16047
  validation: Z.optional(Z.number())
15591
16048
  }
15592
16049
  },
@@ -15594,6 +16051,7 @@ var result = ({ Z }) => ({
15594
16051
  help: "Max bandwidth (SRTO_MAXBW)",
15595
16052
  hint: {
15596
16053
  type: "numeric",
16054
+ optional: true,
15597
16055
  validation: Z.optional(Z.number())
15598
16056
  }
15599
16057
  }
@@ -15603,7 +16061,7 @@ var srt_socket_options_default = result;
15603
16061
  // build/input.srt-caller/info.js
15604
16062
  var import_react2 = __toESM(require_react());
15605
16063
  function info_default3({ defineComponent, Av, validation }) {
15606
- const { Port, IpAddress, SourceName, SrtPassphrase, SrtStreamId } = validation;
16064
+ const { Port, Hostname, SourceName, SrtPassphrase, SrtStreamId } = validation;
15607
16065
  const SocketConfiguration2 = import_react2.default.lazy(async () => {
15608
16066
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
15609
16067
  return { default: views.SocketConfiguration };
@@ -15612,6 +16070,7 @@ function info_default3({ defineComponent, Av, validation }) {
15612
16070
  identifier: "input.srt-caller",
15613
16071
  category: "input",
15614
16072
  name: "SRT Ingest (Caller)",
16073
+ description: "This component allows you to receive Secure Reliable Transport (SRT) streams by calling a remote SRT listener.",
15615
16074
  subscription: {
15616
16075
  accepts: void 0,
15617
16076
  produces: {
@@ -15622,16 +16081,16 @@ function info_default3({ defineComponent, Av, validation }) {
15622
16081
  display: (desc) => {
15623
16082
  return {
15624
16083
  port: desc.config.port.toString(),
15625
- ip: desc.config.ip
16084
+ ip: desc.config.host
15626
16085
  };
15627
16086
  },
15628
16087
  configForm: {
15629
16088
  form: {
15630
16089
  port: { help: "The port this SRT input will connect to", hint: { type: "numeric", validation: Port, defaultValue: 5001 } },
15631
- ip: { help: "The IP address this SRT input will connect to", hint: { type: "text", validation: IpAddress, defaultValue: "0.0.0.0" } },
16090
+ host: { help: "The IP address/hostname this SRT input will connect to", hint: { type: "text", validation: Hostname, defaultValue: "0.0.0.0" } },
15632
16091
  sourceName: { help: "Source name to identify this by", hint: { type: "text", validation: SourceName, defaultValue: "camera1" } },
15633
- passphrase: { help: "Optional: Authentication for this SRT input", hint: { type: "text", validation: SrtPassphrase } },
15634
- streamId: { help: "Optional: StreamId to use when calling the remote listener", hint: { type: "text", validation: SrtStreamId } },
16092
+ passphrase: { help: "Optional: Authentication for this SRT input", hint: { type: "text", optional: true, validation: SrtPassphrase } },
16093
+ streamId: { help: "Optional: StreamId to use when calling the remote listener", hint: { type: "text", optional: true, validation: SrtStreamId } },
15635
16094
  socketOptions: {
15636
16095
  help: "Socket Options",
15637
16096
  hint: {
@@ -15650,7 +16109,7 @@ var import_react3 = __toESM(require_react());
15650
16109
  var InlineView4 = import_react3.default.lazy(async () => Promise.resolve().then(() => (init_inline_view2(), inline_view_exports2)));
15651
16110
  var SummaryView4 = import_react3.default.lazy(async () => Promise.resolve().then(() => (init_summary_view2(), summary_view_exports2)));
15652
16111
  function info_default4({ defineComponent, Av, validation }) {
15653
- const { Z, Port, IpAddress, SourceName, SrtPassphrase, unique } = validation;
16112
+ const { Z, Port, Hostname, SourceName, SrtPassphrase, unique } = validation;
15654
16113
  const SocketConfiguration2 = import_react3.default.lazy(async () => {
15655
16114
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
15656
16115
  return { default: views.SocketConfiguration };
@@ -15659,6 +16118,7 @@ function info_default4({ defineComponent, Av, validation }) {
15659
16118
  identifier: "input.srt-listener",
15660
16119
  category: "input",
15661
16120
  name: "SRT Ingest (Listener)",
16121
+ description: "This component handles media ingest via the SRT(Secure Reliable Transport) protocol. It acts as a listener, receiving media streams from remote SRT sources and is highly configurable, allowing for custom IP addresses, ports, and stream handling behaviours.",
15662
16122
  subscription: {
15663
16123
  accepts: void 0,
15664
16124
  produces: {
@@ -15679,11 +16139,11 @@ function info_default4({ defineComponent, Av, validation }) {
15679
16139
  display: (desc) => {
15680
16140
  return {
15681
16141
  port: desc.config.port.toString(),
15682
- ip: desc.config.ip
16142
+ ip: desc.config.host
15683
16143
  };
15684
16144
  },
15685
16145
  runtime: {
15686
- initialState: () => ({ connectedStreams: [] }),
16146
+ initialState: () => ({ connectedStreams: [], disabledStreams: [] }),
15687
16147
  handleEvent(ev, state) {
15688
16148
  const evType = ev.type;
15689
16149
  switch (evType) {
@@ -15693,6 +16153,12 @@ function info_default4({ defineComponent, Av, validation }) {
15693
16153
  case "source-disconnected":
15694
16154
  state.connectedStreams = state.connectedStreams.filter((streamId) => streamId !== ev.streamId);
15695
16155
  break;
16156
+ case "source-enabled":
16157
+ state.disabledStreams = state.disabledStreams.filter((streamId) => streamId !== ev.streamId);
16158
+ break;
16159
+ case "source-disabled":
16160
+ state.disabledStreams.push(ev.streamId);
16161
+ break;
15696
16162
  default:
15697
16163
  assertUnreachable2(evType);
15698
16164
  }
@@ -15713,11 +16179,11 @@ function info_default4({ defineComponent, Av, validation }) {
15713
16179
  envOverride: true
15714
16180
  }
15715
16181
  },
15716
- ip: {
15717
- help: "The IP address this SRT input will listen on",
16182
+ host: {
16183
+ help: "The IP address/hostname this SRT input will listen on",
15718
16184
  hint: {
15719
16185
  type: "text",
15720
- validation: IpAddress,
16186
+ validation: Hostname,
15721
16187
  defaultValue: "0.0.0.0",
15722
16188
  envOverride: true
15723
16189
  }
@@ -15726,6 +16192,7 @@ function info_default4({ defineComponent, Av, validation }) {
15726
16192
  help: "Optional: Authentication for this SRT input",
15727
16193
  hint: {
15728
16194
  type: "text",
16195
+ optional: true,
15729
16196
  validation: SrtPassphrase,
15730
16197
  envOverride: true
15731
16198
  }
@@ -15767,11 +16234,12 @@ function assertUnreachable2(_) {
15767
16234
  }
15768
16235
 
15769
16236
  // build/input.udp-ts/info.js
15770
- function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress, SourceName, unique } }) {
16237
+ function info_default5({ defineComponent, Av, validation: { Z, Port, Hostname, SourceName, unique } }) {
15771
16238
  return defineComponent({
15772
16239
  identifier: "input.udp-ts",
15773
16240
  category: "input",
15774
16241
  name: "UDP TS ingest",
16242
+ description: "This component receives and processes MPEG Transport Streams (TS) over UDP.",
15775
16243
  subscription: {
15776
16244
  accepts: void 0,
15777
16245
  produces: {
@@ -15782,15 +16250,15 @@ function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress,
15782
16250
  display: (desc) => {
15783
16251
  return {
15784
16252
  port: desc.config.port.toString(),
15785
- ip: desc.config.ip
16253
+ ip: desc.config.host
15786
16254
  };
15787
16255
  },
15788
16256
  configForm: {
15789
16257
  form: {
15790
16258
  port: { help: "The receiving port", hint: { type: "numeric", validation: Port, defaultValue: 5001, global: unique("port") } },
15791
- ip: { help: "The receiving IP address", hint: { type: "text", validation: IpAddress, defaultValue: "127.0.0.1" } },
16259
+ host: { help: "The receiving IP address/hostname", hint: { type: "text", validation: Hostname, defaultValue: "127.0.0.1" } },
15792
16260
  sourceName: { help: "Source name to identify this by", hint: { type: "text", validation: SourceName, defaultValue: "udp-ts", global: unique("sourceName") } },
15793
- interface: { help: "Optional interface to bind to", hint: { type: "text", validation: Z.union([Z.string().min(2).max(32), Z.string().length(0)]).optional() } },
16261
+ interface: { help: "Optional interface to bind to", hint: { type: "text", optional: true, validation: Z.union([Z.string().min(2).max(32), Z.string().length(0)]).optional() } },
15794
16262
  timeout: { help: "Timeout in milliseconds before determining the input is closed", hint: { type: "numeric", validation: Z.number().refine((value) => value > 0 && value < 6e5, "Timeout must be less than 10 minutes"), defaultValue: 1e3 } },
15795
16263
  rtpDecapsulate: { help: "Whether to expect the input TS to be encapsulated in RTP via RFC 2250 (default: false)", hint: { type: "boolean" } }
15796
16264
  }
@@ -15799,11 +16267,12 @@ function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress,
15799
16267
  }
15800
16268
 
15801
16269
  // build/input.videoTestCard/info.js
15802
- function info_default6({ defineComponent, Video, validation: { SourceName }, common: { Resolutions, FrameRates } }) {
16270
+ function info_default6({ defineComponent, Video, validation: { SourceName, unique }, common: { Resolutions, FrameRates } }) {
15803
16271
  return defineComponent({
15804
16272
  identifier: "input.videoTestCard",
15805
16273
  category: "input",
15806
16274
  name: "Video Test Card",
16275
+ description: "The Video Test Card component generates a test card video stream with customizable settings.",
15807
16276
  subscription: {
15808
16277
  accepts: void 0,
15809
16278
  produces: {
@@ -15820,9 +16289,18 @@ function info_default6({ defineComponent, Video, validation: { SourceName }, com
15820
16289
  },
15821
16290
  configForm: {
15822
16291
  form: {
15823
- resolution: { help: "The resolution of the test card stream", hint: { type: "select", options: Resolutions, defaultValue: { width: 1280, height: 720 } } },
15824
- frameRate: { help: "The frame rate of the test card stream", hint: { type: "select", options: FrameRates, defaultValue: { frames: 25, seconds: 1 } } },
15825
- sourceName: { help: "Source name to use for this test card stream", hint: { type: "text", validation: SourceName, defaultValue: "video" } },
16292
+ resolution: {
16293
+ help: "The resolution of the test card stream",
16294
+ hint: { type: "select", options: Resolutions, defaultValue: { width: 1280, height: 720 } }
16295
+ },
16296
+ frameRate: {
16297
+ help: "The frame rate of the test card stream",
16298
+ hint: { type: "select", options: FrameRates, defaultValue: { frames: 25, seconds: 1 } }
16299
+ },
16300
+ sourceName: {
16301
+ help: "Source name to use for this test card stream",
16302
+ hint: { type: "text", validation: SourceName, defaultValue: "video", global: unique("sourceName") }
16303
+ },
15826
16304
  pattern: {
15827
16305
  help: "The pattern on the test card stream",
15828
16306
  hint: {
@@ -15841,15 +16319,16 @@ function info_default6({ defineComponent, Video, validation: { SourceName }, com
15841
16319
  }
15842
16320
 
15843
16321
  // build/output.autoCmaf/info.js
15844
- var import_react6 = __toESM(require_react());
15845
- function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15846
- const SummaryView6 = import_react6.default.lazy(async () => Promise.resolve().then(() => (init_summary(), summary_exports)));
15847
- const FullscreenView2 = import_react6.default.lazy(async () => Promise.resolve().then(() => (init_fullscreen(), fullscreen_exports)));
15848
- const SegmentConfiguration2 = import_react6.default.lazy(async () => {
16322
+ var import_config = __toESM(require_config());
16323
+ var import_react5 = __toESM(require_react());
16324
+ function info_default7(R) {
16325
+ const { defineComponent, All, validation: { Z, Hostname } } = R;
16326
+ const FullscreenView2 = import_react5.default.lazy(async () => Promise.resolve().then(() => (init_fullscreen(), fullscreen_exports)));
16327
+ const SegmentConfiguration2 = import_react5.default.lazy(async () => {
15849
16328
  const views = await Promise.resolve().then(() => (init_form_views(), form_views_exports));
15850
16329
  return { default: views.SegmentConfiguration };
15851
16330
  });
15852
- const S3Destination2 = import_react6.default.lazy(async () => {
16331
+ const S3Destination2 = import_react5.default.lazy(async () => {
15853
16332
  const views = await Promise.resolve().then(() => (init_form_views(), form_views_exports));
15854
16333
  return { default: views.S3Destination };
15855
16334
  });
@@ -15857,6 +16336,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15857
16336
  identifier: "output.autoCmaf",
15858
16337
  category: "output",
15859
16338
  name: "Auto CMAF",
16339
+ description: "This component handles the creation of CMAF outputs from multiple video and audio streams.",
15860
16340
  subscription: {
15861
16341
  // Again, accept anything
15862
16342
  // but reject the same stream twice
@@ -15867,10 +16347,36 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15867
16347
  }
15868
16348
  },
15869
16349
  extraValidation: (ctx) => {
15870
- const audioStreams = ctx.subscriptions.filter((s) => s.streams.select.includes("audio"));
16350
+ const audioStreams = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("audio"));
15871
16351
  if (audioStreams.length == 0) {
15872
16352
  ctx.addError("AutoCMAF requires at least one audio stream");
15873
16353
  }
16354
+ const uniqueVideoStreamNodes = ctx.subscriptions.reduce((acc, s) => {
16355
+ if (s.validatedStreams.select.includes("video")) {
16356
+ if (!acc.includes(s.source)) {
16357
+ acc.push(s.source);
16358
+ }
16359
+ }
16360
+ return acc;
16361
+ }, []);
16362
+ if (uniqueVideoStreamNodes.length > 1) {
16363
+ ctx.addWarning("More than one video source detected, did you mean to do this? (For example: Did you subscribe to both a source *and* a ladder?)");
16364
+ }
16365
+ if (ctx.config.drmProvider && ctx.config.__global) {
16366
+ if (ctx.config.drmProvider === "ezdrm") {
16367
+ if (!ctx.config.__global.ezdrmConfig?.token) {
16368
+ ctx.addError("Provide EZDRM token in global configuration");
16369
+ }
16370
+ }
16371
+ if (ctx.config.drmProvider === "axinom") {
16372
+ if (!ctx.config.__global.axinomConfig?.tenantId) {
16373
+ ctx.addError("Provide Axinom DRM Tenant ID in global configuration");
16374
+ }
16375
+ if (!ctx.config.__global.axinomConfig?.managementKey) {
16376
+ ctx.addError("Provide Axinom DRM Management Key in global configuration");
16377
+ }
16378
+ }
16379
+ }
15874
16380
  },
15875
16381
  display: (desc) => {
15876
16382
  return {
@@ -15878,22 +16384,35 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15878
16384
  };
15879
16385
  },
15880
16386
  runtime: {
15881
- initialState: () => ({}),
16387
+ initialState: () => ({
16388
+ enabled: true
16389
+ }),
15882
16390
  handleEvent(ev, state) {
15883
16391
  const evType = ev.type;
15884
16392
  switch (evType) {
15885
16393
  case "url-published":
15886
16394
  state.url = ev.url;
16395
+ state.drmToken = ev.drmToken;
16396
+ break;
16397
+ case "output-enabled":
16398
+ state.enabled = true;
16399
+ break;
16400
+ case "output-disabled":
16401
+ state.enabled = false;
15887
16402
  break;
15888
16403
  default:
15889
16404
  assertUnreachable3(evType);
15890
16405
  }
15891
16406
  return { ...state };
15892
16407
  },
15893
- summary: SummaryView6,
16408
+ //summary: SummaryView,
15894
16409
  fullscreen: FullscreenView2
15895
16410
  },
15896
16411
  configForm: {
16412
+ global: {
16413
+ ezdrmConfig: (0, import_config.GlobalEzDrmConfig)(R),
16414
+ axinomConfig: (0, import_config.GlobalAxinomConfig)(R)
16415
+ },
15897
16416
  form: {
15898
16417
  name: {
15899
16418
  help: "The name of the multivariant/dash playlist",
@@ -15961,6 +16480,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15961
16480
  help: "How many segments back should a player start",
15962
16481
  hint: {
15963
16482
  type: "numeric",
16483
+ optional: true,
15964
16484
  validation: Z.number().min(3).max(10).int().optional()
15965
16485
  }
15966
16486
  },
@@ -15968,6 +16488,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15968
16488
  help: "How many parts back should a player start",
15969
16489
  hint: {
15970
16490
  type: "numeric",
16491
+ optional: true,
15971
16492
  validation: Z.number().min(3).max(10).int().optional()
15972
16493
  }
15973
16494
  }
@@ -15985,12 +16506,11 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15985
16506
  help: "The hostname of the s3 bucket to push to",
15986
16507
  hint: {
15987
16508
  type: "text",
15988
- defaultValue: "",
15989
16509
  validation: Hostname
15990
16510
  }
15991
16511
  },
15992
16512
  prefix: {
15993
- help: "The sub directory of the bucket to place playlists + segments into",
16513
+ help: "The sub directory of the bucket to place playlists and segments into",
15994
16514
  hint: {
15995
16515
  type: "text",
15996
16516
  defaultValue: ""
@@ -16005,6 +16525,23 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
16005
16525
  }
16006
16526
  }
16007
16527
  }
16528
+ },
16529
+ drmProvider: {
16530
+ help: "Encrypt with a DRM provider (if configured globally)",
16531
+ hint: {
16532
+ type: "select",
16533
+ optional: true,
16534
+ options: [
16535
+ {
16536
+ display: "EZDRM",
16537
+ value: "ezdrm"
16538
+ },
16539
+ {
16540
+ display: "Axinom DRM",
16541
+ value: "axinom"
16542
+ }
16543
+ ]
16544
+ }
16008
16545
  }
16009
16546
  }
16010
16547
  }
@@ -16015,15 +16552,16 @@ function assertUnreachable3(_) {
16015
16552
  }
16016
16553
 
16017
16554
  // build/output.preview/info.js
16018
- var import_react8 = __toESM(require_react());
16019
- var import_config = __toESM(require_config());
16555
+ var import_react7 = __toESM(require_react());
16556
+ var import_config2 = __toESM(require_config());
16020
16557
  function info_default8(R) {
16021
16558
  const { defineComponent, Av, validation: { JitterBuffer } } = R;
16022
- const InlineView13 = import_react8.default.lazy(async () => Promise.resolve().then(() => (init_inline_view3(), inline_view_exports3)));
16559
+ const InlineView13 = import_react7.default.lazy(async () => Promise.resolve().then(() => (init_inline_view3(), inline_view_exports3)));
16023
16560
  return defineComponent({
16024
16561
  identifier: "output.preview",
16025
16562
  category: "output",
16026
16563
  name: "Preview",
16564
+ description: "Preview allows for the real-time preview of media streams. It provides a way to visualize and monitor the output from various media sources before final processing or distribution.",
16027
16565
  subscription: {
16028
16566
  accepts: {
16029
16567
  type: "single-stream",
@@ -16032,8 +16570,8 @@ function info_default8(R) {
16032
16570
  produces: void 0
16033
16571
  },
16034
16572
  extraValidation: (ctx) => {
16035
- const video = ctx.subscriptions.filter((s) => s.streams.select.includes("video"));
16036
- const audio = ctx.subscriptions.filter((s) => s.streams.select.includes("audio"));
16573
+ const video = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("video"));
16574
+ const audio = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("audio"));
16037
16575
  if (video.length == 1 && audio.length == 1)
16038
16576
  return;
16039
16577
  if (video.length == 0) {
@@ -16073,11 +16611,13 @@ function info_default8(R) {
16073
16611
  },
16074
16612
  configForm: {
16075
16613
  global: {
16076
- iceServers: (0, import_config.GlobalIceServers)(R),
16077
- hardware: (0, import_config.HardwareSelection)()
16614
+ iceServers: (0, import_config2.GlobalIceServers)(R),
16615
+ hardware: (0, import_config2.HardwareSelection)()
16078
16616
  },
16079
16617
  form: {
16080
- bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } }
16618
+ bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16619
+ skipTranscode: { help: "Skip transcoding for WebRTC-ready streams", hint: { type: "boolean", defaultValue: false } },
16620
+ showPreview: { help: "Show video preview", hint: { type: "boolean", defaultValue: true } }
16081
16621
  }
16082
16622
  }
16083
16623
  });
@@ -16087,13 +16627,14 @@ function assertUnreachable4(_) {
16087
16627
  }
16088
16628
 
16089
16629
  // build/output.rtmp/info.js
16090
- var import_react9 = __toESM(require_react());
16630
+ var import_react8 = __toESM(require_react());
16091
16631
  function info_default9({ defineComponent, Av, validation: { Z, JitterBuffer } }) {
16092
- const InlineView13 = import_react9.default.lazy(async () => Promise.resolve().then(() => (init_inline_view4(), inline_view_exports4)));
16632
+ const InlineView13 = import_react8.default.lazy(async () => Promise.resolve().then(() => (init_inline_view4(), inline_view_exports4)));
16093
16633
  return defineComponent({
16094
16634
  identifier: "output.rtmp",
16095
16635
  category: "output",
16096
16636
  name: "RTMP Egest",
16637
+ description: "This component handles the output of RTMP (Real-Time Messaging Protocol) streams. It is used to connect to a remote RTMP server and manage the streaming of media. ",
16097
16638
  subscription: {
16098
16639
  // No validation?
16099
16640
  // Accept either *just* audio, or *just* video, or audio *and* video
@@ -16144,11 +16685,12 @@ function assertUnreachable5(_) {
16144
16685
  }
16145
16686
 
16146
16687
  // build/output.srt/info.js
16147
- var import_react10 = __toESM(require_react());
16688
+ var import_react9 = __toESM(require_react());
16689
+ var import_util = __toESM(require_util());
16148
16690
  function info_default10(registration) {
16149
16691
  const { defineComponent, All, validation } = registration;
16150
- const { Port, IpAddress, JitterBuffer, SrtPassphrase, SrtStreamId } = validation;
16151
- const SocketConfiguration2 = import_react10.default.lazy(async () => {
16692
+ const { Port, Hostname, JitterBuffer, SrtPassphrase, SrtStreamId } = validation;
16693
+ const SocketConfiguration2 = import_react9.default.lazy(async () => {
16152
16694
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
16153
16695
  return { default: views.SocketConfiguration };
16154
16696
  });
@@ -16156,6 +16698,7 @@ function info_default10(registration) {
16156
16698
  identifier: "output.srt",
16157
16699
  category: "output",
16158
16700
  name: "SRT Egest",
16701
+ description: "This component manages the sending of SRT (Secure Reliable Transport) streams. It allows you to configure various settings to control how the SRT output is handled, including connection details, buffer settings, and delay options.",
16159
16702
  subscription: {
16160
16703
  // No validation?
16161
16704
  // Streams have to be unique? That's a stretch goal
@@ -16167,11 +16710,30 @@ function info_default10(registration) {
16167
16710
  display: (desc) => {
16168
16711
  return {
16169
16712
  port: desc.config.port?.toString() ?? "",
16170
- ip: desc.config.ip,
16713
+ host: desc.config.host,
16171
16714
  mode: desc.config.mode,
16172
16715
  bufferDelayMs: desc.config.bufferDelayMs?.toString() ?? "none"
16173
16716
  };
16174
16717
  },
16718
+ runtime: {
16719
+ initialState: () => ({
16720
+ enabled: true
16721
+ }),
16722
+ handleEvent(ev, state) {
16723
+ const evType = ev.type;
16724
+ switch (evType) {
16725
+ case "output-enabled":
16726
+ state.enabled = true;
16727
+ break;
16728
+ case "output-disabled":
16729
+ state.enabled = false;
16730
+ break;
16731
+ default:
16732
+ (0, import_util.assertUnreachable)(evType);
16733
+ }
16734
+ return { ...state };
16735
+ }
16736
+ },
16175
16737
  configForm: {
16176
16738
  form: {
16177
16739
  port: {
@@ -16187,7 +16749,7 @@ function info_default10(registration) {
16187
16749
  }
16188
16750
  }
16189
16751
  },
16190
- ip: { help: "The IP address this SRT output will connect to or listen on", hint: { type: "text", validation: IpAddress, defaultValue: "0.0.0.0" } },
16752
+ host: { help: "The IP address/Hostname this SRT output will connect to or listen on", hint: { type: "text", validation: Hostname, defaultValue: "0.0.0.0" } },
16191
16753
  bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16192
16754
  avDelayMs: { help: "How many milliseconds to delay A/V to account for subtitles/ancillary data", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 50 } },
16193
16755
  mode: {
@@ -16207,8 +16769,8 @@ function info_default10(registration) {
16207
16769
  ]
16208
16770
  }
16209
16771
  },
16210
- passphrase: { help: "Optional: Authentication for this SRT output", hint: { type: "text", validation: SrtPassphrase } },
16211
- streamId: { help: "Optional: StreamId to use when calling a remote listener", hint: { type: "text", validation: SrtStreamId } },
16772
+ passphrase: { help: "Optional: Authentication for this SRT output", hint: { type: "text", optional: true, validation: SrtPassphrase } },
16773
+ streamId: { help: "Optional: StreamId to use when calling a remote listener", hint: { type: "text", optional: true, validation: SrtStreamId } },
16212
16774
  socketOptions: {
16213
16775
  help: "Socket Options",
16214
16776
  hint: {
@@ -16226,11 +16788,12 @@ function info_default10(registration) {
16226
16788
  init_info();
16227
16789
 
16228
16790
  // build/output.udpTs/info.js
16229
- function info_default12({ defineComponent, All, validation: { Port, IpAddress, JitterBuffer, Iface, Z } }) {
16791
+ function info_default12({ defineComponent, All, validation: { Port, Hostname, JitterBuffer, Iface, Z } }) {
16230
16792
  return defineComponent({
16231
16793
  identifier: "output.udpTs",
16232
16794
  category: "output",
16233
16795
  name: "UDP TS Egest",
16796
+ description: "This component outputs multiple media streams over UDP in TS (Transport Stream) format. It accepts multiple input streams and sends them to a specified IP address and port.",
16234
16797
  subscription: {
16235
16798
  // Just works with no validation
16236
16799
  // although uniqueness again, stretch goal
@@ -16242,7 +16805,7 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16242
16805
  display: (desc) => {
16243
16806
  return {
16244
16807
  port: desc.config.port.toString(),
16245
- destinationIp: desc.config.destinationIp,
16808
+ destinationIp: desc.config.destinationHost,
16246
16809
  interface: desc.config.interface,
16247
16810
  bufferDelayMs: desc.config.bufferDelayMs?.toString() ?? "none"
16248
16811
  };
@@ -16250,7 +16813,7 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16250
16813
  configForm: {
16251
16814
  form: {
16252
16815
  port: { help: "The port this UDP TS output will send to", hint: { type: "numeric", validation: Port, defaultValue: 8001 } },
16253
- destinationIp: { help: "The IP address this UDP TS output will send to", hint: { type: "text", validation: IpAddress, defaultValue: "127.0.0.1" } },
16816
+ destinationHost: { help: "The IP address/Hostname this UDP TS output will send to", hint: { type: "text", validation: Hostname, defaultValue: "127.0.0.1" } },
16254
16817
  bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16255
16818
  interface: { help: "Which interface to bind to for publishing", hint: { type: "text", validation: Z.union([Z.string().length(0), Iface]), defaultValue: "any" } }
16256
16819
  }
@@ -16259,13 +16822,16 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16259
16822
  }
16260
16823
 
16261
16824
  // build/output.whep/info.js
16262
- var import_config2 = __toESM(require_config());
16825
+ var import_config3 = __toESM(require_config());
16826
+ var import_react12 = __toESM(require_react());
16263
16827
  function info_default13(R) {
16264
16828
  const { defineComponent, Av, validation: { JitterBuffer } } = R;
16829
+ const InlineView13 = import_react12.default.lazy(async () => Promise.resolve().then(() => (init_inline_view6(), inline_view_exports6)));
16265
16830
  return defineComponent({
16266
16831
  identifier: "output.whep",
16267
16832
  category: "output",
16268
16833
  name: "WHEP Egest",
16834
+ description: "This component allows us to use WebRTC egress for outputs.",
16269
16835
  subscription: {
16270
16836
  // No validation?
16271
16837
  // Accept either *just* audio, or *just* video, or audio *and* video
@@ -16280,24 +16846,48 @@ function info_default13(R) {
16280
16846
  display: (_desc) => {
16281
16847
  return {};
16282
16848
  },
16849
+ css: ["styles.css"],
16850
+ runtime: {
16851
+ initialState: () => ({}),
16852
+ handleEvent(ev, state) {
16853
+ const evType = ev.type;
16854
+ switch (evType) {
16855
+ case "url-published":
16856
+ state.url = ev.url;
16857
+ break;
16858
+ default:
16859
+ assertUnreachable8(evType);
16860
+ }
16861
+ return { ...state };
16862
+ },
16863
+ inline: InlineView13
16864
+ },
16283
16865
  configForm: {
16284
16866
  global: {
16285
- iceServers: (0, import_config2.GlobalIceServers)(R)
16867
+ iceServers: (0, import_config3.GlobalIceServers)(R)
16286
16868
  },
16287
16869
  form: {
16288
- bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } }
16870
+ bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16871
+ showPreview: { help: "Show video preview", hint: { type: "boolean", defaultValue: true } }
16289
16872
  }
16290
16873
  }
16291
16874
  });
16292
16875
  }
16876
+ function assertUnreachable8(_) {
16877
+ throw new Error("Didn't expect to get here");
16878
+ }
16293
16879
 
16294
16880
  // build/processor.browserOverlay/info.js
16295
- var import_config3 = __toESM(require_config());
16881
+ var import_config4 = __toESM(require_config());
16882
+ var import_react14 = __toESM(require_react());
16883
+ var SummaryView6 = import_react14.default.lazy(async () => Promise.resolve().then(() => (init_summary_view3(), summary_view_exports3)));
16884
+ var InlineView10 = import_react14.default.lazy(async () => Promise.resolve().then(() => (init_inline_view7(), inline_view_exports7)));
16296
16885
  function info_default14({ defineComponent, Video, validation: { Z } }) {
16297
16886
  return defineComponent({
16298
- identifier: "processor.transform.browserOverlay",
16887
+ identifier: "processor.browserOverlay",
16299
16888
  category: "processor",
16300
16889
  name: "Browser Overlay",
16890
+ description: "Capture a live URL and overlay onto a video",
16301
16891
  subscription: {
16302
16892
  // Only accept a single video stream
16303
16893
  accepts: {
@@ -16314,12 +16904,33 @@ function info_default14({ defineComponent, Video, validation: { Z } }) {
16314
16904
  },
16315
16905
  display: (desc) => {
16316
16906
  return {
16317
- url: desc.config?.url
16907
+ url: desc.config.url
16318
16908
  };
16319
16909
  },
16910
+ runtime: {
16911
+ summary: SummaryView6,
16912
+ inline: InlineView10,
16913
+ initialState: () => ({
16914
+ currentUrl: "",
16915
+ enabled: true
16916
+ }),
16917
+ handleEvent: (ev, state) => {
16918
+ const evType = ev.type;
16919
+ switch (evType) {
16920
+ case "url-changed":
16921
+ return { ...state, currentUrl: ev.url };
16922
+ case "enabled":
16923
+ return { ...state, enabled: true };
16924
+ case "disabled":
16925
+ return { ...state, enabled: false };
16926
+ default:
16927
+ assertUnreachable9(evType);
16928
+ }
16929
+ }
16930
+ },
16320
16931
  configForm: {
16321
16932
  global: {
16322
- hardware: (0, import_config3.HardwareSelection)()
16933
+ hardware: (0, import_config4.HardwareSelection)()
16323
16934
  },
16324
16935
  form: {
16325
16936
  url: { help: "URL to render on top of the video", hint: { type: "text", validation: Z.string().url(), defaultValue: "" } }
@@ -16327,15 +16938,19 @@ function info_default14({ defineComponent, Video, validation: { Z } }) {
16327
16938
  }
16328
16939
  });
16329
16940
  }
16941
+ function assertUnreachable9(_) {
16942
+ throw new Error("Didn't expect to get here");
16943
+ }
16330
16944
 
16331
16945
  // build/processor.cascadingSwitch/info.js
16332
16946
  function info_default15({ defineComponent, Av, React: React14, common: { Resolutions, FrameRates } }) {
16333
16947
  const SourceSelection = React14.lazy(async () => Promise.resolve().then(() => (init_source_selection(), source_selection_exports)));
16334
- const InlineView13 = React14.lazy(async () => Promise.resolve().then(() => (init_inline_view6(), inline_view_exports6)));
16948
+ const InlineView13 = React14.lazy(async () => Promise.resolve().then(() => (init_inline_view8(), inline_view_exports8)));
16335
16949
  return defineComponent({
16336
- identifier: "processor.control.cascadingSwitch",
16950
+ identifier: "processor.cascadingSwitch",
16337
16951
  category: "processor",
16338
16952
  name: "Cascading Switch",
16953
+ description: "This component manages multiple A/V (audio and video) sources based on priority, allowing for the configuration of settings such as resolution, frame rate, sample rate, and channel layout.",
16339
16954
  subscription: {
16340
16955
  // This needs to change anyway
16341
16956
  // but it'll be the same as MCS
@@ -16350,10 +16965,10 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16350
16965
  },
16351
16966
  extraValidation: function(ctx) {
16352
16967
  ctx.subscriptions.forEach((s) => {
16353
- if (!s.streams.select.includes("video")) {
16968
+ if (!s.validatedStreams.select.includes("video")) {
16354
16969
  ctx.addError(`Subscription to ${s.source} is missing video`);
16355
16970
  }
16356
- if (!s.streams.select.includes("audio")) {
16971
+ if (!s.validatedStreams.select.includes("audio")) {
16357
16972
  ctx.addError(`Subscription to ${s.source} is missing audio`);
16358
16973
  }
16359
16974
  if (s.streams.type == "take-all-streams") {
@@ -16409,7 +17024,7 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16409
17024
  state.availableSources.splice(state.availableSources.indexOf(ev.source), 1);
16410
17025
  return { ...state };
16411
17026
  default:
16412
- assertUnreachable7(evType);
17027
+ assertUnreachable10(evType);
16413
17028
  }
16414
17029
  },
16415
17030
  inline: InlineView13,
@@ -16460,96 +17075,22 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16460
17075
  }
16461
17076
  });
16462
17077
  }
16463
- function assertUnreachable7(_) {
16464
- throw new Error("Didn't expect to get here");
16465
- }
16466
-
16467
- // build/processor.dynamicBug/info.js
16468
- var import_config4 = __toESM(require_config());
16469
- var import_react15 = __toESM(require_react());
16470
- function info_default16({ defineComponent, Video }) {
16471
- const BugSelection2 = import_react15.default.lazy(async () => Promise.resolve().then(() => (init_bug_selection(), bug_selection_exports)));
16472
- const SummaryView6 = import_react15.default.lazy(async () => Promise.resolve().then(() => (init_summary_view3(), summary_view_exports3)));
16473
- return defineComponent({
16474
- identifier: "processor.dynamicBug",
16475
- category: "processor",
16476
- name: "Dynamic Bug",
16477
- subscription: {
16478
- // Only accept a single video stream
16479
- accepts: {
16480
- type: "single-stream",
16481
- media: Video
16482
- },
16483
- produces: {
16484
- type: "single-stream",
16485
- media: Video
16486
- }
16487
- },
16488
- extraValidation: function(ctx) {
16489
- ctx.requireVideo(1);
16490
- },
16491
- display: (desc) => {
16492
- return {
16493
- default: desc.config.defaultBug ?? "none"
16494
- };
16495
- },
16496
- runtime: {
16497
- summary: SummaryView6,
16498
- initialState: () => ({}),
16499
- handleEvent: (ev, state) => {
16500
- const evType = ev.type;
16501
- switch (evType) {
16502
- case "bug-changed":
16503
- return { ...state, activeBug: { file: ev.file, position: ev.position } };
16504
- default:
16505
- assertUnreachable8(evType);
16506
- }
16507
- }
16508
- },
16509
- configForm: {
16510
- global: {
16511
- hardware: (0, import_config4.HardwareSelection)()
16512
- },
16513
- form: {
16514
- defaultBug: {
16515
- help: "The default bug to render on the video (if any)",
16516
- hint: {
16517
- type: "custom",
16518
- component: BugSelection2
16519
- }
16520
- },
16521
- defaultPosition: {
16522
- help: "The default location to render the bug in",
16523
- hint: {
16524
- type: "select",
16525
- optional: true,
16526
- options: [
16527
- { value: "topleft", display: "Top Left" },
16528
- { value: "topright", display: "Top Right" },
16529
- { value: "bottomleft", display: "Bottom Left" },
16530
- { value: "bottomright", display: "Bottom Right" }
16531
- ]
16532
- }
16533
- }
16534
- }
16535
- }
16536
- });
16537
- }
16538
- function assertUnreachable8(_) {
17078
+ function assertUnreachable10(_) {
16539
17079
  throw new Error("Didn't expect to get here");
16540
17080
  }
16541
17081
 
16542
17082
  // build/processor.fixedLadder/info.js
16543
17083
  var import_react17 = __toESM(require_react());
16544
17084
  var import_config5 = __toESM(require_config());
16545
- function info_default17({ defineComponent, Video }) {
17085
+ function info_default16({ defineComponent, Video }) {
16546
17086
  const RungView = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_rung_view(), rung_view_exports)));
16547
17087
  const CodecEditor3 = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_codec_editor(), codec_editor_exports)));
16548
17088
  const CodecView = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_codec_view(), codec_view_exports)));
16549
17089
  return defineComponent({
16550
- identifier: "processor.transform.fixedLadder",
17090
+ identifier: "processor.fixedLadder",
16551
17091
  category: "processor",
16552
17092
  name: "Encode Ladder",
17093
+ description: "The Fixed Ladder Encoder is a processor component for encoding a single input video stream into multiple encoded renditions. It creates an encoding ladder, where each `rung` represents a different quality level or rendition of the original video, typically varying in resolution and bitrate.",
16553
17094
  subscription: {
16554
17095
  // Only accept a single video stream
16555
17096
  accepts: {
@@ -16665,6 +17206,7 @@ function info_default17({ defineComponent, Video }) {
16665
17206
  help: `Settings to use when encoding using ${mode} mode`,
16666
17207
  hint: {
16667
17208
  type: "form-item",
17209
+ optional: true,
16668
17210
  view: CodecView,
16669
17211
  form: {
16670
17212
  width: {
@@ -16707,7 +17249,7 @@ function createSoftwareRung(rung) {
16707
17249
  case "h264_320x180":
16708
17250
  return createRungImpl({ name: rung, threads: 1, bitrate: 800 });
16709
17251
  default:
16710
- return assertUnreachable9(rung);
17252
+ return assertUnreachable11(rung);
16711
17253
  }
16712
17254
  }
16713
17255
  function createMa35dRung(rung) {
@@ -16721,7 +17263,7 @@ function createMa35dRung(rung) {
16721
17263
  case "h264_320x180":
16722
17264
  return createMa35DH264RungImpl({ name: rung, bitrate: 1e3 });
16723
17265
  default:
16724
- return assertUnreachable9(rung);
17266
+ return assertUnreachable11(rung);
16725
17267
  }
16726
17268
  }
16727
17269
  function createNvidiaRung(rung) {
@@ -16735,7 +17277,7 @@ function createNvidiaRung(rung) {
16735
17277
  case "h264_320x180":
16736
17278
  return createNvidiaRungImpl({ name: rung, bitrate: 8e5 });
16737
17279
  default:
16738
- return assertUnreachable9(rung);
17280
+ return assertUnreachable11(rung);
16739
17281
  }
16740
17282
  }
16741
17283
  function createQuadraRung(rung) {
@@ -16749,7 +17291,7 @@ function createQuadraRung(rung) {
16749
17291
  case "h264_320x180":
16750
17292
  return createQuadraRungImpl({ name: rung, bitrate: 8e5 });
16751
17293
  default:
16752
- return assertUnreachable9(rung);
17294
+ return assertUnreachable11(rung);
16753
17295
  }
16754
17296
  }
16755
17297
  function createLoganRung(rung) {
@@ -16763,7 +17305,7 @@ function createLoganRung(rung) {
16763
17305
  case "h264_320x180":
16764
17306
  return createLoganRungImpl({ name: rung, bitrate: 8e5 });
16765
17307
  default:
16766
- return assertUnreachable9(rung);
17308
+ return assertUnreachable11(rung);
16767
17309
  }
16768
17310
  }
16769
17311
  function createRungImpl({ name, threads, bitrate }) {
@@ -16861,62 +17403,248 @@ function rungWidth(rungName) {
16861
17403
  function rungHeight(rungName) {
16862
17404
  return parseInt(rungName.split("_")[1].split(`x`)[1]);
16863
17405
  }
16864
- function assertUnreachable9(_) {
17406
+ function assertUnreachable11(_) {
16865
17407
  throw new Error("Didn't expect to get here");
16866
17408
  }
16867
17409
 
16868
- // build/processor.whisper-transcribe/info.js
16869
- function info_default18({ defineComponent, Av, Subtitle, validation: { Z } }) {
17410
+ // build/processor.onscreenGraphic/info.js
17411
+ var import_config6 = __toESM(require_config());
17412
+ var import_react20 = __toESM(require_react());
17413
+ function info_default17({ defineComponent, Video }) {
17414
+ const GraphicSelection2 = import_react20.default.lazy(async () => Promise.resolve().then(() => (init_image_selection(), image_selection_exports)));
17415
+ const SummaryView8 = import_react20.default.lazy(async () => Promise.resolve().then(() => (init_summary_view4(), summary_view_exports4)));
16870
17416
  return defineComponent({
16871
- identifier: "processor.whisper-transcribe",
17417
+ identifier: "processor.onscreenGraphic",
16872
17418
  category: "processor",
16873
- name: "Whisper Transcribe",
17419
+ name: "Onscreen Graphic",
17420
+ description: "Overlay graphics onto a video",
16874
17421
  subscription: {
17422
+ // Only accept a single video stream
16875
17423
  accepts: {
16876
17424
  type: "single-stream",
16877
- media: Av
16878
- // video because we'll use the id of it..
17425
+ media: Video
16879
17426
  },
16880
17427
  produces: {
16881
- media: Subtitle,
16882
- type: "single-stream"
17428
+ type: "single-stream",
17429
+ media: Video
16883
17430
  }
16884
17431
  },
16885
17432
  extraValidation: function(ctx) {
16886
- const video = ctx.videoInputs();
16887
- const audio = ctx.audioInputs();
16888
- if (video.length !== 1) {
16889
- ctx.addError("Whisper Transcribe requires a single video stream to use as a reference");
16890
- }
16891
- if (audio.length !== 1) {
16892
- ctx.addError("Whisper Transcribe requires a single audio stream to transcribe");
16893
- }
17433
+ ctx.requireVideo(1);
16894
17434
  },
16895
17435
  display: (desc) => {
16896
17436
  return {
16897
- model: desc.config.model
17437
+ default: desc.config.initialGraphic ?? "none"
16898
17438
  };
16899
17439
  },
17440
+ runtime: {
17441
+ summary: SummaryView8,
17442
+ initialState: () => ({}),
17443
+ handleEvent: (ev, state) => {
17444
+ const evType = ev.type;
17445
+ switch (evType) {
17446
+ case "graphic-changed":
17447
+ return { ...state, activeGraphic: { file: ev.file, position: ev.position } };
17448
+ case "video-changed":
17449
+ return { ...state, currentVideo: ev.currentVideo };
17450
+ case "graphic-loaded":
17451
+ return { ...state, currentGraphic: ev.currentGraphic };
17452
+ default:
17453
+ assertUnreachable13(evType);
17454
+ }
17455
+ }
17456
+ },
17457
+ configForm: {
17458
+ global: {
17459
+ hardware: (0, import_config6.HardwareSelection)()
17460
+ },
17461
+ form: {
17462
+ initialGraphic: {
17463
+ help: "The initial graphic to render on the video (if any)",
17464
+ hint: {
17465
+ type: "custom",
17466
+ optional: true,
17467
+ component: GraphicSelection2
17468
+ }
17469
+ },
17470
+ initialPosition: {
17471
+ help: "The initial location at which to render the graphic",
17472
+ hint: {
17473
+ type: "select",
17474
+ optional: true,
17475
+ options: [
17476
+ { value: { type: "named", position: "topleft" }, display: "Top Left" },
17477
+ { value: { type: "named", position: "topright" }, display: "Top Right" },
17478
+ { value: { type: "named", position: "bottomleft" }, display: "Bottom Left" },
17479
+ { value: { type: "named", position: "bottomright" }, display: "Bottom Right" },
17480
+ { value: { type: "named", position: "center" }, display: "Centered" }
17481
+ ]
17482
+ }
17483
+ }
17484
+ }
17485
+ }
17486
+ });
17487
+ }
17488
+ function assertUnreachable13(_) {
17489
+ throw new Error("Didn't expect to get here");
17490
+ }
17491
+
17492
+ // build/processor.streamKeyOverride/info.js
17493
+ function info_default18({ defineComponent, All, validation: { Z } }) {
17494
+ return defineComponent({
17495
+ identifier: "processor.StreamKeyOverride",
17496
+ category: "processor",
17497
+ name: "Stream Key Override",
17498
+ description: "Override stream keys for several streams at once, setting some components of the keys and optionally incrementing stream ID.",
17499
+ subscription: {
17500
+ accepts: {
17501
+ type: "multi-stream",
17502
+ media: All
17503
+ },
17504
+ produces: {
17505
+ type: "fixed-list",
17506
+ possibleMedia: All,
17507
+ keys: (cfg, subs) => {
17508
+ const outputs = subs.flatMap((sub) => {
17509
+ const sourceNode = sub.document.components[sub.source];
17510
+ if (!sourceNode)
17511
+ return [];
17512
+ const produces = sourceNode.info.subscription.produces;
17513
+ if (produces?.type === "fixed-list") {
17514
+ return produces.keys(sourceNode.config, sourceNode.subscriptions).map((sel) => ({ ...sel, key: `${sourceNode.id}-${sel.key}`, display: `${sourceNode.config.displayName}: ${sel.display}` }));
17515
+ } else {
17516
+ return [{ key: `${sourceNode.id}`, display: `${sourceNode.config.displayName}`, media: produces ? produces.media : All }];
17517
+ }
17518
+ });
17519
+ if (cfg.output === "merged") {
17520
+ const media = Array.from(new Set(outputs.flatMap((x) => x.media)));
17521
+ return [{ key: `merged`, display: "Merged", media }];
17522
+ }
17523
+ return outputs;
17524
+ },
17525
+ selector: () => {
17526
+ console.error("Use selectOutputs from process.streamKeyOverride/runtime.ts, not selector from info.ts");
17527
+ return [];
17528
+ }
17529
+ }
17530
+ },
17531
+ display: ({ config }) => {
17532
+ const disp = {};
17533
+ disp.mode = config.mode || "simple";
17534
+ disp.output = config.output || "individually-selectable";
17535
+ if (config.sourceName) {
17536
+ disp.sourceName = config.sourceName;
17537
+ }
17538
+ if (config.programNumber !== void 0) {
17539
+ disp.programNumber = String(config.programNumber);
17540
+ }
17541
+ if (config.streamId !== void 0) {
17542
+ disp.streamId = String(config.streamId);
17543
+ }
17544
+ if (config.renditionName) {
17545
+ disp.renditionName = config.renditionName;
17546
+ }
17547
+ return disp;
17548
+ },
17549
+ extraValidation: (ctx) => {
17550
+ const { config, subscriptions } = ctx;
17551
+ if ((config.mode || "simple") == "simple" && config.sourceName && config.programNumber !== void 0 && config.streamId !== void 0 && config.renditionName) {
17552
+ if (subscriptions.length > 1)
17553
+ ctx.addError("A fully specified stream key override must only subscribe to one stream, or use a mode other than simple");
17554
+ }
17555
+ if (config.mode === "by-media-type" && config.streamId === void 0) {
17556
+ ctx.addError("You must specify the starting streamId for a by-media-type stream key override");
17557
+ }
17558
+ if (config.output === "merged" && !config.sourceName) {
17559
+ ctx.addError("You must specify a sourceName for a single merged output");
17560
+ }
17561
+ },
16900
17562
  configForm: {
16901
17563
  form: {
16902
- model: { help: "The ggml model path", hint: { type: "text", validation: Z.string().min(1, "Choosing a model is mandatory") } },
16903
- translate: { help: "Whether to translate the output to English", hint: { type: "boolean", defaultValue: false } },
16904
- language: { help: "Source language (otherwise automatic)", hint: { type: "text", validation: Z.union([Z.string().length(0), Z.string().min(1)]) } }
17564
+ mode: {
17565
+ help: "Multi-stream behavior",
17566
+ hint: {
17567
+ type: "select",
17568
+ defaultValue: "simple",
17569
+ options: [
17570
+ {
17571
+ display: "Override values directly",
17572
+ value: "simple"
17573
+ },
17574
+ {
17575
+ display: "Increment stream ID by media type (video, audio, ...)",
17576
+ value: "by-media-type"
17577
+ },
17578
+ {
17579
+ display: "Increment stream ID per program in order of subscription",
17580
+ value: "in-order"
17581
+ }
17582
+ ]
17583
+ }
17584
+ },
17585
+ output: {
17586
+ help: "Output individual streams or a single merged stream",
17587
+ hint: {
17588
+ type: "select",
17589
+ defaultValue: "individually-selectable",
17590
+ options: [
17591
+ {
17592
+ display: "Individual inputs can be selected in the output",
17593
+ value: "individually-selectable"
17594
+ },
17595
+ {
17596
+ display: "The outputs are merged into a single stream",
17597
+ value: "merged"
17598
+ }
17599
+ ]
17600
+ }
17601
+ },
17602
+ sourceName: {
17603
+ help: "Override source name",
17604
+ hint: {
17605
+ type: "text",
17606
+ optional: true
17607
+ }
17608
+ },
17609
+ programNumber: {
17610
+ help: "Override program number",
17611
+ hint: {
17612
+ type: "numeric",
17613
+ optional: true,
17614
+ validation: Z.number().min(0).int().optional()
17615
+ }
17616
+ },
17617
+ streamId: {
17618
+ help: "Override stream ID",
17619
+ hint: {
17620
+ type: "numeric",
17621
+ optional: true,
17622
+ validation: Z.number().min(0).int().optional()
17623
+ }
17624
+ },
17625
+ renditionName: {
17626
+ help: "Override rendition name",
17627
+ hint: {
17628
+ type: "text",
17629
+ optional: true
17630
+ }
17631
+ }
16905
17632
  }
16906
17633
  }
16907
17634
  });
16908
17635
  }
16909
17636
 
16910
- // build/util.latency/info.js
16911
- var import_react19 = __toESM(require_react());
17637
+ // build/util.stats.latency/info.js
17638
+ var import_react22 = __toESM(require_react());
16912
17639
  function info_default19(R) {
16913
17640
  const { defineComponent } = R;
16914
- const InlineView13 = import_react19.default.lazy(async () => Promise.resolve().then(() => (init_inline_view7(), inline_view_exports7)));
16915
- const SourceNodeSelection2 = import_react19.default.lazy(async () => Promise.resolve().then(() => (init_source_node_selection(), source_node_selection_exports)));
17641
+ const InlineView13 = import_react22.default.lazy(async () => Promise.resolve().then(() => (init_inline_view9(), inline_view_exports9)));
17642
+ const SourceNodeSelection2 = import_react22.default.lazy(async () => Promise.resolve().then(() => (init_source_node_selection(), source_node_selection_exports)));
16916
17643
  return defineComponent({
16917
- identifier: "util.latency-stats",
17644
+ identifier: "util.stats.latency",
16918
17645
  category: "output",
16919
17646
  name: "Latency Probe",
17647
+ description: "This component tracks and processes latency statistics within a media processing pipeline.",
16920
17648
  subscription: {
16921
17649
  accepts: void 0,
16922
17650
  produces: void 0
@@ -16939,7 +17667,7 @@ function info_default19(R) {
16939
17667
  break;
16940
17668
  }
16941
17669
  default:
16942
- assertUnreachable10(evType);
17670
+ assertUnreachable14(evType);
16943
17671
  }
16944
17672
  return { ...state };
16945
17673
  },
@@ -16993,113 +17721,7 @@ function info_default19(R) {
16993
17721
  }
16994
17722
  });
16995
17723
  }
16996
- function assertUnreachable10(_) {
16997
- throw new Error("Didn't expect to get here");
16998
- }
16999
-
17000
- // build/util.ma35d/info.js
17001
- var import_react21 = __toESM(require_react());
17002
- function info_default20(R) {
17003
- const { defineComponent } = R;
17004
- const InlineView13 = import_react21.default.lazy(async () => Promise.resolve().then(() => (init_inline_view8(), inline_view_exports8)));
17005
- return defineComponent({
17006
- identifier: "util.ma35d-stats",
17007
- category: "output",
17008
- name: "MA35D Stats",
17009
- subscription: {
17010
- accepts: void 0,
17011
- produces: void 0
17012
- },
17013
- display: (_desc) => {
17014
- return {};
17015
- },
17016
- runtime: {
17017
- initialState: () => ({
17018
- decoder: new Array(200).fill(0),
17019
- scaler: new Array(200).fill(0),
17020
- encoder: new Array(200).fill(0)
17021
- }),
17022
- handleEvent(ev, state) {
17023
- const evType = ev.type;
17024
- switch (evType) {
17025
- case "new-stats": {
17026
- state.decoder.push(ev.decoder);
17027
- state.scaler.push(ev.scaler);
17028
- state.encoder.push(ev.encoder);
17029
- while (state.decoder.length > 200) {
17030
- state.decoder.splice(0, 1);
17031
- state.scaler.splice(0, 1);
17032
- state.encoder.splice(0, 1);
17033
- }
17034
- break;
17035
- }
17036
- default:
17037
- assertUnreachable11(evType);
17038
- }
17039
- return { ...state };
17040
- },
17041
- inline: InlineView13
17042
- },
17043
- configForm: {
17044
- form: {}
17045
- }
17046
- });
17047
- }
17048
- function assertUnreachable11(_) {
17049
- throw new Error("Didn't expect to get here");
17050
- }
17051
-
17052
- // build/util.timestamps/info.js
17053
- var import_react23 = __toESM(require_react());
17054
- function info_default21(R) {
17055
- const { defineComponent, All } = R;
17056
- const InlineView13 = import_react23.default.lazy(async () => Promise.resolve().then(() => (init_inline_view9(), inline_view_exports9)));
17057
- return defineComponent({
17058
- identifier: "util.timestamps",
17059
- category: "output",
17060
- name: "Jitter",
17061
- subscription: {
17062
- accepts: {
17063
- type: "multi-stream",
17064
- media: All
17065
- },
17066
- produces: void 0
17067
- },
17068
- display: (_desc) => {
17069
- return {};
17070
- },
17071
- runtime: {
17072
- initialState: () => ({
17073
- timestamps: new Array(200).fill(0)
17074
- }),
17075
- handleEvent(ev, state) {
17076
- const evType = ev.type;
17077
- switch (evType) {
17078
- case "new-timestamp": {
17079
- const target = state.timestamps.find((e) => e.key === ev.key) ?? (() => {
17080
- const start = { key: ev.key, startTimeMs: (/* @__PURE__ */ new Date()).valueOf(), startTimestamp: ev.value, timestamps: [] };
17081
- state.timestamps.push(start);
17082
- return start;
17083
- })();
17084
- target.timestamps.push({ ts: ev.value, wall: ev.wallMs });
17085
- while (target.timestamps.length > 200) {
17086
- target.timestamps.splice(0, 1);
17087
- }
17088
- break;
17089
- }
17090
- default:
17091
- assertUnreachable12(evType);
17092
- }
17093
- return { ...state };
17094
- },
17095
- inline: InlineView13
17096
- },
17097
- configForm: {
17098
- form: {}
17099
- }
17100
- });
17101
- }
17102
- function assertUnreachable12(_) {
17724
+ function assertUnreachable14(_) {
17103
17725
  throw new Error("Didn't expect to get here");
17104
17726
  }
17105
17727
 
@@ -17136,8 +17758,6 @@ AllComponents.push((r) => info_default16(r));
17136
17758
  AllComponents.push((r) => info_default17(r));
17137
17759
  AllComponents.push((r) => info_default18(r));
17138
17760
  AllComponents.push((r) => info_default19(r));
17139
- AllComponents.push((r) => info_default20(r));
17140
- AllComponents.push((r) => info_default21(r));
17141
17761
  export {
17142
17762
  getNodeInfo as default
17143
17763
  };