@norskvideo/norsk-studio-built-ins 1.11.6 → 1.12.0-2025-01-27-b21c8c91

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 +1278 -776
  3. package/client/output.whep/styles.css +9 -0
  4. package/client/style.css +501 -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/openApi.d.ts +133 -0
  10. package/lib/input.rtmp/openApi.js +3 -0
  11. package/lib/input.rtmp/openApi.js.map +1 -0
  12. package/lib/input.rtmp/runtime.d.ts +24 -5
  13. package/lib/input.rtmp/runtime.js +166 -60
  14. package/lib/input.rtmp/runtime.js.map +1 -1
  15. package/lib/input.rtmp/summary-view.d.ts +3 -5
  16. package/lib/input.rtmp/summary-view.js +26 -6
  17. package/lib/input.rtmp/summary-view.js.map +1 -1
  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 +7 -5
  25. package/lib/input.srt-listener/info.js.map +1 -1
  26. package/lib/input.srt-listener/openApi.d.ts +133 -0
  27. package/lib/input.srt-listener/openApi.js +3 -0
  28. package/lib/input.srt-listener/openApi.js.map +1 -0
  29. package/lib/input.srt-listener/runtime.d.ts +26 -6
  30. package/lib/input.srt-listener/runtime.js +168 -57
  31. package/lib/input.srt-listener/runtime.js.map +1 -1
  32. package/lib/input.srt-listener/summary-view.d.ts +3 -5
  33. package/lib/input.srt-listener/summary-view.js +28 -4
  34. package/lib/input.srt-listener/summary-view.js.map +1 -1
  35. package/lib/input.srt-listener/types.yaml +99 -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 +4 -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 +8 -4
  59. package/lib/output.preview/inline-view.js.map +1 -1
  60. package/lib/output.preview/runtime.d.ts +4 -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 +48 -0
  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 +24 -0
  93. package/lib/output.whep/inline-view.js.map +1 -0
  94. package/lib/output.whep/runtime.d.ts +26 -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/openApi.d.ts +174 -0
  108. package/lib/processor.browserOverlay/openApi.js +3 -0
  109. package/lib/processor.browserOverlay/openApi.js.map +1 -0
  110. package/lib/processor.browserOverlay/runtime.d.ts +40 -6
  111. package/lib/processor.browserOverlay/runtime.js +151 -23
  112. package/lib/processor.browserOverlay/runtime.js.map +1 -1
  113. package/lib/processor.browserOverlay/summary-view.d.ts +4 -0
  114. package/lib/processor.browserOverlay/summary-view.js +27 -0
  115. package/lib/processor.browserOverlay/summary-view.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,9 +166,32 @@ 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 disconnectStream = async (streamId) => {
173
+ try {
174
+ const response = await fetch(`${urls.componentUrl}/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: "disconnect-source",
186
+ streamId
187
+ });
188
+ } catch (error) {
189
+ console.error("Failed to disconnect stream:", error);
190
+ }
191
+ };
192
+ const handleDisconnectStream = (streamId) => {
193
+ void disconnectStream(streamId);
194
+ };
153
195
  config.streamIds.forEach((streamId) => {
154
196
  if (state.connectedStreams.includes(streamId)) {
155
197
  connectedSources.push(streamId);
@@ -157,9 +199,9 @@ function SummaryView3({ state, config }) {
157
199
  disconnectedSources.push(streamId);
158
200
  }
159
201
  });
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) => {
202
+ 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) => {
203
+ return (0, import_jsx_runtime5.jsxs)("li", { className: "text-green-300", children: [streamId, (0, import_jsx_runtime5.jsx)("button", { onClick: () => handleDisconnectStream(streamId), className: "ml-2 px-2 py-1 text-xs bg-red-600 hover:bg-red-700 text-white rounded", children: "Disconnect" })] }, streamId);
204
+ }) })] }), (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) => {
163
205
  return (0, import_jsx_runtime5.jsx)("li", { className: "text-orange-300", children: streamId }, streamId);
164
206
  }) })] })] });
165
207
  }
@@ -172,117 +214,24 @@ var init_summary_view2 = __esm({
172
214
  }
173
215
  });
174
216
 
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
217
  // ../../node_modules/@norskvideo/norsk-studio/lib/shared/shared-views.js
277
218
  var require_shared_views = __commonJS({
278
219
  "../../node_modules/@norskvideo/norsk-studio/lib/shared/shared-views.js"(exports) {
279
220
  "use strict";
280
221
  Object.defineProperty(exports, "__esModule", { value: true });
281
222
  exports.GlobalIceServerView = GlobalIceServerView;
223
+ exports.EzDrmConfigView = EzDrmConfigView;
224
+ exports.AxinomConfigView = AxinomConfigView;
282
225
  var jsx_runtime_1 = require_jsx_runtime();
283
226
  function GlobalIceServerView(i) {
284
227
  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
228
  }
229
+ function EzDrmConfigView(i) {
230
+ 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" })] });
231
+ }
232
+ function AxinomConfigView(i) {
233
+ 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" })] });
234
+ }
286
235
  }
287
236
  });
288
237
 
@@ -327,6 +276,8 @@ var require_config = __commonJS({
327
276
  };
328
277
  Object.defineProperty(exports, "__esModule", { value: true });
329
278
  exports.GlobalIceServers = GlobalIceServers3;
279
+ exports.GlobalEzDrmConfig = GlobalEzDrmConfig2;
280
+ exports.GlobalAxinomConfig = GlobalAxinomConfig2;
330
281
  exports.contractHardwareAcceleration = contractHardwareAcceleration;
331
282
  exports.HardwareSelection = HardwareSelection5;
332
283
  exports.RootDataDir = RootDataDir;
@@ -356,7 +307,8 @@ var require_config = __commonJS({
356
307
  help: "Optional URL of the STUN/TURN server as accessed by the client (if different to the above)",
357
308
  hint: {
358
309
  type: "text",
359
- validation: f.validation.IceServer
310
+ validation: Z.union([Z.literal(""), f.validation.IceServer]).optional(),
311
+ optional: true
360
312
  }
361
313
  },
362
314
  username: {
@@ -382,6 +334,90 @@ var require_config = __commonJS({
382
334
  }
383
335
  };
384
336
  }
337
+ function GlobalEzDrmConfig2(_f) {
338
+ const EzDrmConfigView = react_1.default.lazy(async () => {
339
+ const views = await Promise.resolve().then(() => __importStar(require_shared_views()));
340
+ return { default: views.EzDrmConfigView };
341
+ });
342
+ return {
343
+ id: "ezdrm-config",
344
+ form: {
345
+ help: "Configuration for EZDRM",
346
+ hint: {
347
+ envOverride: true,
348
+ type: "form-item",
349
+ optional: true,
350
+ form: {
351
+ token: {
352
+ help: "Token for EZDRM",
353
+ hint: {
354
+ envOverride: true,
355
+ type: "text"
356
+ }
357
+ },
358
+ pX: {
359
+ help: "The last six digits of your Widevine Profile ID",
360
+ hint: {
361
+ envOverride: true,
362
+ defaultValue: "",
363
+ type: "text"
364
+ }
365
+ }
366
+ },
367
+ view: EzDrmConfigView
368
+ }
369
+ }
370
+ };
371
+ }
372
+ function GlobalAxinomConfig2(_f) {
373
+ const AxinomConfigView = react_1.default.lazy(async () => {
374
+ const views = await Promise.resolve().then(() => __importStar(require_shared_views()));
375
+ return { default: views.AxinomConfigView };
376
+ });
377
+ return {
378
+ id: "axinom-config",
379
+ form: {
380
+ help: "Configuration for Axinom DRM",
381
+ hint: {
382
+ envOverride: true,
383
+ type: "form-item",
384
+ form: {
385
+ tenantId: {
386
+ help: "Tenant ID from your Axinom DRM account",
387
+ hint: {
388
+ envOverride: true,
389
+ type: "text"
390
+ }
391
+ },
392
+ managementKey: {
393
+ help: "Management Key from your Axinom DRM account",
394
+ hint: {
395
+ envOverride: true,
396
+ type: "text"
397
+ }
398
+ },
399
+ comKeyId: {
400
+ help: "Communication Key ID from your Axinom DRM account",
401
+ hint: {
402
+ envOverride: true,
403
+ defaultValue: "",
404
+ type: "text"
405
+ }
406
+ },
407
+ comKey: {
408
+ help: "Communication Key from your Axinom DRM account",
409
+ hint: {
410
+ envOverride: true,
411
+ defaultValue: "",
412
+ type: "text"
413
+ }
414
+ }
415
+ },
416
+ view: AxinomConfigView
417
+ }
418
+ }
419
+ };
420
+ }
385
421
  function contractHardwareAcceleration(value, accepted) {
386
422
  if (!value)
387
423
  return void 0;
@@ -424,6 +460,70 @@ var require_config = __commonJS({
424
460
  }
425
461
  });
426
462
 
463
+ // external-global-plugin:hls.js
464
+ var require_hls = __commonJS({
465
+ "external-global-plugin:hls.js"(exports, module) {
466
+ module.exports = window.HlsJs;
467
+ }
468
+ });
469
+
470
+ // build/output.autoCmaf/fullscreen.js
471
+ var fullscreen_exports = {};
472
+ __export(fullscreen_exports, {
473
+ default: () => fullscreen_default
474
+ });
475
+ function FullscreenView({ state, config }) {
476
+ const url = state.url;
477
+ const id = config.id;
478
+ (0, import_react4.useEffect)(() => {
479
+ if (!url)
480
+ return;
481
+ const element = document.getElementById(`${id}-video`);
482
+ if (import_hls.default.isSupported()) {
483
+ const hls = new import_hls.default();
484
+ hls.loadSource(url);
485
+ hls.attachMedia(element);
486
+ } else if (element.canPlayType("application/vnd.apple.mpegurl")) {
487
+ element.src = url;
488
+ }
489
+ }, [state.url]);
490
+ if (!url)
491
+ return (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: "..." });
492
+ {
493
+ }
494
+ return (0, import_jsx_runtime6.jsx)("div", { children: (0, import_jsx_runtime6.jsx)("video", { controls: true, autoPlay: true, muted: true, id: `${id}-video` }) });
495
+ }
496
+ var import_jsx_runtime6, import_react4, import_hls, fullscreen_default;
497
+ var init_fullscreen = __esm({
498
+ "build/output.autoCmaf/fullscreen.js"() {
499
+ "use strict";
500
+ import_jsx_runtime6 = __toESM(require_jsx_runtime());
501
+ import_react4 = __toESM(require_react());
502
+ import_hls = __toESM(require_hls());
503
+ fullscreen_default = FullscreenView;
504
+ }
505
+ });
506
+
507
+ // build/output.autoCmaf/form-views.js
508
+ var form_views_exports = {};
509
+ __export(form_views_exports, {
510
+ S3Destination: () => S3Destination,
511
+ SegmentConfiguration: () => SegmentConfiguration
512
+ });
513
+ function S3Destination(destination) {
514
+ 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" })] });
515
+ }
516
+ function SegmentConfiguration(cfg) {
517
+ 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"] })] });
518
+ }
519
+ var import_jsx_runtime7;
520
+ var init_form_views = __esm({
521
+ "build/output.autoCmaf/form-views.js"() {
522
+ "use strict";
523
+ import_jsx_runtime7 = __toESM(require_jsx_runtime());
524
+ }
525
+ });
526
+
427
527
  // external-global-plugin:@norskvideo/webrtc-client
428
528
  var require_webrtc_client = __commonJS({
429
529
  "external-global-plugin:@norskvideo/webrtc-client"(exports, module) {
@@ -436,17 +536,21 @@ var inline_view_exports3 = {};
436
536
  __export(inline_view_exports3, {
437
537
  default: () => inline_view_default3
438
538
  });
439
- function InlineView6({ state, config }) {
539
+ function InlineView5({ state, config, raise }) {
440
540
  const url = state.url;
441
541
  const id = config.id;
442
- (0, import_react7.useEffect)(() => {
542
+ (0, import_react6.useEffect)(() => {
443
543
  if (!url)
444
544
  return;
445
- const client = new import_webrtc_client.WhepClient({ url, container: document.getElementById(`preview-${id}`) ?? void 0 });
545
+ const client = new import_webrtc_client.WhepClient({
546
+ url,
547
+ container: document.getElementById(`preview-${id}`) ?? void 0
548
+ });
446
549
  void client.start();
447
550
  }, [state.url]);
551
+ raise && (0, import_react6.useEffect)(raise, []);
448
552
  if (!url)
449
- return (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: "..." });
553
+ return (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: "..." });
450
554
  function percentage(levels) {
451
555
  if (!levels) {
452
556
  return 0;
@@ -456,16 +560,16 @@ function InlineView6({ state, config }) {
456
560
  const snapped = Math.floor(capped * 10) * 10;
457
561
  return Math.max(0, 100 - snapped);
458
562
  }
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` }) })] });
563
+ return (0, import_jsx_runtime8.jsxs)("div", { className: "preview-outer-container", children: [(0, import_jsx_runtime8.jsx)("div", { className: "preview-video", id: `preview-${id}` }), (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
564
  }
461
- var import_jsx_runtime9, import_react7, import_webrtc_client, inline_view_default3;
565
+ var import_jsx_runtime8, import_react6, import_webrtc_client, inline_view_default3;
462
566
  var init_inline_view3 = __esm({
463
567
  "build/output.preview/inline-view.js"() {
464
568
  "use strict";
465
- import_jsx_runtime9 = __toESM(require_jsx_runtime());
466
- import_react7 = __toESM(require_react());
569
+ import_jsx_runtime8 = __toESM(require_jsx_runtime());
570
+ import_react6 = __toESM(require_react());
467
571
  import_webrtc_client = __toESM(require_webrtc_client());
468
- inline_view_default3 = InlineView6;
572
+ inline_view_default3 = InlineView5;
469
573
  }
470
574
  });
471
575
 
@@ -474,17 +578,92 @@ var inline_view_exports4 = {};
474
578
  __export(inline_view_exports4, {
475
579
  default: () => inline_view_default4
476
580
  });
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 });
581
+ function InlineView6({ state, config }) {
582
+ const connected = (0, import_jsx_runtime9.jsx)("div", { className: "active text-green-500 dark:text-green-300", children: "Connected and publishing" });
583
+ 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})` : ""] });
584
+ return (0, import_jsx_runtime9.jsx)("div", { className: "rtmp-output", id: `rtmp-output-${config.id}`, children: state.connected ? connected : disconnected });
481
585
  }
482
- var import_jsx_runtime10, inline_view_default4;
586
+ var import_jsx_runtime9, inline_view_default4;
483
587
  var init_inline_view4 = __esm({
484
588
  "build/output.rtmp/inline-view.js"() {
485
589
  "use strict";
486
- import_jsx_runtime10 = __toESM(require_jsx_runtime());
487
- inline_view_default4 = InlineView7;
590
+ import_jsx_runtime9 = __toESM(require_jsx_runtime());
591
+ inline_view_default4 = InlineView6;
592
+ }
593
+ });
594
+
595
+ // ../../node_modules/@norskvideo/norsk-studio/lib/shared/util.js
596
+ var require_util = __commonJS({
597
+ "../../node_modules/@norskvideo/norsk-studio/lib/shared/util.js"(exports) {
598
+ "use strict";
599
+ Object.defineProperty(exports, "__esModule", { value: true });
600
+ exports.nodeApiUrl = nodeApiUrl;
601
+ exports.componentApiUrl = componentApiUrl;
602
+ exports.findObjectByType = findObjectByType;
603
+ exports.getObjectByType = getObjectByType;
604
+ exports.getObjectByPath = getObjectByPath;
605
+ exports.displayNodeId = displayNodeId;
606
+ exports.assertUnreachable = assertUnreachable15;
607
+ exports.waitForCondition = waitForCondition;
608
+ function nodeApiUrl(nodeId) {
609
+ return new URL(`${document.location.protocol}//${document.location.host}/live/api/${encodeURIComponent(nodeId)}`);
610
+ }
611
+ function componentApiUrl(indentifier) {
612
+ return new URL(`${document.location.protocol}//${document.location.host}/components/${encodeURIComponent(indentifier)}`);
613
+ }
614
+ function findObjectByType(potentials, t) {
615
+ for (const v of potentials) {
616
+ const potential = getObjectByType(v, t);
617
+ if (potential) {
618
+ return potential;
619
+ }
620
+ }
621
+ return null;
622
+ }
623
+ function getObjectByType(acc, t) {
624
+ const paths = t.split(".");
625
+ return getObjectByPath(acc, paths);
626
+ }
627
+ function getObjectByPath(acc, paths) {
628
+ if (paths.length == 0) {
629
+ return acc;
630
+ }
631
+ if (!acc) {
632
+ return null;
633
+ }
634
+ const head = paths[0];
635
+ const tail = paths.slice(1);
636
+ const result2 = Object.entries(acc).find(([k, _]) => k == head);
637
+ if (!result2) {
638
+ return null;
639
+ }
640
+ return getObjectByPath(result2[1], tail);
641
+ }
642
+ function displayNodeId(id, document2) {
643
+ if (!id) {
644
+ return "";
645
+ }
646
+ return document2.components[id]?.config?.displayName ?? id;
647
+ }
648
+ function assertUnreachable15(_) {
649
+ throw new Error("Didn't expect to get here");
650
+ }
651
+ async function waitForCondition(condition, timeout, interval) {
652
+ return new Promise((r, f) => {
653
+ const i = setInterval(async () => {
654
+ const success = await condition();
655
+ if (success) {
656
+ clearInterval(i);
657
+ clearTimeout(t);
658
+ r();
659
+ }
660
+ }, interval ?? 10);
661
+ const t = setTimeout(() => {
662
+ clearInterval(i);
663
+ f(new Error("Timeout on condition wait"));
664
+ }, timeout ?? 2e3);
665
+ });
666
+ }
488
667
  }
489
668
  });
490
669
 
@@ -493,49 +672,51 @@ var inline_view_exports5 = {};
493
672
  __export(inline_view_exports5, {
494
673
  default: () => inline_view_default5
495
674
  });
496
- function InlineView8({ state }) {
675
+ function InlineView7({ state }) {
497
676
  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) => {
677
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
678
+ const format = (stat) => Math.floor(stat).toLocaleString("en-US", { maximumFractionDigits: 0 });
679
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: state.previous.allStreams.map((s, i) => {
500
680
  const metaCase = s.metadata.case;
501
681
  switch (metaCase) {
502
682
  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);
683
+ 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
684
  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);
685
+ 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
686
  case "ancillary":
507
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
687
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
508
688
  case "subtitle":
509
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
689
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
510
690
  case "playlist":
511
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
691
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
512
692
  case void 0:
513
- return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
693
+ return (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
514
694
  default:
515
- assertUnreachable6(metaCase);
695
+ assertUnreachable7(metaCase);
516
696
  }
517
697
  }) });
518
698
  }
519
699
  function streamKey(streamKey2) {
520
700
  return streamKey2.streamId.toString();
521
701
  }
522
- var import_jsx_runtime11, inline_view_default5;
702
+ var import_jsx_runtime10, inline_view_default5;
523
703
  var init_inline_view5 = __esm({
524
704
  "build/output.statistics/inline-view.js"() {
525
705
  "use strict";
526
- import_jsx_runtime11 = __toESM(require_jsx_runtime());
706
+ import_jsx_runtime10 = __toESM(require_jsx_runtime());
527
707
  init_info();
528
- inline_view_default5 = InlineView8;
708
+ inline_view_default5 = InlineView7;
529
709
  }
530
710
  });
531
711
 
532
712
  // build/output.statistics/info.js
533
713
  function info_default11({ defineComponent, All }) {
534
- const InlineView13 = import_react11.default.lazy(async () => Promise.resolve().then(() => (init_inline_view5(), inline_view_exports5)));
714
+ const InlineView13 = import_react10.default.lazy(async () => Promise.resolve().then(() => (init_inline_view5(), inline_view_exports5)));
535
715
  return defineComponent({
536
716
  identifier: "output.statistics",
537
717
  category: "output",
538
718
  name: "Statistics",
719
+ description: "This component accepts multiple media streams, captures and reports metrics or statistical data related to the media streams.",
539
720
  subscription: {
540
721
  // No validation required
541
722
  accepts: {
@@ -555,7 +736,7 @@ function info_default11({ defineComponent, All }) {
555
736
  state.previous = ev.summary;
556
737
  break;
557
738
  default:
558
- assertUnreachable6(evType);
739
+ assertUnreachable7(evType);
559
740
  }
560
741
  return { ...state };
561
742
  },
@@ -566,14 +747,99 @@ function info_default11({ defineComponent, All }) {
566
747
  }
567
748
  });
568
749
  }
569
- function assertUnreachable6(_) {
750
+ function assertUnreachable7(_) {
570
751
  throw new Error("Didn't expect to get here");
571
752
  }
572
- var import_react11;
753
+ var import_react10;
573
754
  var init_info = __esm({
574
755
  "build/output.statistics/info.js"() {
575
756
  "use strict";
757
+ import_react10 = __toESM(require_react());
758
+ }
759
+ });
760
+
761
+ // build/output.whep/inline-view.js
762
+ var inline_view_exports6 = {};
763
+ __export(inline_view_exports6, {
764
+ default: () => inline_view_default6
765
+ });
766
+ function InlineView8({ state, config, raise }) {
767
+ const url = state.url;
768
+ const id = config.id;
769
+ (0, import_react11.useEffect)(() => {
770
+ if (!url)
771
+ return;
772
+ const client = new import_webrtc_client2.WhepClient({
773
+ url,
774
+ container: document.getElementById(`whep-${id}`) ?? void 0
775
+ });
776
+ void client.start();
777
+ }, [state.url]);
778
+ raise && (0, import_react11.useEffect)(raise, []);
779
+ if (!url)
780
+ return (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: "..." });
781
+ return (0, import_jsx_runtime11.jsx)("div", { className: "whep-container", children: (0, import_jsx_runtime11.jsx)("div", { className: "whep-video", id: `whep-${id}` }) });
782
+ }
783
+ var import_jsx_runtime11, import_react11, import_webrtc_client2, inline_view_default6;
784
+ var init_inline_view6 = __esm({
785
+ "build/output.whep/inline-view.js"() {
786
+ "use strict";
787
+ import_jsx_runtime11 = __toESM(require_jsx_runtime());
576
788
  import_react11 = __toESM(require_react());
789
+ import_webrtc_client2 = __toESM(require_webrtc_client());
790
+ inline_view_default6 = InlineView8;
791
+ }
792
+ });
793
+
794
+ // build/processor.browserOverlay/summary-view.js
795
+ var summary_view_exports3 = {};
796
+ __export(summary_view_exports3, {
797
+ default: () => summary_view_default3
798
+ });
799
+ function SummaryView5({ state, sendCommand }) {
800
+ const [url, setUrl] = (0, import_react13.useState)(state.currentUrl);
801
+ const [enabled, setEnabled] = (0, import_react13.useState)(state.enabled);
802
+ const stateChanged = (0, import_react13.useMemo)(() => {
803
+ return url !== state.currentUrl || enabled !== state.enabled;
804
+ }, [url, enabled]);
805
+ 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";
806
+ 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: () => {
807
+ if (url !== state.currentUrl) {
808
+ sendCommand({ type: "change-url", url });
809
+ }
810
+ if (enabled !== state.enabled) {
811
+ if (enabled) {
812
+ sendCommand({ type: "enable" });
813
+ } else {
814
+ sendCommand({ type: "disable" });
815
+ }
816
+ }
817
+ }, children: "Commit" })] });
818
+ }
819
+ var import_jsx_runtime12, import_react13, summary_view_default3;
820
+ var init_summary_view3 = __esm({
821
+ "build/processor.browserOverlay/summary-view.js"() {
822
+ "use strict";
823
+ import_jsx_runtime12 = __toESM(require_jsx_runtime());
824
+ import_react13 = __toESM(require_react());
825
+ summary_view_default3 = SummaryView5;
826
+ }
827
+ });
828
+
829
+ // build/processor.browserOverlay/inline-view.js
830
+ var inline_view_exports7 = {};
831
+ __export(inline_view_exports7, {
832
+ default: () => inline_view_default7
833
+ });
834
+ function InlineView9({ state, config }) {
835
+ 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" })] }) })] }) });
836
+ }
837
+ var import_jsx_runtime13, inline_view_default7;
838
+ var init_inline_view7 = __esm({
839
+ "build/processor.browserOverlay/inline-view.js"() {
840
+ "use strict";
841
+ import_jsx_runtime13 = __toESM(require_jsx_runtime());
842
+ inline_view_default7 = InlineView9;
577
843
  }
578
844
  });
579
845
 
@@ -583,15 +849,15 @@ __export(source_selection_exports, {
583
849
  default: () => source_selection_default
584
850
  });
585
851
  function OrderInput(props) {
586
- (0, import_react12.useEffect)(() => {
852
+ (0, import_react15.useEffect)(() => {
587
853
  props.onChanged(props.defaultValue ?? []);
588
854
  }, [props.defaultValue]);
589
- const [value, setValue] = (0, import_react12.useState)(props.defaultValue ?? []);
855
+ const [value, setValue] = (0, import_react15.useState)(props.defaultValue ?? []);
590
856
  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" });
857
+ 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
858
  } 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);
859
+ return (0, import_jsx_runtime14.jsx)("div", { id: props.id, children: (0, import_jsx_runtime14.jsx)("ul", { children: value.map((v, ix) => {
860
+ 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
861
  }) }) });
596
862
  }
597
863
  function moveUp(ix) {
@@ -613,146 +879,33 @@ function OrderInput(props) {
613
879
  };
614
880
  }
615
881
  }
616
- var import_jsx_runtime12, import_react12, source_selection_default;
882
+ var import_jsx_runtime14, import_react15, source_selection_default;
617
883
  var init_source_selection = __esm({
618
884
  "build/processor.cascadingSwitch/source-selection.js"() {
619
885
  "use strict";
620
- import_jsx_runtime12 = __toESM(require_jsx_runtime());
621
- import_react12 = __toESM(require_react());
886
+ import_jsx_runtime14 = __toESM(require_jsx_runtime());
887
+ import_react15 = __toESM(require_react());
622
888
  source_selection_default = OrderInput;
623
889
  }
624
890
  });
625
891
 
626
892
  // build/processor.cascadingSwitch/inline-view.js
627
- var inline_view_exports6 = {};
628
- __export(inline_view_exports6, {
629
- default: () => inline_view_default6
893
+ var inline_view_exports8 = {};
894
+ __export(inline_view_exports8, {
895
+ default: () => inline_view_default8
630
896
  });
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")] })] });
897
+ function InlineView11({ state, config }) {
898
+ 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
899
  }
634
- var import_jsx_runtime13, activeClasses, availableClasses, inactiveClasses, inline_view_default6;
635
- var init_inline_view6 = __esm({
900
+ var import_jsx_runtime15, activeClasses, availableClasses, inactiveClasses, inline_view_default8;
901
+ var init_inline_view8 = __esm({
636
902
  "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
903
  "use strict";
753
904
  import_jsx_runtime15 = __toESM(require_jsx_runtime());
754
- import_react14 = __toESM(require_react());
755
- summary_view_default3 = SummaryView5;
905
+ activeClasses = "active text-green-500 dark:text-green-300";
906
+ availableClasses = "available text-green-500 dark:text-green-300";
907
+ inactiveClasses = "inactive text-orange-500 dark:text-orange-300";
908
+ inline_view_default8 = InlineView11;
756
909
  }
757
910
  });
758
911
 
@@ -762,7 +915,7 @@ __export(rung_view_exports, {
762
915
  default: () => rung_view_default
763
916
  });
764
917
  function rung_view_default(rung) {
765
- return (0, import_jsx_runtime16.jsx)("div", { className: "", children: rung.name });
918
+ return (0, import_jsx_runtime16.jsx)("div", { className: "text-gray-900 dark:text-white", children: rung.name });
766
919
  }
767
920
  var import_jsx_runtime16;
768
921
  var init_rung_view = __esm({
@@ -791,7 +944,7 @@ function CodecEditor(props) {
791
944
  target.style.height = target.scrollHeight + "px";
792
945
  }
793
946
  }, []);
794
- return (0, import_jsx_runtime17.jsx)("textarea", { ref: textAreaRef, className: "w-full min-h-fit dark:text-white dark:bg-black", onChange: (e) => {
947
+ 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
948
  const target = e.currentTarget;
796
949
  try {
797
950
  const codec = JSON.parse(target.value);
@@ -816,7 +969,7 @@ __export(codec_view_exports, {
816
969
  default: () => CodecEditor2
817
970
  });
818
971
  function CodecEditor2(props) {
819
- return (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [props.width, "x", props.height] });
972
+ return (0, import_jsx_runtime18.jsxs)("div", { className: "text-gray-900 dark:text-white", children: [props.width, "x", props.height] });
820
973
  }
821
974
  var import_jsx_runtime18;
822
975
  var init_codec_view = __esm({
@@ -826,6 +979,384 @@ var init_codec_view = __esm({
826
979
  }
827
980
  });
828
981
 
982
+ // build/processor.onscreenGraphic/image-selection.js
983
+ var image_selection_exports = {};
984
+ __export(image_selection_exports, {
985
+ default: () => image_selection_default
986
+ });
987
+ function GraphicSelection(props) {
988
+ const [loading, setLoading] = (0, import_react18.useState)(true);
989
+ (0, import_react18.useEffect)(() => {
990
+ const fn = async () => {
991
+ const result2 = await fetch("components/processor.onscreenGraphic/graphics");
992
+ if (result2.ok && result2.body) {
993
+ const graphics = await result2.json();
994
+ setGraphics(graphics);
995
+ setLoading(false);
996
+ if (props.defaultValue)
997
+ props.onChanged(props.defaultValue);
998
+ } else {
999
+ const text = await result2.text();
1000
+ throw new Error(text);
1001
+ }
1002
+ };
1003
+ fn().catch(console.error);
1004
+ }, []);
1005
+ const [graphcs, setGraphics] = (0, import_react18.useState)([]);
1006
+ if (loading) {
1007
+ return (0, import_jsx_runtime19.jsx)("div", { children: "Loading.." });
1008
+ }
1009
+ if (graphcs.length == 0) {
1010
+ return (0, import_jsx_runtime19.jsx)("div", { children: "No graphics loaded" });
1011
+ }
1012
+ 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) => {
1013
+ return (0, import_jsx_runtime19.jsx)("option", { value: o, children: o }, i);
1014
+ })] }) });
1015
+ function myOnChange(e) {
1016
+ props.onChanged(e.target.value);
1017
+ }
1018
+ }
1019
+ var import_jsx_runtime19, import_react18, image_selection_default;
1020
+ var init_image_selection = __esm({
1021
+ "build/processor.onscreenGraphic/image-selection.js"() {
1022
+ "use strict";
1023
+ import_jsx_runtime19 = __toESM(require_jsx_runtime());
1024
+ import_react18 = __toESM(require_react());
1025
+ image_selection_default = GraphicSelection;
1026
+ }
1027
+ });
1028
+
1029
+ // build/processor.onscreenGraphic/summary-view.js
1030
+ var summary_view_exports4 = {};
1031
+ __export(summary_view_exports4, {
1032
+ default: () => summary_view_default4
1033
+ });
1034
+ function SummaryView7({ state, sendCommand, urls }) {
1035
+ const [graphic, setGraphic] = (0, import_react19.useState)(state.activeGraphic?.file);
1036
+ const [position, setPosition] = (0, import_react19.useState)(state.activeGraphic?.position ?? { type: "named", position: "topleft" });
1037
+ const [graphics, setGraphics] = (0, import_react19.useState)([]);
1038
+ const [fileToUpload, setFileToUpload] = (0, import_react19.useState)(void 0);
1039
+ const [showFileInput, setShowFileInput] = (0, import_react19.useState)(false);
1040
+ const [showUploadButton, setShowUploadButton] = (0, import_react19.useState)(false);
1041
+ const [uploadStatus, setUploadStatus] = (0, import_react19.useState)({ success: false, message: null });
1042
+ const [showDeleteDropdown, setShowDeleteDropdown] = (0, import_react19.useState)(false);
1043
+ const [graphicToDelete, setGraphicToDelete] = (0, import_react19.useState)("");
1044
+ const updateGraphics = (0, import_react19.useCallback)(async () => {
1045
+ try {
1046
+ const result2 = await fetch(`${urls.componentUrl}/graphics`);
1047
+ if (result2.ok) {
1048
+ const newGraphics = await result2.json();
1049
+ setGraphics(newGraphics);
1050
+ } else {
1051
+ throw new Error(await result2.text());
1052
+ }
1053
+ } catch (error) {
1054
+ console.error("Failed to update graphics:", error);
1055
+ setUploadStatus({
1056
+ success: false,
1057
+ message: "Failed to update graphic list."
1058
+ });
1059
+ }
1060
+ }, [urls.componentUrl]);
1061
+ (0, import_react19.useEffect)(() => {
1062
+ updateGraphics().catch(console.error);
1063
+ }, [updateGraphics]);
1064
+ const onFileChange = (e) => {
1065
+ const file = e.target.files?.[0];
1066
+ setFileToUpload(file);
1067
+ setShowUploadButton(!!file);
1068
+ setUploadStatus({ success: false, message: null });
1069
+ };
1070
+ const uploadFileHandle = async () => {
1071
+ if (!fileToUpload)
1072
+ return;
1073
+ try {
1074
+ const form = new FormData();
1075
+ form.append("file", fileToUpload);
1076
+ const response = await fetch(`${urls.componentUrl}/graphics`, {
1077
+ method: "POST",
1078
+ body: form
1079
+ });
1080
+ if (response.status === 409) {
1081
+ const errorData = await response.json();
1082
+ setUploadStatus({
1083
+ success: false,
1084
+ message: `${errorData.error}. Delete the existing graphic first if you want to replace it.`
1085
+ });
1086
+ } else if (!response.ok) {
1087
+ throw new Error("Upload failed");
1088
+ } else {
1089
+ setFileToUpload(void 0);
1090
+ setShowFileInput(false);
1091
+ setUploadStatus({
1092
+ success: true,
1093
+ message: "Graphic uploaded successfully!"
1094
+ });
1095
+ await updateGraphics();
1096
+ }
1097
+ } catch (error) {
1098
+ console.error("Failed to upload file:", error);
1099
+ setUploadStatus({ success: false, message: "Failed to upload graphic." });
1100
+ }
1101
+ setTimeout(() => setUploadStatus({ success: false, message: null }), 5e3);
1102
+ };
1103
+ const uploadFile = () => {
1104
+ void uploadFileHandle();
1105
+ };
1106
+ const deleteBugHandle = async () => {
1107
+ if (!graphicToDelete)
1108
+ return;
1109
+ try {
1110
+ console.log(`${urls.componentUrl}`);
1111
+ const response = await fetch(`${urls.componentUrl}/graphic`, {
1112
+ method: "DELETE",
1113
+ headers: {
1114
+ "Content-Type": "application/json"
1115
+ },
1116
+ body: JSON.stringify({ filename: graphicToDelete })
1117
+ });
1118
+ if (response.ok) {
1119
+ setUploadStatus({
1120
+ success: true,
1121
+ message: "Graphic deleted successfully!"
1122
+ });
1123
+ await updateGraphics();
1124
+ if (graphic === graphicToDelete) {
1125
+ setGraphic(void 0);
1126
+ sendCommand({
1127
+ type: "change-graphic",
1128
+ file: void 0,
1129
+ position: void 0
1130
+ });
1131
+ }
1132
+ setGraphicToDelete("");
1133
+ setShowDeleteDropdown(false);
1134
+ } else {
1135
+ const errorData = await response.json();
1136
+ setUploadStatus({
1137
+ success: false,
1138
+ message: errorData.error || "Failed to delete graphic"
1139
+ });
1140
+ }
1141
+ } catch (error) {
1142
+ console.error("Failed to delete graphic:", error);
1143
+ setUploadStatus({ success: false, message: "Failed to delete graphic" });
1144
+ }
1145
+ setTimeout(() => setUploadStatus({ success: false, message: null }), 3e3);
1146
+ };
1147
+ const deleteBug = () => {
1148
+ void deleteBugHandle();
1149
+ };
1150
+ const eqPosition = (l, r) => {
1151
+ if (!r)
1152
+ return false;
1153
+ if (l.type === "named") {
1154
+ if (r.type !== "named")
1155
+ return false;
1156
+ return l.position === r.position;
1157
+ }
1158
+ if (r.type === "named")
1159
+ return false;
1160
+ if (l.type !== r.type)
1161
+ return false;
1162
+ return l.x === r.x && l.y === r.y;
1163
+ };
1164
+ const graphicChanged = graphic !== state.activeGraphic?.file;
1165
+ const stateChanged = graphicChanged || !eqPosition(position, state.activeGraphic?.position);
1166
+ 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";
1167
+ 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";
1168
+ 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";
1169
+ 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 })] });
1170
+ }
1171
+ function convertPosition(givenPosition, currentVideo, currentGraphic) {
1172
+ if (!givenPosition)
1173
+ givenPosition = { type: "named", position: "topleft" };
1174
+ if (givenPosition.type === "named") {
1175
+ let xy;
1176
+ if (givenPosition.position === "topleft") {
1177
+ xy = { x: 0, y: 0 };
1178
+ } else if (givenPosition.position === "topright") {
1179
+ xy = { x: 100, y: 0 };
1180
+ } else if (givenPosition.position === "bottomleft") {
1181
+ xy = { x: 0, y: 100 };
1182
+ } else if (givenPosition.position === "bottomright") {
1183
+ xy = { x: 100, y: 100 };
1184
+ } else if (givenPosition.position === "center") {
1185
+ xy = { x: 50, y: 50 };
1186
+ } else {
1187
+ assertUnreachable12(givenPosition.position);
1188
+ }
1189
+ return { ...givenPosition, ...xy, xPct: xy.x, yPct: xy.y };
1190
+ }
1191
+ if (givenPosition.type === "coordinate") {
1192
+ if (!currentVideo || !currentGraphic) {
1193
+ return { ...givenPosition, xPct: 0, yPct: 0 };
1194
+ }
1195
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1196
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1197
+ const maxX = videoWidth - graphicWidth;
1198
+ const maxY = videoHeight - graphicHeight;
1199
+ return {
1200
+ ...givenPosition,
1201
+ x: clamp(0, givenPosition.x, maxX),
1202
+ xPct: clamp(0, givenPosition.x * 100 / maxX, 100),
1203
+ y: clamp(0, givenPosition.y, maxY),
1204
+ yPct: clamp(0, givenPosition.y * 100 / maxY, 100)
1205
+ };
1206
+ }
1207
+ return { ...givenPosition, xPct: givenPosition.x, yPct: givenPosition.y };
1208
+ }
1209
+ function clamp(min, num, max) {
1210
+ return num < min ? min : num > max ? max : num;
1211
+ }
1212
+ function assertUnreachable12(_) {
1213
+ throw new Error("Didn't expect to get here");
1214
+ }
1215
+ var import_jsx_runtime20, import_react19, PositionSelector, summary_view_default4;
1216
+ var init_summary_view4 = __esm({
1217
+ "build/processor.onscreenGraphic/summary-view.js"() {
1218
+ "use strict";
1219
+ import_jsx_runtime20 = __toESM(require_jsx_runtime());
1220
+ import_react19 = __toESM(require_react());
1221
+ PositionSelector = ({ initialPosition: givenPosition = { type: "named", position: "topleft" }, onChange, currentVideo, currentGraphic, graphicChanged }) => {
1222
+ const convertPos = (pos) => convertPosition(pos, currentVideo, currentGraphic);
1223
+ const initialPosition = convertPos(givenPosition);
1224
+ const [position, setLocalPosition] = (0, import_react19.useState)(initialPosition);
1225
+ const setPosition = (v) => {
1226
+ setLocalPosition(v);
1227
+ onChange(v);
1228
+ };
1229
+ const [positionUnit, setPositionUnit] = (0, import_react19.useState)(position.type === "coordinate" ? "px" : "%");
1230
+ const [isDragging, setIsDragging] = (0, import_react19.useState)(false);
1231
+ const [dragStart, setDragStart] = (0, import_react19.useState)({ xPct: 0, yPct: 0, cx: 0, cy: 0 });
1232
+ const previewAreaRef = (0, import_react19.useRef)(null);
1233
+ const previewTargetRef = (0, import_react19.useRef)(null);
1234
+ const handleMouseDown = (e) => {
1235
+ setIsDragging(true);
1236
+ setDragStart({
1237
+ ...position,
1238
+ cx: e.clientX,
1239
+ cy: e.clientY
1240
+ });
1241
+ handleMouseMove(e);
1242
+ };
1243
+ const handleMouseMove = (e) => {
1244
+ if (!isDragging)
1245
+ return;
1246
+ const boundingBox = previewAreaRef.current?.getBoundingClientRect() ?? { width: 0, height: 0 };
1247
+ const bbTarget = previewTargetRef.current?.getBoundingClientRect() ?? { width: 0, height: 0 };
1248
+ const clientWidth = boundingBox.width - bbTarget.width;
1249
+ const clientHeight = boundingBox.height - bbTarget.height;
1250
+ const newX = clamp(0, dragStart.xPct + (e.clientX - dragStart.cx) * (100 / clientWidth), 100);
1251
+ const newY = clamp(0, dragStart.yPct + (e.clientY - dragStart.cy) * (100 / clientHeight), 100);
1252
+ if (positionUnit === "px" && currentVideo && currentGraphic) {
1253
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1254
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1255
+ const maxX = videoWidth - graphicWidth;
1256
+ const maxY = videoHeight - graphicHeight;
1257
+ setPosition({
1258
+ type: "coordinate",
1259
+ x: newX * maxX / 100,
1260
+ y: newY * maxY / 100,
1261
+ xPct: newX,
1262
+ yPct: newY
1263
+ });
1264
+ } else {
1265
+ setPosition({
1266
+ type: "percentage",
1267
+ x: newX,
1268
+ y: newY,
1269
+ xPct: newX,
1270
+ yPct: newY
1271
+ });
1272
+ }
1273
+ };
1274
+ const handleMouseUp = () => {
1275
+ setIsDragging(false);
1276
+ };
1277
+ (0, import_react19.useEffect)(() => {
1278
+ if (isDragging) {
1279
+ window.addEventListener("mousemove", handleMouseMove);
1280
+ window.addEventListener("mouseup", handleMouseUp);
1281
+ }
1282
+ return () => {
1283
+ window.removeEventListener("mousemove", handleMouseMove);
1284
+ window.removeEventListener("mouseup", handleMouseUp);
1285
+ };
1286
+ }, [isDragging]);
1287
+ 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) => {
1288
+ const newType = e.target.value;
1289
+ if (newType === "named") {
1290
+ setPosition(convertPos({ type: "named", position: "topleft" }));
1291
+ } else {
1292
+ setPositionUnit("%");
1293
+ setPosition({ ...convertPos(position), type: "percentage" });
1294
+ }
1295
+ }, 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) => {
1296
+ setPosition(convertPos({
1297
+ type: "named",
1298
+ position: e.target.value
1299
+ }));
1300
+ }, 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) => {
1301
+ setPositionUnit(e.target.value);
1302
+ if (e.target.value === "px" && position.type !== "coordinate" && currentVideo && currentGraphic) {
1303
+ const { width: videoWidth, height: videoHeight } = currentVideo;
1304
+ const { width: graphicWidth, height: graphicHeight } = currentGraphic;
1305
+ const maxX = videoWidth - graphicWidth;
1306
+ const maxY = videoHeight - graphicHeight;
1307
+ setPosition({
1308
+ ...position,
1309
+ type: "coordinate",
1310
+ x: position.xPct * maxX / 100,
1311
+ y: position.yPct * maxY / 100,
1312
+ xStr: void 0,
1313
+ yStr: void 0
1314
+ });
1315
+ } else if (e.target.value === "%") {
1316
+ setPosition({
1317
+ ...position,
1318
+ type: "percentage",
1319
+ x: position.xPct,
1320
+ y: position.yPct,
1321
+ xStr: void 0,
1322
+ yStr: void 0
1323
+ });
1324
+ }
1325
+ }, 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: {
1326
+ width: "100%",
1327
+ userSelect: "none",
1328
+ aspectRatio: currentVideo ? `${currentVideo.width} / ${currentVideo.height}` : `3 / 2`
1329
+ }, 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
1330
+ ${isDragging ? "bg-opacity-75" : ""}`, style: {
1331
+ left: `${position.xPct}%`,
1332
+ top: `${position.yPct}%`,
1333
+ transform: `translate(-${position.xPct}%, -${position.yPct}%)`,
1334
+ aspectRatio: currentGraphic && !graphicChanged ? `${currentGraphic.width} / ${currentGraphic.height}` : `1`,
1335
+ width: currentGraphic && currentVideo && !graphicChanged ? currentGraphic.width / currentVideo.width * 100 + "%" : void 0
1336
+ }, 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) => {
1337
+ const newX = Number(e.target.value);
1338
+ setPosition(convertPos({
1339
+ type: positionUnit === "%" ? "percentage" : "coordinate",
1340
+ x: newX,
1341
+ xStr: e.target.value,
1342
+ y: position.y,
1343
+ yStr: position.yStr
1344
+ }));
1345
+ }, 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) => {
1346
+ const newY = Number(e.target.value);
1347
+ setPosition(convertPos({
1348
+ type: positionUnit === "%" ? "percentage" : "coordinate",
1349
+ x: position.x,
1350
+ xStr: position.xStr,
1351
+ y: newY,
1352
+ yStr: e.target.value
1353
+ }));
1354
+ }, 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" })] })] })] })] });
1355
+ };
1356
+ summary_view_default4 = SummaryView7;
1357
+ }
1358
+ });
1359
+
829
1360
  // ../../node_modules/@kurkle/color/dist/color.esm.js
830
1361
  function round(v) {
831
1362
  return v + 0.5 | 0;
@@ -15144,14 +15675,14 @@ var init_auto = __esm({
15144
15675
  }
15145
15676
  });
15146
15677
 
15147
- // build/util.latency/inline-view.js
15148
- var inline_view_exports7 = {};
15149
- __export(inline_view_exports7, {
15150
- default: () => inline_view_default7
15678
+ // build/util.stats.latency/inline-view.js
15679
+ var inline_view_exports9 = {};
15680
+ __export(inline_view_exports9, {
15681
+ default: () => inline_view_default9
15151
15682
  });
15152
- function InlineView10({ state, config: _2 }) {
15153
- const chartContainer = (0, import_react18.useRef)(null);
15154
- const [chartControl, setChartControl] = (0, import_react18.useState)(void 0);
15683
+ function InlineView12({ state, config: _2 }) {
15684
+ const chartContainer = (0, import_react21.useRef)(null);
15685
+ const [chartControl, setChartControl] = (0, import_react21.useState)(void 0);
15155
15686
  function makeDataSet(key, color2, values) {
15156
15687
  return {
15157
15688
  label: key,
@@ -15168,7 +15699,7 @@ function InlineView10({ state, config: _2 }) {
15168
15699
  datasets: [makeDataSet("latency", "rgba(255, 0, 0, 255)", state2.values)]
15169
15700
  };
15170
15701
  }
15171
- (0, import_react18.useEffect)(() => {
15702
+ (0, import_react21.useEffect)(() => {
15172
15703
  if (!chartContainer.current)
15173
15704
  return;
15174
15705
  auto_default.defaults.color = "#FFF";
@@ -15206,237 +15737,47 @@ function InlineView10({ state, config: _2 }) {
15206
15737
  chart.update();
15207
15738
  }, 100);
15208
15739
  }, [chartContainer]);
15209
- (0, import_react18.useEffect)(() => {
15740
+ (0, import_react21.useEffect)(() => {
15210
15741
  if (!chartControl)
15211
15742
  return;
15212
15743
  chartControl.data = makeData(state);
15213
15744
  }, [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 }) });
15745
+ 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
15746
  }
15216
- var import_jsx_runtime19, import_react18, inline_view_default7;
15217
- var init_inline_view7 = __esm({
15218
- "build/util.latency/inline-view.js"() {
15747
+ var import_jsx_runtime21, import_react21, inline_view_default9;
15748
+ var init_inline_view9 = __esm({
15749
+ "build/util.stats.latency/inline-view.js"() {
15219
15750
  "use strict";
15220
- import_jsx_runtime19 = __toESM(require_jsx_runtime());
15221
- import_react18 = __toESM(require_react());
15751
+ import_jsx_runtime21 = __toESM(require_jsx_runtime());
15752
+ import_react21 = __toESM(require_react());
15222
15753
  init_auto();
15223
- inline_view_default7 = InlineView10;
15754
+ inline_view_default9 = InlineView12;
15224
15755
  }
15225
15756
  });
15226
15757
 
15227
- // build/util.latency/source-node-selection.js
15758
+ // build/util.stats.latency/source-node-selection.js
15228
15759
  var source_node_selection_exports = {};
15229
15760
  __export(source_node_selection_exports, {
15230
15761
  default: () => source_node_selection_default
15231
15762
  });
15232
15763
  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) => {
15764
+ 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
15765
  if (o.id == props.id)
15235
- return (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, {});
15766
+ return (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, {});
15236
15767
  if (o.info.category === "output")
15237
15768
  return;
15238
- return (0, import_jsx_runtime20.jsx)("option", { value: o.id, children: o.config.displayName }, i);
15769
+ return (0, import_jsx_runtime22.jsx)("option", { value: o.id, children: o.config.displayName }, i);
15239
15770
  })] }) });
15240
15771
  function myOnChange(e) {
15241
15772
  props.onChanged(e.target.value);
15242
15773
  }
15243
15774
  }
15244
- var import_jsx_runtime20, source_node_selection_default;
15775
+ var import_jsx_runtime22, source_node_selection_default;
15245
15776
  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"() {
15777
+ "build/util.stats.latency/source-node-selection.js"() {
15435
15778
  "use strict";
15436
15779
  import_jsx_runtime22 = __toESM(require_jsx_runtime());
15437
- import_react22 = __toESM(require_react());
15438
- init_auto();
15439
- inline_view_default9 = InlineView12;
15780
+ source_node_selection_default = SourceNodeSelection;
15440
15781
  }
15441
15782
  });
15442
15783
 
@@ -15450,6 +15791,7 @@ function info_default({ defineComponent, Av, validation: { Z, Port, SourceName,
15450
15791
  identifier: "input.rtmp",
15451
15792
  category: "input",
15452
15793
  name: "RTMP Ingest",
15794
+ description: "A component that listens for RTMP input on the address specified.",
15453
15795
  subscription: {
15454
15796
  accepts: void 0,
15455
15797
  produces: {
@@ -15494,7 +15836,7 @@ function info_default({ defineComponent, Av, validation: { Z, Port, SourceName,
15494
15836
  configForm: {
15495
15837
  form: {
15496
15838
  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" } },
15839
+ ssl: { help: "Optional: SSL", hint: { type: "boolean", optional: true } },
15498
15840
  appName: { help: "Name of the app", hint: { type: "text", validation: Z.string().min(1), defaultValue: "norsk" } },
15499
15841
  streamNames: {
15500
15842
  help: "List of stream names to assign to the accepted streams",
@@ -15519,6 +15861,7 @@ function info_default2({ defineComponent, Audio }) {
15519
15861
  identifier: "input.silence",
15520
15862
  category: "input",
15521
15863
  name: "Silence Generator",
15864
+ description: "A component that produces silent audio streams with configurable sample rate and channel layout.",
15522
15865
  subscription: {
15523
15866
  produces: {
15524
15867
  type: "single-stream",
@@ -15527,14 +15870,14 @@ function info_default2({ defineComponent, Audio }) {
15527
15870
  },
15528
15871
  display: (desc) => {
15529
15872
  return {
15530
- sampleRate: desc.config.sampleRate.toString() + "khz",
15873
+ sampleRate: desc.config.sampleRate.toString() + "Hz",
15531
15874
  channelLayout: desc.config.channelLayout.toString()
15532
15875
  };
15533
15876
  },
15534
15877
  configForm: {
15535
15878
  form: {
15536
15879
  sampleRate: {
15537
- help: "Samplerate in khz of the generated audio",
15880
+ help: "Samplerate in Hz of the generated audio",
15538
15881
  hint: {
15539
15882
  type: "select",
15540
15883
  options: [
@@ -15566,6 +15909,7 @@ var result = ({ Z }) => ({
15566
15909
  help: "The latency value in the receiving direction of the socket (SRTO_RCVLATENCY)",
15567
15910
  hint: {
15568
15911
  type: "numeric",
15912
+ optional: true,
15569
15913
  validation: Z.optional(Z.number())
15570
15914
  }
15571
15915
  },
@@ -15573,13 +15917,15 @@ var result = ({ Z }) => ({
15573
15917
  help: "The latency value provided by the sender side as a minimum value for the receiver (SRTO_PEERLATENCY)",
15574
15918
  hint: {
15575
15919
  type: "numeric",
15920
+ optional: true,
15576
15921
  validation: Z.optional(Z.number())
15577
15922
  }
15578
15923
  },
15579
15924
  inputBandwidth: {
15580
- help: "Input bandwidth (SRTO_INPUTBW xxx",
15925
+ help: "Input bandwidth (SRTO_INPUTBW)",
15581
15926
  hint: {
15582
15927
  type: "numeric",
15928
+ optional: true,
15583
15929
  validation: Z.optional(Z.number())
15584
15930
  }
15585
15931
  },
@@ -15587,6 +15933,7 @@ var result = ({ Z }) => ({
15587
15933
  help: "Overhead bandwidth (SRTO_OHEADBW)",
15588
15934
  hint: {
15589
15935
  type: "numeric",
15936
+ optional: true,
15590
15937
  validation: Z.optional(Z.number())
15591
15938
  }
15592
15939
  },
@@ -15594,6 +15941,7 @@ var result = ({ Z }) => ({
15594
15941
  help: "Max bandwidth (SRTO_MAXBW)",
15595
15942
  hint: {
15596
15943
  type: "numeric",
15944
+ optional: true,
15597
15945
  validation: Z.optional(Z.number())
15598
15946
  }
15599
15947
  }
@@ -15603,7 +15951,7 @@ var srt_socket_options_default = result;
15603
15951
  // build/input.srt-caller/info.js
15604
15952
  var import_react2 = __toESM(require_react());
15605
15953
  function info_default3({ defineComponent, Av, validation }) {
15606
- const { Port, IpAddress, SourceName, SrtPassphrase, SrtStreamId } = validation;
15954
+ const { Port, Hostname, SourceName, SrtPassphrase, SrtStreamId } = validation;
15607
15955
  const SocketConfiguration2 = import_react2.default.lazy(async () => {
15608
15956
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
15609
15957
  return { default: views.SocketConfiguration };
@@ -15612,6 +15960,7 @@ function info_default3({ defineComponent, Av, validation }) {
15612
15960
  identifier: "input.srt-caller",
15613
15961
  category: "input",
15614
15962
  name: "SRT Ingest (Caller)",
15963
+ description: "This component allows you to receive Secure Reliable Transport (SRT) streams by calling a remote SRT listener.",
15615
15964
  subscription: {
15616
15965
  accepts: void 0,
15617
15966
  produces: {
@@ -15622,16 +15971,16 @@ function info_default3({ defineComponent, Av, validation }) {
15622
15971
  display: (desc) => {
15623
15972
  return {
15624
15973
  port: desc.config.port.toString(),
15625
- ip: desc.config.ip
15974
+ ip: desc.config.host
15626
15975
  };
15627
15976
  },
15628
15977
  configForm: {
15629
15978
  form: {
15630
15979
  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" } },
15980
+ host: { help: "The IP address/hostname this SRT input will connect to", hint: { type: "text", validation: Hostname, defaultValue: "0.0.0.0" } },
15632
15981
  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 } },
15982
+ passphrase: { help: "Optional: Authentication for this SRT input", hint: { type: "text", optional: true, validation: SrtPassphrase } },
15983
+ streamId: { help: "Optional: StreamId to use when calling the remote listener", hint: { type: "text", optional: true, validation: SrtStreamId } },
15635
15984
  socketOptions: {
15636
15985
  help: "Socket Options",
15637
15986
  hint: {
@@ -15650,7 +15999,7 @@ var import_react3 = __toESM(require_react());
15650
15999
  var InlineView4 = import_react3.default.lazy(async () => Promise.resolve().then(() => (init_inline_view2(), inline_view_exports2)));
15651
16000
  var SummaryView4 = import_react3.default.lazy(async () => Promise.resolve().then(() => (init_summary_view2(), summary_view_exports2)));
15652
16001
  function info_default4({ defineComponent, Av, validation }) {
15653
- const { Z, Port, IpAddress, SourceName, SrtPassphrase, unique } = validation;
16002
+ const { Z, Port, Hostname, SourceName, SrtPassphrase, unique } = validation;
15654
16003
  const SocketConfiguration2 = import_react3.default.lazy(async () => {
15655
16004
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
15656
16005
  return { default: views.SocketConfiguration };
@@ -15659,6 +16008,7 @@ function info_default4({ defineComponent, Av, validation }) {
15659
16008
  identifier: "input.srt-listener",
15660
16009
  category: "input",
15661
16010
  name: "SRT Ingest (Listener)",
16011
+ 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
16012
  subscription: {
15663
16013
  accepts: void 0,
15664
16014
  produces: {
@@ -15679,7 +16029,7 @@ function info_default4({ defineComponent, Av, validation }) {
15679
16029
  display: (desc) => {
15680
16030
  return {
15681
16031
  port: desc.config.port.toString(),
15682
- ip: desc.config.ip
16032
+ ip: desc.config.host
15683
16033
  };
15684
16034
  },
15685
16035
  runtime: {
@@ -15713,11 +16063,11 @@ function info_default4({ defineComponent, Av, validation }) {
15713
16063
  envOverride: true
15714
16064
  }
15715
16065
  },
15716
- ip: {
15717
- help: "The IP address this SRT input will listen on",
16066
+ host: {
16067
+ help: "The IP address/hostname this SRT input will listen on",
15718
16068
  hint: {
15719
16069
  type: "text",
15720
- validation: IpAddress,
16070
+ validation: Hostname,
15721
16071
  defaultValue: "0.0.0.0",
15722
16072
  envOverride: true
15723
16073
  }
@@ -15726,6 +16076,7 @@ function info_default4({ defineComponent, Av, validation }) {
15726
16076
  help: "Optional: Authentication for this SRT input",
15727
16077
  hint: {
15728
16078
  type: "text",
16079
+ optional: true,
15729
16080
  validation: SrtPassphrase,
15730
16081
  envOverride: true
15731
16082
  }
@@ -15767,11 +16118,12 @@ function assertUnreachable2(_) {
15767
16118
  }
15768
16119
 
15769
16120
  // build/input.udp-ts/info.js
15770
- function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress, SourceName, unique } }) {
16121
+ function info_default5({ defineComponent, Av, validation: { Z, Port, Hostname, SourceName, unique } }) {
15771
16122
  return defineComponent({
15772
16123
  identifier: "input.udp-ts",
15773
16124
  category: "input",
15774
16125
  name: "UDP TS ingest",
16126
+ description: "This component receives and processes MPEG Transport Streams (TS) over UDP.",
15775
16127
  subscription: {
15776
16128
  accepts: void 0,
15777
16129
  produces: {
@@ -15782,15 +16134,15 @@ function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress,
15782
16134
  display: (desc) => {
15783
16135
  return {
15784
16136
  port: desc.config.port.toString(),
15785
- ip: desc.config.ip
16137
+ ip: desc.config.host
15786
16138
  };
15787
16139
  },
15788
16140
  configForm: {
15789
16141
  form: {
15790
16142
  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" } },
16143
+ host: { help: "The receiving IP address/hostname", hint: { type: "text", validation: Hostname, defaultValue: "127.0.0.1" } },
15792
16144
  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() } },
16145
+ 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
16146
  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
16147
  rtpDecapsulate: { help: "Whether to expect the input TS to be encapsulated in RTP via RFC 2250 (default: false)", hint: { type: "boolean" } }
15796
16148
  }
@@ -15799,11 +16151,12 @@ function info_default5({ defineComponent, Av, validation: { Z, Port, IpAddress,
15799
16151
  }
15800
16152
 
15801
16153
  // build/input.videoTestCard/info.js
15802
- function info_default6({ defineComponent, Video, validation: { SourceName }, common: { Resolutions, FrameRates } }) {
16154
+ function info_default6({ defineComponent, Video, validation: { SourceName, unique }, common: { Resolutions, FrameRates } }) {
15803
16155
  return defineComponent({
15804
16156
  identifier: "input.videoTestCard",
15805
16157
  category: "input",
15806
16158
  name: "Video Test Card",
16159
+ description: "The Video Test Card component generates a test card video stream with customizable settings.",
15807
16160
  subscription: {
15808
16161
  accepts: void 0,
15809
16162
  produces: {
@@ -15820,9 +16173,18 @@ function info_default6({ defineComponent, Video, validation: { SourceName }, com
15820
16173
  },
15821
16174
  configForm: {
15822
16175
  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" } },
16176
+ resolution: {
16177
+ help: "The resolution of the test card stream",
16178
+ hint: { type: "select", options: Resolutions, defaultValue: { width: 1280, height: 720 } }
16179
+ },
16180
+ frameRate: {
16181
+ help: "The frame rate of the test card stream",
16182
+ hint: { type: "select", options: FrameRates, defaultValue: { frames: 25, seconds: 1 } }
16183
+ },
16184
+ sourceName: {
16185
+ help: "Source name to use for this test card stream",
16186
+ hint: { type: "text", validation: SourceName, defaultValue: "video", global: unique("sourceName") }
16187
+ },
15826
16188
  pattern: {
15827
16189
  help: "The pattern on the test card stream",
15828
16190
  hint: {
@@ -15841,15 +16203,16 @@ function info_default6({ defineComponent, Video, validation: { SourceName }, com
15841
16203
  }
15842
16204
 
15843
16205
  // 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 () => {
16206
+ var import_config = __toESM(require_config());
16207
+ var import_react5 = __toESM(require_react());
16208
+ function info_default7(R) {
16209
+ const { defineComponent, All, validation: { Z, Hostname } } = R;
16210
+ const FullscreenView2 = import_react5.default.lazy(async () => Promise.resolve().then(() => (init_fullscreen(), fullscreen_exports)));
16211
+ const SegmentConfiguration2 = import_react5.default.lazy(async () => {
15849
16212
  const views = await Promise.resolve().then(() => (init_form_views(), form_views_exports));
15850
16213
  return { default: views.SegmentConfiguration };
15851
16214
  });
15852
- const S3Destination2 = import_react6.default.lazy(async () => {
16215
+ const S3Destination2 = import_react5.default.lazy(async () => {
15853
16216
  const views = await Promise.resolve().then(() => (init_form_views(), form_views_exports));
15854
16217
  return { default: views.S3Destination };
15855
16218
  });
@@ -15857,6 +16220,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15857
16220
  identifier: "output.autoCmaf",
15858
16221
  category: "output",
15859
16222
  name: "Auto CMAF",
16223
+ description: "This component handles the creation of CMAF outputs from multiple video and audio streams.",
15860
16224
  subscription: {
15861
16225
  // Again, accept anything
15862
16226
  // but reject the same stream twice
@@ -15867,10 +16231,36 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15867
16231
  }
15868
16232
  },
15869
16233
  extraValidation: (ctx) => {
15870
- const audioStreams = ctx.subscriptions.filter((s) => s.streams.select.includes("audio"));
16234
+ const audioStreams = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("audio"));
15871
16235
  if (audioStreams.length == 0) {
15872
16236
  ctx.addError("AutoCMAF requires at least one audio stream");
15873
16237
  }
16238
+ const uniqueVideoStreamNodes = ctx.subscriptions.reduce((acc, s) => {
16239
+ if (s.validatedStreams.select.includes("video")) {
16240
+ if (!acc.includes(s.source)) {
16241
+ acc.push(s.source);
16242
+ }
16243
+ }
16244
+ return acc;
16245
+ }, []);
16246
+ if (uniqueVideoStreamNodes.length > 1) {
16247
+ 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?)");
16248
+ }
16249
+ if (ctx.config.drmProvider && ctx.config.__global) {
16250
+ if (ctx.config.drmProvider === "ezdrm") {
16251
+ if (!ctx.config.__global.ezdrmConfig?.token) {
16252
+ ctx.addError("Provide EZDRM token in global configuration");
16253
+ }
16254
+ }
16255
+ if (ctx.config.drmProvider === "axinom") {
16256
+ if (!ctx.config.__global.axinomConfig?.tenantId) {
16257
+ ctx.addError("Provide Axinom DRM Tenant ID in global configuration");
16258
+ }
16259
+ if (!ctx.config.__global.axinomConfig?.managementKey) {
16260
+ ctx.addError("Provide Axinom DRM Management Key in global configuration");
16261
+ }
16262
+ }
16263
+ }
15874
16264
  },
15875
16265
  display: (desc) => {
15876
16266
  return {
@@ -15878,22 +16268,35 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15878
16268
  };
15879
16269
  },
15880
16270
  runtime: {
15881
- initialState: () => ({}),
16271
+ initialState: () => ({
16272
+ enabled: true
16273
+ }),
15882
16274
  handleEvent(ev, state) {
15883
16275
  const evType = ev.type;
15884
16276
  switch (evType) {
15885
16277
  case "url-published":
15886
16278
  state.url = ev.url;
16279
+ state.drmToken = ev.drmToken;
16280
+ break;
16281
+ case "output-enabled":
16282
+ state.enabled = true;
16283
+ break;
16284
+ case "output-disabled":
16285
+ state.enabled = false;
15887
16286
  break;
15888
16287
  default:
15889
16288
  assertUnreachable3(evType);
15890
16289
  }
15891
16290
  return { ...state };
15892
16291
  },
15893
- summary: SummaryView6,
16292
+ //summary: SummaryView,
15894
16293
  fullscreen: FullscreenView2
15895
16294
  },
15896
16295
  configForm: {
16296
+ global: {
16297
+ ezdrmConfig: (0, import_config.GlobalEzDrmConfig)(R),
16298
+ axinomConfig: (0, import_config.GlobalAxinomConfig)(R)
16299
+ },
15897
16300
  form: {
15898
16301
  name: {
15899
16302
  help: "The name of the multivariant/dash playlist",
@@ -15961,6 +16364,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15961
16364
  help: "How many segments back should a player start",
15962
16365
  hint: {
15963
16366
  type: "numeric",
16367
+ optional: true,
15964
16368
  validation: Z.number().min(3).max(10).int().optional()
15965
16369
  }
15966
16370
  },
@@ -15968,6 +16372,7 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15968
16372
  help: "How many parts back should a player start",
15969
16373
  hint: {
15970
16374
  type: "numeric",
16375
+ optional: true,
15971
16376
  validation: Z.number().min(3).max(10).int().optional()
15972
16377
  }
15973
16378
  }
@@ -15985,12 +16390,11 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
15985
16390
  help: "The hostname of the s3 bucket to push to",
15986
16391
  hint: {
15987
16392
  type: "text",
15988
- defaultValue: "",
15989
16393
  validation: Hostname
15990
16394
  }
15991
16395
  },
15992
16396
  prefix: {
15993
- help: "The sub directory of the bucket to place playlists + segments into",
16397
+ help: "The sub directory of the bucket to place playlists and segments into",
15994
16398
  hint: {
15995
16399
  type: "text",
15996
16400
  defaultValue: ""
@@ -16005,6 +16409,23 @@ function info_default7({ defineComponent, All, validation: { Z, Hostname } }) {
16005
16409
  }
16006
16410
  }
16007
16411
  }
16412
+ },
16413
+ drmProvider: {
16414
+ help: "Encrypt with a DRM provider (if configured globally)",
16415
+ hint: {
16416
+ type: "select",
16417
+ optional: true,
16418
+ options: [
16419
+ {
16420
+ display: "EZDRM",
16421
+ value: "ezdrm"
16422
+ },
16423
+ {
16424
+ display: "Axinom DRM",
16425
+ value: "axinom"
16426
+ }
16427
+ ]
16428
+ }
16008
16429
  }
16009
16430
  }
16010
16431
  }
@@ -16015,15 +16436,16 @@ function assertUnreachable3(_) {
16015
16436
  }
16016
16437
 
16017
16438
  // build/output.preview/info.js
16018
- var import_react8 = __toESM(require_react());
16019
- var import_config = __toESM(require_config());
16439
+ var import_react7 = __toESM(require_react());
16440
+ var import_config2 = __toESM(require_config());
16020
16441
  function info_default8(R) {
16021
16442
  const { defineComponent, Av, validation: { JitterBuffer } } = R;
16022
- const InlineView13 = import_react8.default.lazy(async () => Promise.resolve().then(() => (init_inline_view3(), inline_view_exports3)));
16443
+ const InlineView13 = import_react7.default.lazy(async () => Promise.resolve().then(() => (init_inline_view3(), inline_view_exports3)));
16023
16444
  return defineComponent({
16024
16445
  identifier: "output.preview",
16025
16446
  category: "output",
16026
16447
  name: "Preview",
16448
+ 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
16449
  subscription: {
16028
16450
  accepts: {
16029
16451
  type: "single-stream",
@@ -16032,8 +16454,8 @@ function info_default8(R) {
16032
16454
  produces: void 0
16033
16455
  },
16034
16456
  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"));
16457
+ const video = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("video"));
16458
+ const audio = ctx.subscriptions.filter((s) => s.validatedStreams.select.includes("audio"));
16037
16459
  if (video.length == 1 && audio.length == 1)
16038
16460
  return;
16039
16461
  if (video.length == 0) {
@@ -16073,11 +16495,12 @@ function info_default8(R) {
16073
16495
  },
16074
16496
  configForm: {
16075
16497
  global: {
16076
- iceServers: (0, import_config.GlobalIceServers)(R),
16077
- hardware: (0, import_config.HardwareSelection)()
16498
+ iceServers: (0, import_config2.GlobalIceServers)(R),
16499
+ hardware: (0, import_config2.HardwareSelection)()
16078
16500
  },
16079
16501
  form: {
16080
- bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } }
16502
+ bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16503
+ skipTranscode: { help: "Skip transcoding for WebRTC-ready streams", hint: { type: "boolean", defaultValue: false } }
16081
16504
  }
16082
16505
  }
16083
16506
  });
@@ -16087,13 +16510,14 @@ function assertUnreachable4(_) {
16087
16510
  }
16088
16511
 
16089
16512
  // build/output.rtmp/info.js
16090
- var import_react9 = __toESM(require_react());
16513
+ var import_react8 = __toESM(require_react());
16091
16514
  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)));
16515
+ const InlineView13 = import_react8.default.lazy(async () => Promise.resolve().then(() => (init_inline_view4(), inline_view_exports4)));
16093
16516
  return defineComponent({
16094
16517
  identifier: "output.rtmp",
16095
16518
  category: "output",
16096
16519
  name: "RTMP Egest",
16520
+ 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
16521
  subscription: {
16098
16522
  // No validation?
16099
16523
  // Accept either *just* audio, or *just* video, or audio *and* video
@@ -16144,11 +16568,12 @@ function assertUnreachable5(_) {
16144
16568
  }
16145
16569
 
16146
16570
  // build/output.srt/info.js
16147
- var import_react10 = __toESM(require_react());
16571
+ var import_react9 = __toESM(require_react());
16572
+ var import_util = __toESM(require_util());
16148
16573
  function info_default10(registration) {
16149
16574
  const { defineComponent, All, validation } = registration;
16150
- const { Port, IpAddress, JitterBuffer, SrtPassphrase, SrtStreamId } = validation;
16151
- const SocketConfiguration2 = import_react10.default.lazy(async () => {
16575
+ const { Port, Hostname, JitterBuffer, SrtPassphrase, SrtStreamId } = validation;
16576
+ const SocketConfiguration2 = import_react9.default.lazy(async () => {
16152
16577
  const views = await Promise.resolve().then(() => (init_srt_form_views(), srt_form_views_exports));
16153
16578
  return { default: views.SocketConfiguration };
16154
16579
  });
@@ -16156,6 +16581,7 @@ function info_default10(registration) {
16156
16581
  identifier: "output.srt",
16157
16582
  category: "output",
16158
16583
  name: "SRT Egest",
16584
+ 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
16585
  subscription: {
16160
16586
  // No validation?
16161
16587
  // Streams have to be unique? That's a stretch goal
@@ -16167,11 +16593,30 @@ function info_default10(registration) {
16167
16593
  display: (desc) => {
16168
16594
  return {
16169
16595
  port: desc.config.port?.toString() ?? "",
16170
- ip: desc.config.ip,
16596
+ host: desc.config.host,
16171
16597
  mode: desc.config.mode,
16172
16598
  bufferDelayMs: desc.config.bufferDelayMs?.toString() ?? "none"
16173
16599
  };
16174
16600
  },
16601
+ runtime: {
16602
+ initialState: () => ({
16603
+ enabled: true
16604
+ }),
16605
+ handleEvent(ev, state) {
16606
+ const evType = ev.type;
16607
+ switch (evType) {
16608
+ case "output-enabled":
16609
+ state.enabled = true;
16610
+ break;
16611
+ case "output-disabled":
16612
+ state.enabled = false;
16613
+ break;
16614
+ default:
16615
+ (0, import_util.assertUnreachable)(evType);
16616
+ }
16617
+ return { ...state };
16618
+ }
16619
+ },
16175
16620
  configForm: {
16176
16621
  form: {
16177
16622
  port: {
@@ -16187,7 +16632,7 @@ function info_default10(registration) {
16187
16632
  }
16188
16633
  }
16189
16634
  },
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" } },
16635
+ 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
16636
  bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16192
16637
  avDelayMs: { help: "How many milliseconds to delay A/V to account for subtitles/ancillary data", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 50 } },
16193
16638
  mode: {
@@ -16207,8 +16652,8 @@ function info_default10(registration) {
16207
16652
  ]
16208
16653
  }
16209
16654
  },
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 } },
16655
+ passphrase: { help: "Optional: Authentication for this SRT output", hint: { type: "text", optional: true, validation: SrtPassphrase } },
16656
+ streamId: { help: "Optional: StreamId to use when calling a remote listener", hint: { type: "text", optional: true, validation: SrtStreamId } },
16212
16657
  socketOptions: {
16213
16658
  help: "Socket Options",
16214
16659
  hint: {
@@ -16226,11 +16671,12 @@ function info_default10(registration) {
16226
16671
  init_info();
16227
16672
 
16228
16673
  // build/output.udpTs/info.js
16229
- function info_default12({ defineComponent, All, validation: { Port, IpAddress, JitterBuffer, Iface, Z } }) {
16674
+ function info_default12({ defineComponent, All, validation: { Port, Hostname, JitterBuffer, Iface, Z } }) {
16230
16675
  return defineComponent({
16231
16676
  identifier: "output.udpTs",
16232
16677
  category: "output",
16233
16678
  name: "UDP TS Egest",
16679
+ 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
16680
  subscription: {
16235
16681
  // Just works with no validation
16236
16682
  // although uniqueness again, stretch goal
@@ -16242,7 +16688,7 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16242
16688
  display: (desc) => {
16243
16689
  return {
16244
16690
  port: desc.config.port.toString(),
16245
- destinationIp: desc.config.destinationIp,
16691
+ destinationIp: desc.config.destinationHost,
16246
16692
  interface: desc.config.interface,
16247
16693
  bufferDelayMs: desc.config.bufferDelayMs?.toString() ?? "none"
16248
16694
  };
@@ -16250,7 +16696,7 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16250
16696
  configForm: {
16251
16697
  form: {
16252
16698
  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" } },
16699
+ destinationHost: { help: "The IP address/Hostname this UDP TS output will send to", hint: { type: "text", validation: Hostname, defaultValue: "127.0.0.1" } },
16254
16700
  bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } },
16255
16701
  interface: { help: "Which interface to bind to for publishing", hint: { type: "text", validation: Z.union([Z.string().length(0), Iface]), defaultValue: "any" } }
16256
16702
  }
@@ -16259,13 +16705,16 @@ function info_default12({ defineComponent, All, validation: { Port, IpAddress, J
16259
16705
  }
16260
16706
 
16261
16707
  // build/output.whep/info.js
16262
- var import_config2 = __toESM(require_config());
16708
+ var import_config3 = __toESM(require_config());
16709
+ var import_react12 = __toESM(require_react());
16263
16710
  function info_default13(R) {
16264
16711
  const { defineComponent, Av, validation: { JitterBuffer } } = R;
16712
+ const InlineView13 = import_react12.default.lazy(async () => Promise.resolve().then(() => (init_inline_view6(), inline_view_exports6)));
16265
16713
  return defineComponent({
16266
16714
  identifier: "output.whep",
16267
16715
  category: "output",
16268
16716
  name: "WHEP Egest",
16717
+ description: "This component allows us to use WebRTC egress for outputs.",
16269
16718
  subscription: {
16270
16719
  // No validation?
16271
16720
  // Accept either *just* audio, or *just* video, or audio *and* video
@@ -16280,9 +16729,25 @@ function info_default13(R) {
16280
16729
  display: (_desc) => {
16281
16730
  return {};
16282
16731
  },
16732
+ css: ["styles.css"],
16733
+ runtime: {
16734
+ initialState: () => ({}),
16735
+ handleEvent(ev, state) {
16736
+ const evType = ev.type;
16737
+ switch (evType) {
16738
+ case "url-published":
16739
+ state.url = ev.url;
16740
+ break;
16741
+ default:
16742
+ assertUnreachable8(evType);
16743
+ }
16744
+ return { ...state };
16745
+ },
16746
+ inline: InlineView13
16747
+ },
16283
16748
  configForm: {
16284
16749
  global: {
16285
- iceServers: (0, import_config2.GlobalIceServers)(R)
16750
+ iceServers: (0, import_config3.GlobalIceServers)(R)
16286
16751
  },
16287
16752
  form: {
16288
16753
  bufferDelayMs: { help: "How many milliseconds in the jitter buffer", hint: { type: "numeric", validation: JitterBuffer, defaultValue: 500 } }
@@ -16290,14 +16755,21 @@ function info_default13(R) {
16290
16755
  }
16291
16756
  });
16292
16757
  }
16758
+ function assertUnreachable8(_) {
16759
+ throw new Error("Didn't expect to get here");
16760
+ }
16293
16761
 
16294
16762
  // build/processor.browserOverlay/info.js
16295
- var import_config3 = __toESM(require_config());
16763
+ var import_config4 = __toESM(require_config());
16764
+ var import_react14 = __toESM(require_react());
16765
+ var SummaryView6 = import_react14.default.lazy(async () => Promise.resolve().then(() => (init_summary_view3(), summary_view_exports3)));
16766
+ var InlineView10 = import_react14.default.lazy(async () => Promise.resolve().then(() => (init_inline_view7(), inline_view_exports7)));
16296
16767
  function info_default14({ defineComponent, Video, validation: { Z } }) {
16297
16768
  return defineComponent({
16298
- identifier: "processor.transform.browserOverlay",
16769
+ identifier: "processor.browserOverlay",
16299
16770
  category: "processor",
16300
16771
  name: "Browser Overlay",
16772
+ description: "Capture a live URL and overlay onto a video",
16301
16773
  subscription: {
16302
16774
  // Only accept a single video stream
16303
16775
  accepts: {
@@ -16314,12 +16786,33 @@ function info_default14({ defineComponent, Video, validation: { Z } }) {
16314
16786
  },
16315
16787
  display: (desc) => {
16316
16788
  return {
16317
- url: desc.config?.url
16789
+ url: desc.config.url
16318
16790
  };
16319
16791
  },
16792
+ runtime: {
16793
+ summary: SummaryView6,
16794
+ inline: InlineView10,
16795
+ initialState: () => ({
16796
+ currentUrl: "",
16797
+ enabled: true
16798
+ }),
16799
+ handleEvent: (ev, state) => {
16800
+ const evType = ev.type;
16801
+ switch (evType) {
16802
+ case "url-changed":
16803
+ return { ...state, currentUrl: ev.url };
16804
+ case "enabled":
16805
+ return { ...state, enabled: true };
16806
+ case "disabled":
16807
+ return { ...state, enabled: false };
16808
+ default:
16809
+ assertUnreachable9(evType);
16810
+ }
16811
+ }
16812
+ },
16320
16813
  configForm: {
16321
16814
  global: {
16322
- hardware: (0, import_config3.HardwareSelection)()
16815
+ hardware: (0, import_config4.HardwareSelection)()
16323
16816
  },
16324
16817
  form: {
16325
16818
  url: { help: "URL to render on top of the video", hint: { type: "text", validation: Z.string().url(), defaultValue: "" } }
@@ -16327,15 +16820,19 @@ function info_default14({ defineComponent, Video, validation: { Z } }) {
16327
16820
  }
16328
16821
  });
16329
16822
  }
16823
+ function assertUnreachable9(_) {
16824
+ throw new Error("Didn't expect to get here");
16825
+ }
16330
16826
 
16331
16827
  // build/processor.cascadingSwitch/info.js
16332
16828
  function info_default15({ defineComponent, Av, React: React14, common: { Resolutions, FrameRates } }) {
16333
16829
  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)));
16830
+ const InlineView13 = React14.lazy(async () => Promise.resolve().then(() => (init_inline_view8(), inline_view_exports8)));
16335
16831
  return defineComponent({
16336
- identifier: "processor.control.cascadingSwitch",
16832
+ identifier: "processor.cascadingSwitch",
16337
16833
  category: "processor",
16338
16834
  name: "Cascading Switch",
16835
+ 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
16836
  subscription: {
16340
16837
  // This needs to change anyway
16341
16838
  // but it'll be the same as MCS
@@ -16350,10 +16847,10 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16350
16847
  },
16351
16848
  extraValidation: function(ctx) {
16352
16849
  ctx.subscriptions.forEach((s) => {
16353
- if (!s.streams.select.includes("video")) {
16850
+ if (!s.validatedStreams.select.includes("video")) {
16354
16851
  ctx.addError(`Subscription to ${s.source} is missing video`);
16355
16852
  }
16356
- if (!s.streams.select.includes("audio")) {
16853
+ if (!s.validatedStreams.select.includes("audio")) {
16357
16854
  ctx.addError(`Subscription to ${s.source} is missing audio`);
16358
16855
  }
16359
16856
  if (s.streams.type == "take-all-streams") {
@@ -16409,7 +16906,7 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16409
16906
  state.availableSources.splice(state.availableSources.indexOf(ev.source), 1);
16410
16907
  return { ...state };
16411
16908
  default:
16412
- assertUnreachable7(evType);
16909
+ assertUnreachable10(evType);
16413
16910
  }
16414
16911
  },
16415
16912
  inline: InlineView13,
@@ -16460,96 +16957,22 @@ function info_default15({ defineComponent, Av, React: React14, common: { Resolut
16460
16957
  }
16461
16958
  });
16462
16959
  }
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(_) {
16960
+ function assertUnreachable10(_) {
16539
16961
  throw new Error("Didn't expect to get here");
16540
16962
  }
16541
16963
 
16542
16964
  // build/processor.fixedLadder/info.js
16543
16965
  var import_react17 = __toESM(require_react());
16544
16966
  var import_config5 = __toESM(require_config());
16545
- function info_default17({ defineComponent, Video }) {
16967
+ function info_default16({ defineComponent, Video }) {
16546
16968
  const RungView = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_rung_view(), rung_view_exports)));
16547
16969
  const CodecEditor3 = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_codec_editor(), codec_editor_exports)));
16548
16970
  const CodecView = import_react17.default.lazy(async () => Promise.resolve().then(() => (init_codec_view(), codec_view_exports)));
16549
16971
  return defineComponent({
16550
- identifier: "processor.transform.fixedLadder",
16972
+ identifier: "processor.fixedLadder",
16551
16973
  category: "processor",
16552
16974
  name: "Encode Ladder",
16975
+ 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
16976
  subscription: {
16554
16977
  // Only accept a single video stream
16555
16978
  accepts: {
@@ -16665,6 +17088,7 @@ function info_default17({ defineComponent, Video }) {
16665
17088
  help: `Settings to use when encoding using ${mode} mode`,
16666
17089
  hint: {
16667
17090
  type: "form-item",
17091
+ optional: true,
16668
17092
  view: CodecView,
16669
17093
  form: {
16670
17094
  width: {
@@ -16707,7 +17131,7 @@ function createSoftwareRung(rung) {
16707
17131
  case "h264_320x180":
16708
17132
  return createRungImpl({ name: rung, threads: 1, bitrate: 800 });
16709
17133
  default:
16710
- return assertUnreachable9(rung);
17134
+ return assertUnreachable11(rung);
16711
17135
  }
16712
17136
  }
16713
17137
  function createMa35dRung(rung) {
@@ -16721,7 +17145,7 @@ function createMa35dRung(rung) {
16721
17145
  case "h264_320x180":
16722
17146
  return createMa35DH264RungImpl({ name: rung, bitrate: 1e3 });
16723
17147
  default:
16724
- return assertUnreachable9(rung);
17148
+ return assertUnreachable11(rung);
16725
17149
  }
16726
17150
  }
16727
17151
  function createNvidiaRung(rung) {
@@ -16735,7 +17159,7 @@ function createNvidiaRung(rung) {
16735
17159
  case "h264_320x180":
16736
17160
  return createNvidiaRungImpl({ name: rung, bitrate: 8e5 });
16737
17161
  default:
16738
- return assertUnreachable9(rung);
17162
+ return assertUnreachable11(rung);
16739
17163
  }
16740
17164
  }
16741
17165
  function createQuadraRung(rung) {
@@ -16749,7 +17173,7 @@ function createQuadraRung(rung) {
16749
17173
  case "h264_320x180":
16750
17174
  return createQuadraRungImpl({ name: rung, bitrate: 8e5 });
16751
17175
  default:
16752
- return assertUnreachable9(rung);
17176
+ return assertUnreachable11(rung);
16753
17177
  }
16754
17178
  }
16755
17179
  function createLoganRung(rung) {
@@ -16763,7 +17187,7 @@ function createLoganRung(rung) {
16763
17187
  case "h264_320x180":
16764
17188
  return createLoganRungImpl({ name: rung, bitrate: 8e5 });
16765
17189
  default:
16766
- return assertUnreachable9(rung);
17190
+ return assertUnreachable11(rung);
16767
17191
  }
16768
17192
  }
16769
17193
  function createRungImpl({ name, threads, bitrate }) {
@@ -16861,62 +17285,248 @@ function rungWidth(rungName) {
16861
17285
  function rungHeight(rungName) {
16862
17286
  return parseInt(rungName.split("_")[1].split(`x`)[1]);
16863
17287
  }
16864
- function assertUnreachable9(_) {
17288
+ function assertUnreachable11(_) {
16865
17289
  throw new Error("Didn't expect to get here");
16866
17290
  }
16867
17291
 
16868
- // build/processor.whisper-transcribe/info.js
16869
- function info_default18({ defineComponent, Av, Subtitle, validation: { Z } }) {
17292
+ // build/processor.onscreenGraphic/info.js
17293
+ var import_config6 = __toESM(require_config());
17294
+ var import_react20 = __toESM(require_react());
17295
+ function info_default17({ defineComponent, Video }) {
17296
+ const GraphicSelection2 = import_react20.default.lazy(async () => Promise.resolve().then(() => (init_image_selection(), image_selection_exports)));
17297
+ const SummaryView8 = import_react20.default.lazy(async () => Promise.resolve().then(() => (init_summary_view4(), summary_view_exports4)));
16870
17298
  return defineComponent({
16871
- identifier: "processor.whisper-transcribe",
17299
+ identifier: "processor.onscreenGraphic",
16872
17300
  category: "processor",
16873
- name: "Whisper Transcribe",
17301
+ name: "Onscreen Graphic",
17302
+ description: "Overlay graphics onto a video",
16874
17303
  subscription: {
17304
+ // Only accept a single video stream
16875
17305
  accepts: {
16876
17306
  type: "single-stream",
16877
- media: Av
16878
- // video because we'll use the id of it..
17307
+ media: Video
16879
17308
  },
16880
17309
  produces: {
16881
- media: Subtitle,
16882
- type: "single-stream"
17310
+ type: "single-stream",
17311
+ media: Video
16883
17312
  }
16884
17313
  },
16885
17314
  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
- }
17315
+ ctx.requireVideo(1);
16894
17316
  },
16895
17317
  display: (desc) => {
16896
17318
  return {
16897
- model: desc.config.model
17319
+ default: desc.config.initialGraphic ?? "none"
16898
17320
  };
16899
17321
  },
17322
+ runtime: {
17323
+ summary: SummaryView8,
17324
+ initialState: () => ({}),
17325
+ handleEvent: (ev, state) => {
17326
+ const evType = ev.type;
17327
+ switch (evType) {
17328
+ case "graphic-changed":
17329
+ return { ...state, activeGraphic: { file: ev.file, position: ev.position } };
17330
+ case "video-changed":
17331
+ return { ...state, currentVideo: ev.currentVideo };
17332
+ case "graphic-loaded":
17333
+ return { ...state, currentGraphic: ev.currentGraphic };
17334
+ default:
17335
+ assertUnreachable13(evType);
17336
+ }
17337
+ }
17338
+ },
17339
+ configForm: {
17340
+ global: {
17341
+ hardware: (0, import_config6.HardwareSelection)()
17342
+ },
17343
+ form: {
17344
+ initialGraphic: {
17345
+ help: "The initial graphic to render on the video (if any)",
17346
+ hint: {
17347
+ type: "custom",
17348
+ optional: true,
17349
+ component: GraphicSelection2
17350
+ }
17351
+ },
17352
+ initialPosition: {
17353
+ help: "The initial location at which to render the graphic",
17354
+ hint: {
17355
+ type: "select",
17356
+ optional: true,
17357
+ options: [
17358
+ { value: { type: "named", position: "topleft" }, display: "Top Left" },
17359
+ { value: { type: "named", position: "topright" }, display: "Top Right" },
17360
+ { value: { type: "named", position: "bottomleft" }, display: "Bottom Left" },
17361
+ { value: { type: "named", position: "bottomright" }, display: "Bottom Right" },
17362
+ { value: { type: "named", position: "center" }, display: "Centered" }
17363
+ ]
17364
+ }
17365
+ }
17366
+ }
17367
+ }
17368
+ });
17369
+ }
17370
+ function assertUnreachable13(_) {
17371
+ throw new Error("Didn't expect to get here");
17372
+ }
17373
+
17374
+ // build/processor.streamKeyOverride/info.js
17375
+ function info_default18({ defineComponent, All, validation: { Z } }) {
17376
+ return defineComponent({
17377
+ identifier: "processor.StreamKeyOverride",
17378
+ category: "processor",
17379
+ name: "Stream Key Override",
17380
+ description: "Override stream keys for several streams at once, setting some components of the keys and optionally incrementing stream ID.",
17381
+ subscription: {
17382
+ accepts: {
17383
+ type: "multi-stream",
17384
+ media: All
17385
+ },
17386
+ produces: {
17387
+ type: "fixed-list",
17388
+ possibleMedia: All,
17389
+ keys: (cfg, subs) => {
17390
+ const outputs = subs.flatMap((sub) => {
17391
+ const sourceNode = sub.document.components[sub.source];
17392
+ if (!sourceNode)
17393
+ return [];
17394
+ const produces = sourceNode.info.subscription.produces;
17395
+ if (produces?.type === "fixed-list") {
17396
+ return produces.keys(sourceNode.config, sourceNode.subscriptions).map((sel) => ({ ...sel, key: `${sourceNode.id}-${sel.key}`, display: `${sourceNode.config.displayName}: ${sel.display}` }));
17397
+ } else {
17398
+ return [{ key: `${sourceNode.id}`, display: `${sourceNode.config.displayName}`, media: produces ? produces.media : All }];
17399
+ }
17400
+ });
17401
+ if (cfg.output === "merged") {
17402
+ const media = Array.from(new Set(outputs.flatMap((x) => x.media)));
17403
+ return [{ key: `merged`, display: "Merged", media }];
17404
+ }
17405
+ return outputs;
17406
+ },
17407
+ selector: () => {
17408
+ console.error("Use selectOutputs from process.streamKeyOverride/runtime.ts, not selector from info.ts");
17409
+ return [];
17410
+ }
17411
+ }
17412
+ },
17413
+ display: ({ config }) => {
17414
+ const disp = {};
17415
+ disp.mode = config.mode || "simple";
17416
+ disp.output = config.output || "individually-selectable";
17417
+ if (config.sourceName) {
17418
+ disp.sourceName = config.sourceName;
17419
+ }
17420
+ if (config.programNumber !== void 0) {
17421
+ disp.programNumber = String(config.programNumber);
17422
+ }
17423
+ if (config.streamId !== void 0) {
17424
+ disp.streamId = String(config.streamId);
17425
+ }
17426
+ if (config.renditionName) {
17427
+ disp.renditionName = config.renditionName;
17428
+ }
17429
+ return disp;
17430
+ },
17431
+ extraValidation: (ctx) => {
17432
+ const { config, subscriptions } = ctx;
17433
+ if ((config.mode || "simple") == "simple" && config.sourceName && config.programNumber !== void 0 && config.streamId !== void 0 && config.renditionName) {
17434
+ if (subscriptions.length > 1)
17435
+ ctx.addError("A fully specified stream key override must only subscribe to one stream, or use a mode other than simple");
17436
+ }
17437
+ if (config.mode === "by-media-type" && config.streamId === void 0) {
17438
+ ctx.addError("You must specify the starting streamId for a by-media-type stream key override");
17439
+ }
17440
+ if (config.output === "merged" && !config.sourceName) {
17441
+ ctx.addError("You must specify a sourceName for a single merged output");
17442
+ }
17443
+ },
16900
17444
  configForm: {
16901
17445
  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)]) } }
17446
+ mode: {
17447
+ help: "Multi-stream behavior",
17448
+ hint: {
17449
+ type: "select",
17450
+ defaultValue: "simple",
17451
+ options: [
17452
+ {
17453
+ display: "Override values directly",
17454
+ value: "simple"
17455
+ },
17456
+ {
17457
+ display: "Increment stream ID by media type (video, audio, ...)",
17458
+ value: "by-media-type"
17459
+ },
17460
+ {
17461
+ display: "Increment stream ID per program in order of subscription",
17462
+ value: "in-order"
17463
+ }
17464
+ ]
17465
+ }
17466
+ },
17467
+ output: {
17468
+ help: "Output individual streams or a single merged stream",
17469
+ hint: {
17470
+ type: "select",
17471
+ defaultValue: "individually-selectable",
17472
+ options: [
17473
+ {
17474
+ display: "Individual inputs can be selected in the output",
17475
+ value: "individually-selectable"
17476
+ },
17477
+ {
17478
+ display: "The outputs are merged into a single stream",
17479
+ value: "merged"
17480
+ }
17481
+ ]
17482
+ }
17483
+ },
17484
+ sourceName: {
17485
+ help: "Override source name",
17486
+ hint: {
17487
+ type: "text",
17488
+ optional: true
17489
+ }
17490
+ },
17491
+ programNumber: {
17492
+ help: "Override program number",
17493
+ hint: {
17494
+ type: "numeric",
17495
+ optional: true,
17496
+ validation: Z.number().min(0).int().optional()
17497
+ }
17498
+ },
17499
+ streamId: {
17500
+ help: "Override stream ID",
17501
+ hint: {
17502
+ type: "numeric",
17503
+ optional: true,
17504
+ validation: Z.number().min(0).int().optional()
17505
+ }
17506
+ },
17507
+ renditionName: {
17508
+ help: "Override rendition name",
17509
+ hint: {
17510
+ type: "text",
17511
+ optional: true
17512
+ }
17513
+ }
16905
17514
  }
16906
17515
  }
16907
17516
  });
16908
17517
  }
16909
17518
 
16910
- // build/util.latency/info.js
16911
- var import_react19 = __toESM(require_react());
17519
+ // build/util.stats.latency/info.js
17520
+ var import_react22 = __toESM(require_react());
16912
17521
  function info_default19(R) {
16913
17522
  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)));
17523
+ const InlineView13 = import_react22.default.lazy(async () => Promise.resolve().then(() => (init_inline_view9(), inline_view_exports9)));
17524
+ const SourceNodeSelection2 = import_react22.default.lazy(async () => Promise.resolve().then(() => (init_source_node_selection(), source_node_selection_exports)));
16916
17525
  return defineComponent({
16917
- identifier: "util.latency-stats",
17526
+ identifier: "util.stats.latency",
16918
17527
  category: "output",
16919
17528
  name: "Latency Probe",
17529
+ description: "This component tracks and processes latency statistics within a media processing pipeline.",
16920
17530
  subscription: {
16921
17531
  accepts: void 0,
16922
17532
  produces: void 0
@@ -16939,7 +17549,7 @@ function info_default19(R) {
16939
17549
  break;
16940
17550
  }
16941
17551
  default:
16942
- assertUnreachable10(evType);
17552
+ assertUnreachable14(evType);
16943
17553
  }
16944
17554
  return { ...state };
16945
17555
  },
@@ -16993,113 +17603,7 @@ function info_default19(R) {
16993
17603
  }
16994
17604
  });
16995
17605
  }
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(_) {
17606
+ function assertUnreachable14(_) {
17103
17607
  throw new Error("Didn't expect to get here");
17104
17608
  }
17105
17609
 
@@ -17136,8 +17640,6 @@ AllComponents.push((r) => info_default16(r));
17136
17640
  AllComponents.push((r) => info_default17(r));
17137
17641
  AllComponents.push((r) => info_default18(r));
17138
17642
  AllComponents.push((r) => info_default19(r));
17139
- AllComponents.push((r) => info_default20(r));
17140
- AllComponents.push((r) => info_default21(r));
17141
17643
  export {
17142
17644
  getNodeInfo as default
17143
17645
  };