@camstack/addon-pipeline 1.2.370 → 1.2.371

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 (37) hide show
  1. package/dist/audio-analyzer/index.js +3 -3
  2. package/dist/audio-analyzer/index.mjs +3 -3
  3. package/dist/{custom-model-catalog-CVbK0xKc.mjs → custom-model-catalog-C6C2cSwd.mjs} +2 -2
  4. package/dist/{custom-model-catalog-BFosahFu.js → custom-model-catalog-n9v8MUL6.js} +2 -2
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-CbFPOFAD.mjs → dist-8AEiKOFO.mjs} +291 -21
  8. package/dist/{dist-jkwxbcbK.js → dist-DmuX7IFJ.js} +308 -20
  9. package/dist/{model-catalogs-DJmwfLfC.mjs → model-catalogs-BSWAHZJh.mjs} +1 -1
  10. package/dist/{model-catalogs-Ds2hC2Br.js → model-catalogs-DO4aA1qo.js} +1 -1
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/{node-C-2fB9kH.mjs → node-Bd4va7c-.mjs} +1 -1
  14. package/dist/{node-C_1U1uzn.js → node-DqA6nD1z.js} +1 -1
  15. package/dist/pipeline-runner/index.js +3 -3
  16. package/dist/pipeline-runner/index.mjs +3 -3
  17. package/dist/{process-memory-Cfh1BQYg.js → process-memory-2OQ2oxrz.js} +1 -1
  18. package/dist/{process-memory-B3I-NvnX.mjs → process-memory-BvS2Z88w.mjs} +1 -1
  19. package/dist/recorder/index.js +184 -54
  20. package/dist/recorder/index.mjs +184 -54
  21. package/dist/{segment-demux-js-uxBcJy15.js → segment-demux-js-BkGK1rhu.js} +1 -1
  22. package/dist/{segment-demux-js-D3JBJeN6.mjs → segment-demux-js-By9MLn_g.mjs} +1 -1
  23. package/dist/stream-broker/_stub.js +1188 -861
  24. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DwwDKaZJ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DjoAY42S.mjs} +3 -3
  25. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C3ssSNKh.mjs +26 -0
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-nua-KuDg.mjs +26 -0
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-DVwYY7oo.mjs → hostInit-DPiGNc5u.mjs} +3 -3
  30. package/dist/stream-broker/index.js +3 -3
  31. package/dist/stream-broker/index.mjs +3 -3
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/i18n/en.json +8 -0
  34. package/i18n/it.json +8 -0
  35. package/package.json +6 -1
  36. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bna0L8uC.mjs +0 -26
  37. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BAvXcDKy.mjs +0 -26
@@ -1,13 +1,13 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BAvXcDKy.mjs";
2
- import { a as p, i as m, n as h, o as g, r as _, t as v } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
3
- import { n as y, r as b, t as x } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
4
- import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bna0L8uC.mjs";
5
- import { n as C, t as w } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BO7TIbJV.mjs";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f, u as p } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-nua-KuDg.mjs";
2
+ import { a as m, i as h, n as g, o as _, r as v, t as y } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
3
+ import { n as b, r as x, t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
4
+ import { t as C } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C3ssSNKh.mjs";
5
+ import { n as w, t as T } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BO7TIbJV.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
- var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), E = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), D = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), O = (e) => {
8
- let t = D(e);
7
+ var E = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), D = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), O = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), k = (e) => {
8
+ let t = O(e);
9
9
  return t.charAt(0).toUpperCase() + t.slice(1);
10
- }, k = {
10
+ }, A = {
11
11
  xmlns: "http://www.w3.org/2000/svg",
12
12
  width: 24,
13
13
  height: 24,
@@ -17,37 +17,37 @@ var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
17
17
  strokeWidth: 2,
18
18
  strokeLinecap: "round",
19
19
  strokeLinejoin: "round"
20
- }, A = (e) => {
20
+ }, j = (e) => {
21
21
  for (let t in e) if (t.startsWith("aria-") || t === "role" || t === "title") return !0;
22
22
  return !1;
23
- }, j = h(({ color: e = "currentColor", size: t = 24, strokeWidth: n = 2, absoluteStrokeWidth: r, className: i = "", children: a, iconNode: o, ...s }, c) => v("svg", {
23
+ }, M = g(({ color: e = "currentColor", size: t = 24, strokeWidth: n = 2, absoluteStrokeWidth: r, className: i = "", children: a, iconNode: o, ...s }, c) => y("svg", {
24
24
  ref: c,
25
- ...k,
25
+ ...A,
26
26
  width: t,
27
27
  height: t,
28
28
  stroke: e,
29
29
  strokeWidth: r ? Number(n) * 24 / Number(t) : n,
30
- className: T("lucide", i),
31
- ...!a && !A(s) && { "aria-hidden": "true" },
30
+ className: E("lucide", i),
31
+ ...!a && !j(s) && { "aria-hidden": "true" },
32
32
  ...s
33
- }, [...o.map(([e, t]) => v(e, t)), ...Array.isArray(a) ? a : [a]])), M = (e, t) => {
34
- let n = h(({ className: n, ...r }, i) => v(j, {
33
+ }, [...o.map(([e, t]) => y(e, t)), ...Array.isArray(a) ? a : [a]])), N = (e, t) => {
34
+ let n = g(({ className: n, ...r }, i) => y(M, {
35
35
  ref: i,
36
36
  iconNode: t,
37
- className: T(`lucide-${E(O(e))}`, `lucide-${e}`, n),
37
+ className: E(`lucide-${D(k(e))}`, `lucide-${e}`, n),
38
38
  ...r
39
39
  }));
40
- return n.displayName = O(e), n;
41
- }, N = M("check", [["path", {
40
+ return n.displayName = k(e), n;
41
+ }, P = N("check", [["path", {
42
42
  d: "M20 6 9 17l-5-5",
43
43
  key: "1gmf2c"
44
- }]]), P = M("chevron-down", [["path", {
44
+ }]]), F = N("chevron-down", [["path", {
45
45
  d: "m6 9 6 6 6-6",
46
46
  key: "qrunsl"
47
- }]]), F = M("chevron-right", [["path", {
47
+ }]]), I = N("chevron-right", [["path", {
48
48
  d: "m9 18 6-6-6-6",
49
49
  key: "mthhwq"
50
- }]]), ee = M("circle-alert", [
50
+ }]]), L = N("circle-alert", [
51
51
  ["circle", {
52
52
  cx: "12",
53
53
  cy: "12",
@@ -68,16 +68,16 @@ var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
68
68
  y2: "16",
69
69
  key: "4dfq90"
70
70
  }]
71
- ]), te = M("loader-circle", [["path", {
71
+ ]), ee = N("loader-circle", [["path", {
72
72
  d: "M21 12a9 9 0 1 1-6.219-8.56",
73
73
  key: "13zald"
74
- }]]), ne = M("plus", [["path", {
74
+ }]]), te = N("plus", [["path", {
75
75
  d: "M5 12h14",
76
76
  key: "1ays0h"
77
77
  }], ["path", {
78
78
  d: "M12 5v14",
79
79
  key: "s699le"
80
- }]]), I = M("radio", [
80
+ }]]), R = N("radio", [
81
81
  ["path", {
82
82
  d: "M16.247 7.761a6 6 0 0 1 0 8.478",
83
83
  key: "1fwjs5"
@@ -100,7 +100,7 @@ var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
100
100
  r: "2",
101
101
  key: "1c9p78"
102
102
  }]
103
- ]), re = M("volume-2", [
103
+ ]), ne = N("volume-2", [
104
104
  ["path", {
105
105
  d: "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",
106
106
  key: "uqj9uw"
@@ -113,7 +113,7 @@ var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
113
113
  d: "M19.364 18.364a9 9 0 0 0 0-12.728",
114
114
  key: "ijwkga"
115
115
  }]
116
- ]), ie = M("volume-x", [
116
+ ]), re = N("volume-x", [
117
117
  ["path", {
118
118
  d: "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",
119
119
  key: "uqj9uw"
@@ -132,16 +132,361 @@ var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
132
132
  y2: "15",
133
133
  key: "5ykzw1"
134
134
  }]
135
- ]), ae = M("x", [["path", {
135
+ ]), ie = N("x", [["path", {
136
136
  d: "M18 6 6 18",
137
137
  key: "1bl5f8"
138
138
  }], ["path", {
139
139
  d: "m6 6 12 12",
140
140
  key: "d8bk6v"
141
- }]]);
141
+ }]]), { useT: z } = o("stream-broker", {
142
+ en: {
143
+ panel: {
144
+ requiresDeviceId: "StreamBrokerPanel requires a deviceId",
145
+ title: "Stream Brokers",
146
+ noActiveSlots: "No active profile slots",
147
+ noSlotsAssigned: "No profile slots assigned for this device",
148
+ assigned: "{{count}} assigned",
149
+ sourceNodeTitle: "Cluster node dialing this camera's source: {{node}}"
150
+ },
151
+ audio: {
152
+ label: "Audio",
153
+ thisNode: "this node",
154
+ unknownTitle: "Audio distribution — unknown: the node that serves this camera did not answer.",
155
+ onTitle: "Audio is distributed by {{node}}. Muting it: {{cost}}",
156
+ mutedTitle: "Muted on {{node}}. {{cost}}",
157
+ stateUnknown: "Audio unknown",
158
+ stateOn: "Audio on",
159
+ stateMuted: "Audio muted",
160
+ writeFailed: "Write failed: {{error}}",
161
+ unknownHint: "The node that serves this camera did not answer, so its audio policy is unknown.",
162
+ costWhenOff: "This node distributes no audio for the camera — live subscribers and new recordings are silent. The camera itself keeps capturing sound."
163
+ },
164
+ unassigned: { title: "Other active streams" },
165
+ profile: {
166
+ high: "High",
167
+ mid: "Mid",
168
+ low: "Low"
169
+ },
170
+ stats: {
171
+ idle: "idle",
172
+ loading: "loading",
173
+ fps: "FPS:",
174
+ bitrate: "Bitrate:",
175
+ codec: "Codec:",
176
+ pkts: "Pkts:",
177
+ clients: "Clients:",
178
+ pipeSuffix: "· pipe {{count}})",
179
+ in: "In:",
180
+ idr: "IDR:",
181
+ pipe: "Pipe:",
182
+ packets: "Packets:",
183
+ data: "Data:",
184
+ audio: "Audio:",
185
+ mono: "mono",
186
+ stereo: "stereo",
187
+ decoded: "decoded",
188
+ noDecoder: "no decoder",
189
+ noDemand: "No demand — stream suspended",
190
+ buffer: "Buffer:"
191
+ },
192
+ prebuffer: {
193
+ loading: "Pre-buffer — loading",
194
+ enabled: "Pre-buffer enabled — click to disable",
195
+ disabled: "Pre-buffer disabled — click to enable"
196
+ },
197
+ subscribers: {
198
+ none: "No active subscribers",
199
+ heading: "Subscribers ({{count}})",
200
+ kindAudio: "AUDIO",
201
+ kindEncoded: "ENCODED",
202
+ unknown: "unknown",
203
+ chunks: "{{count}} chunks",
204
+ pkts: "{{count}} pkts",
205
+ stalled: "stalled",
206
+ playing: "playing",
207
+ paused: "paused",
208
+ stateMuted: "{{state}} · muted",
209
+ lastRtp: "last rtp {{age}} ago",
210
+ connected: "connected {{age}} ago",
211
+ sent: "{{bytes}} sent",
212
+ session: "sess {{id}}",
213
+ user: "user {{id}}",
214
+ callbackCount: "{{count}} callback subscriber(s)",
215
+ audioHeading: "Audio subscribers",
216
+ encodedHeading: "Encoded",
217
+ rtspHeading: "RTSP sessions",
218
+ kick: "Force-disconnect this client"
219
+ },
220
+ ffmpeg: {
221
+ inputArgs: "Input args",
222
+ inputArgsHint: "one per line · inserted between globals and -i",
223
+ outputArgs: "Output args",
224
+ outputArgsHint: "one per line · inserted before the final muxer",
225
+ sourceProbed: "Source (probed)",
226
+ fromPublisher: "From the publisher",
227
+ video: "Video",
228
+ audio: "Audio",
229
+ codec: "Codec",
230
+ copyPassthrough: "copy (passthrough)",
231
+ width: "Width",
232
+ height: "Height",
233
+ fps: "FPS",
234
+ bitrateKbps: "Bitrate (kbps)",
235
+ audioPassthroughNote: "Source audio forwarded without re-encode.",
236
+ switchToCustom: "Switch to custom encode",
237
+ switchToPassthrough: "Switch back to passthrough",
238
+ advanced: "Advanced — raw ffmpeg args",
239
+ argsCount: "{{count}} args",
240
+ saving: "Saving…",
241
+ saved: "Saved",
242
+ saveFailed: "Save failed",
243
+ autosaves: "Autosaves",
244
+ chipCodec: "codec",
245
+ chipRes: "res",
246
+ chipFps: "fps",
247
+ chipBitrate: "bitrate",
248
+ chipAudio: "audio",
249
+ chipPassthrough: "passthrough",
250
+ chipAudioBitrate: "a-bitrate",
251
+ chipSampleRate: "a-sr",
252
+ chipChannels: "a-ch",
253
+ noDeviceId: "ffmpeg-params: no deviceId in widget context — this widget only renders inside a device tab.",
254
+ fieldKeyRequired: "ffmpeg-params: widgetConfig.fieldKey is required — fix the contribution builder.",
255
+ addFlag: "Add flag…"
256
+ },
257
+ geometry: {
258
+ title: "Geometry / zoom",
259
+ hint: "composes a single -vf into output args",
260
+ apply: "Apply geometry",
261
+ aspect: "Aspect",
262
+ none: "none",
263
+ aspectMode: "Aspect mode",
264
+ pad: "pad",
265
+ crop: "crop",
266
+ aspectWidth: "Aspect width",
267
+ aspectHeight: "Aspect height",
268
+ cropZoom: "Crop / zoom",
269
+ cropX: "Crop x",
270
+ cropY: "Crop y",
271
+ cropWidth: "Crop width",
272
+ cropHeight: "Crop height",
273
+ rotate: "Rotate",
274
+ empty: "(empty)"
275
+ },
276
+ flags: {
277
+ threadQueueSize1024: "Larger input packet queue (helps with high-bitrate sources)",
278
+ fflagsGenpts: "Generate PTS when the source lacks them",
279
+ re: "Read input at native frame rate (file replay)",
280
+ probesize32: "Minimal probe size — faster start",
281
+ analyzeduration0: "Skip stream analysis — faster start",
282
+ rtspTransportTcp: "Force TCP transport for RTSP source",
283
+ stimeout5000000: "Socket I/O timeout (microseconds, 5s)",
284
+ useWallclockAsTimestamps1: "Rewrite timestamps from wall-clock (fixes non-monotonic cloud sources)",
285
+ fflagsGenptsIgndts: "Generate PTS + ignore DTS",
286
+ flushPackets1: "Flush each packet immediately",
287
+ movflagsFaststart: "Move MOOV atom to front (MP4)",
288
+ bsfVH264Mp4toannexb: "Convert MP4-format H.264 to Annex-B",
289
+ bsfVHevcMp4toannexb: "Convert MP4-format HEVC to Annex-B",
290
+ x264ParamsKeyintMin15: "Force minimum keyframe interval to 15 frames",
291
+ x264ParamsScenecut0: "Disable scene-change keyframes (predictable GOP)",
292
+ x264ParamsNalHrdCbr: "Force CBR HRD signalling (HomeKit-friendly)",
293
+ aqMode3: "Auto-variance adaptive quantisation (mode 3)",
294
+ x265ParamsKeyint30: "Force maximum keyframe interval to 30 frames",
295
+ x265ParamsNoScenecut1: "Disable scene-change keyframes",
296
+ fpsModePassthrough: "Preserve source framerate exactly",
297
+ copyts: "Preserve source timestamps",
298
+ avoidNegativeTsMakeZero: "Shift timestamps so they start at zero",
299
+ afAresampleAsync1: "Resample audio to correct drift / gaps",
300
+ muxdelay0: "No mux buffering delay"
301
+ },
302
+ flagGroups: {
303
+ demuxer: "Demuxer",
304
+ rtsp: "RTSP",
305
+ timestamps: "Timestamps",
306
+ muxer: "Muxer",
307
+ bitstream: "Bitstream",
308
+ x264: "x264",
309
+ x265: "x265",
310
+ global: "Global",
311
+ audio: "Audio"
312
+ }
313
+ },
314
+ it: {
315
+ panel: {
316
+ requiresDeviceId: "StreamBrokerPanel richiede un deviceId",
317
+ title: "Broker degli stream",
318
+ noActiveSlots: "Nessuno slot di profilo attivo",
319
+ noSlotsAssigned: "Nessuno slot di profilo assegnato a questo dispositivo",
320
+ assigned: "{{count}} assegnati",
321
+ sourceNodeTitle: "Nodo del cluster che si collega alla sorgente di questa telecamera: {{node}}"
322
+ },
323
+ audio: {
324
+ label: "Audio",
325
+ thisNode: "questo nodo",
326
+ unknownTitle: "Distribuzione audio — sconosciuta: il nodo che serve questa telecamera non ha risposto.",
327
+ onTitle: "L'audio è distribuito da {{node}}. Silenziandolo: {{cost}}",
328
+ mutedTitle: "Silenziato su {{node}}. {{cost}}",
329
+ stateUnknown: "Audio sconosciuto",
330
+ stateOn: "Audio attivo",
331
+ stateMuted: "Audio silenziato",
332
+ writeFailed: "Scrittura fallita: {{error}}",
333
+ unknownHint: "Il nodo che serve questa telecamera non ha risposto, quindi la sua politica audio è sconosciuta.",
334
+ costWhenOff: "Questo nodo non distribuisce audio per la telecamera: i subscriber live e le nuove registrazioni sono muti. La telecamera continua comunque a captare il suono."
335
+ },
336
+ unassigned: { title: "Altri stream attivi" },
337
+ profile: {
338
+ high: "Alta",
339
+ mid: "Media",
340
+ low: "Bassa"
341
+ },
342
+ stats: {
343
+ idle: "inattivo",
344
+ loading: "caricamento",
345
+ fps: "FPS:",
346
+ bitrate: "Bitrate:",
347
+ codec: "Codec:",
348
+ pkts: "Pacchetti:",
349
+ clients: "Client:",
350
+ pipeSuffix: "· pipe {{count}})",
351
+ in: "Ingresso:",
352
+ idr: "IDR:",
353
+ pipe: "Pipe:",
354
+ packets: "Pacchetti:",
355
+ data: "Dati:",
356
+ audio: "Audio:",
357
+ mono: "mono",
358
+ stereo: "stereo",
359
+ decoded: "decodificato",
360
+ noDecoder: "nessun decoder",
361
+ noDemand: "Nessuna richiesta — stream sospeso",
362
+ buffer: "Buffer:"
363
+ },
364
+ prebuffer: {
365
+ loading: "Pre-buffer — caricamento",
366
+ enabled: "Pre-buffer attivo — clicca per disattivarlo",
367
+ disabled: "Pre-buffer disattivato — clicca per attivarlo"
368
+ },
369
+ subscribers: {
370
+ none: "Nessun subscriber attivo",
371
+ heading: "Subscriber ({{count}})",
372
+ kindAudio: "AUDIO",
373
+ kindEncoded: "CODIFICATI",
374
+ unknown: "sconosciuto",
375
+ chunks: "{{count}} chunk",
376
+ pkts: "{{count}} pacchetti",
377
+ stalled: "bloccato",
378
+ playing: "in riproduzione",
379
+ paused: "in pausa",
380
+ stateMuted: "{{state}} · silenziato",
381
+ lastRtp: "ultimo rtp {{age}} fa",
382
+ connected: "connesso {{age}} fa",
383
+ sent: "{{bytes}} inviati",
384
+ session: "sess {{id}}",
385
+ user: "utente {{id}}",
386
+ callbackCount: "{{count}} subscriber di callback",
387
+ audioHeading: "Subscriber audio",
388
+ encodedHeading: "Codificati",
389
+ rtspHeading: "Sessioni RTSP",
390
+ kick: "Disconnetti forzatamente questo client"
391
+ },
392
+ ffmpeg: {
393
+ inputArgs: "Argomenti di input",
394
+ inputArgsHint: "uno per riga · inseriti tra i globali e -i",
395
+ outputArgs: "Argomenti di output",
396
+ outputArgsHint: "uno per riga · inseriti prima del muxer finale",
397
+ sourceProbed: "Sorgente (rilevata)",
398
+ fromPublisher: "Dal publisher",
399
+ video: "Video",
400
+ audio: "Audio",
401
+ codec: "Codec",
402
+ copyPassthrough: "copy (passthrough)",
403
+ width: "Larghezza",
404
+ height: "Altezza",
405
+ fps: "FPS",
406
+ bitrateKbps: "Bitrate (kbps)",
407
+ audioPassthroughNote: "L'audio della sorgente viene inoltrato senza ricodifica.",
408
+ switchToCustom: "Passa alla codifica personalizzata",
409
+ switchToPassthrough: "Torna al passthrough",
410
+ advanced: "Avanzate — argomenti ffmpeg grezzi",
411
+ argsCount: "{{count}} argomenti",
412
+ saving: "Salvataggio…",
413
+ saved: "Salvato",
414
+ saveFailed: "Salvataggio fallito",
415
+ autosaves: "Salvataggio automatico",
416
+ chipCodec: "codec",
417
+ chipRes: "ris",
418
+ chipFps: "fps",
419
+ chipBitrate: "bitrate",
420
+ chipAudio: "audio",
421
+ chipPassthrough: "passthrough",
422
+ chipAudioBitrate: "a-bitrate",
423
+ chipSampleRate: "a-sr",
424
+ chipChannels: "a-ch",
425
+ noDeviceId: "ffmpeg-params: nessun deviceId nel contesto del widget — questo widget viene mostrato solo dentro la scheda di un dispositivo.",
426
+ fieldKeyRequired: "ffmpeg-params: widgetConfig.fieldKey è obbligatorio — correggi il builder del contributo.",
427
+ addFlag: "Aggiungi flag…"
428
+ },
429
+ geometry: {
430
+ title: "Geometria / zoom",
431
+ hint: "compone un unico -vf negli argomenti di output",
432
+ apply: "Applica geometria",
433
+ aspect: "Proporzioni",
434
+ none: "nessuna",
435
+ aspectMode: "Modalità proporzioni",
436
+ pad: "riempi",
437
+ crop: "ritaglia",
438
+ aspectWidth: "Larghezza proporzioni",
439
+ aspectHeight: "Altezza proporzioni",
440
+ cropZoom: "Ritaglio / zoom",
441
+ cropX: "Ritaglio x",
442
+ cropY: "Ritaglio y",
443
+ cropWidth: "Larghezza ritaglio",
444
+ cropHeight: "Altezza ritaglio",
445
+ rotate: "Ruota",
446
+ empty: "(vuoto)"
447
+ },
448
+ flags: {
449
+ threadQueueSize1024: "Coda dei pacchetti di input più grande (utile con sorgenti ad alto bitrate)",
450
+ fflagsGenpts: "Genera i PTS quando la sorgente ne è priva",
451
+ re: "Legge l'input alla frequenza di fotogrammi nativa (riproduzione da file)",
452
+ probesize32: "Dimensione di probe minima — avvio più rapido",
453
+ analyzeduration0: "Salta l'analisi dello stream — avvio più rapido",
454
+ rtspTransportTcp: "Forza il trasporto TCP per la sorgente RTSP",
455
+ stimeout5000000: "Timeout di I/O del socket (microsecondi, 5 s)",
456
+ useWallclockAsTimestamps1: "Riscrive i timestamp dall'orologio di sistema (corregge le sorgenti cloud non monotone)",
457
+ fflagsGenptsIgndts: "Genera i PTS + ignora i DTS",
458
+ flushPackets1: "Scarica subito ogni pacchetto",
459
+ movflagsFaststart: "Sposta l'atom MOOV all'inizio (MP4)",
460
+ bsfVH264Mp4toannexb: "Converte l'H.264 in formato MP4 in Annex-B",
461
+ bsfVHevcMp4toannexb: "Converte l'HEVC in formato MP4 in Annex-B",
462
+ x264ParamsKeyintMin15: "Forza un intervallo minimo tra keyframe di 15 fotogrammi",
463
+ x264ParamsScenecut0: "Disattiva i keyframe sui cambi di scena (GOP prevedibile)",
464
+ x264ParamsNalHrdCbr: "Forza la segnalazione HRD CBR (compatibile con HomeKit)",
465
+ aqMode3: "Quantizzazione adattiva con varianza automatica (modalità 3)",
466
+ x265ParamsKeyint30: "Forza un intervallo massimo tra keyframe di 30 fotogrammi",
467
+ x265ParamsNoScenecut1: "Disattiva i keyframe sui cambi di scena",
468
+ fpsModePassthrough: "Mantiene esattamente il framerate della sorgente",
469
+ copyts: "Mantiene i timestamp della sorgente",
470
+ avoidNegativeTsMakeZero: "Sposta i timestamp perché partano da zero",
471
+ afAresampleAsync1: "Ricampiona l'audio per correggere derive / vuoti",
472
+ muxdelay0: "Nessun ritardo di buffering nel mux"
473
+ },
474
+ flagGroups: {
475
+ demuxer: "Demuxer",
476
+ rtsp: "RTSP",
477
+ timestamps: "Timestamp",
478
+ muxer: "Muxer",
479
+ bitstream: "Bitstream",
480
+ x264: "x264",
481
+ x265: "x265",
482
+ global: "Globali",
483
+ audio: "Audio"
484
+ }
485
+ }
486
+ });
142
487
  //#endregion
143
488
  //#region src/stream-broker/widgets/GeometryBuilder.tsx
144
- function oe(e) {
489
+ function ae(e) {
145
490
  let t = [];
146
491
  if (e.crop && t.push(`crop=${e.crop.w}:${e.crop.h}:${e.crop.x}:${e.crop.y}`), e.targetAspect && e.width !== void 0 && e.height !== void 0) {
147
492
  let n = e.targetAspect.replace(":", "/");
@@ -149,7 +494,7 @@ function oe(e) {
149
494
  }
150
495
  return e.rotate === 90 ? t.push("transpose=1") : e.rotate === 270 ? t.push("transpose=2") : e.rotate === 180 && t.push("hflip", "vflip"), e.hflip && e.rotate !== 180 && t.push("hflip"), e.vflip && e.rotate !== 180 && t.push("vflip"), t.join(",");
151
496
  }
152
- function se(e, t) {
497
+ function oe(e, t) {
153
498
  let n = [];
154
499
  for (let t = 0; t < e.length; t++) {
155
500
  if (e[t] === "-vf") {
@@ -161,205 +506,205 @@ function se(e, t) {
161
506
  }
162
507
  return t.length > 0 && n.push("-vf", t), n;
163
508
  }
164
- var L = "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium";
165
- function ce({ outputArgs: e, onChange: t }) {
166
- let [n, r] = g(""), [i, a] = g("pad"), [o, s] = g("1920"), [c, l] = g("1080"), [u, d] = g(!1), [f, p] = g("0"), [m, h] = g("0"), [_, v] = g("0"), [S, C] = g("0"), [w, T] = g(0), [E, D] = g(!1), [O, k] = g(!1), A = oe((() => {
509
+ var B = "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium";
510
+ function se({ outputArgs: e, onChange: t }) {
511
+ let { t: n } = z(), [r, i] = _(""), [a, o] = _("pad"), [s, c] = _("1920"), [l, u] = _("1080"), [d, f] = _(!1), [p, m] = _("0"), [h, g] = _("0"), [v, y] = _("0"), [C, w] = _("0"), [T, E] = _(0), [D, O] = _(!1), [k, A] = _(!1), j = ae((() => {
167
512
  let e = {
168
- rotate: w,
169
- hflip: E,
170
- vflip: O
513
+ rotate: T,
514
+ hflip: D,
515
+ vflip: k
171
516
  };
172
- return n !== "" && (e.targetAspect = n, e.mode = i, e.width = Number(o), e.height = Number(c)), u && (e.crop = {
173
- x: Number(f),
174
- y: Number(m),
175
- w: Number(_),
176
- h: Number(S)
517
+ return r !== "" && (e.targetAspect = r, e.mode = a, e.width = Number(s), e.height = Number(l)), d && (e.crop = {
518
+ x: Number(p),
519
+ y: Number(h),
520
+ w: Number(v),
521
+ h: Number(C)
177
522
  }), e;
178
523
  })());
179
- return /* @__PURE__ */ b("div", {
524
+ return /* @__PURE__ */ x("div", {
180
525
  className: "space-y-2 rounded border border-border/50 bg-surface-2/30 px-3 py-2",
181
526
  children: [
182
- /* @__PURE__ */ b("div", {
527
+ /* @__PURE__ */ x("div", {
183
528
  className: "flex items-center justify-between",
184
- children: [/* @__PURE__ */ b("span", {
185
- className: L,
186
- children: ["Geometry / zoom", /* @__PURE__ */ y("span", {
529
+ children: [/* @__PURE__ */ x("span", {
530
+ className: B,
531
+ children: [n("geometry.title"), /* @__PURE__ */ b("span", {
187
532
  className: "ml-2 text-[10px] normal-case text-foreground-subtle italic",
188
- children: "composes a single -vf into output args"
533
+ children: n("geometry.hint")
189
534
  })]
190
- }), /* @__PURE__ */ y("button", {
535
+ }), /* @__PURE__ */ b("button", {
191
536
  type: "button",
192
- onClick: () => t(se(e, A)),
537
+ onClick: () => t(oe(e, j)),
193
538
  className: "rounded-md border border-border bg-surface-hover px-2 py-0.5 text-[10px] font-medium text-foreground hover:bg-surface-hover/70 transition-colors",
194
- children: "Apply geometry"
539
+ children: n("geometry.apply")
195
540
  })]
196
541
  }),
197
- /* @__PURE__ */ b("div", {
542
+ /* @__PURE__ */ x("div", {
198
543
  className: "flex flex-wrap items-center gap-2",
199
544
  children: [
200
- /* @__PURE__ */ y("label", {
201
- className: L,
545
+ /* @__PURE__ */ b("label", {
546
+ className: B,
202
547
  htmlFor: "geom-aspect",
203
- children: "Aspect"
548
+ children: n("geometry.aspect")
204
549
  }),
205
- /* @__PURE__ */ b("select", {
550
+ /* @__PURE__ */ x("select", {
206
551
  id: "geom-aspect",
207
- value: n,
208
- onChange: (e) => r(e.target.value),
552
+ value: r,
553
+ onChange: (e) => i(e.target.value),
209
554
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed appearance-none pr-6 min-w-[90px]",
210
555
  children: [
211
- /* @__PURE__ */ y("option", {
556
+ /* @__PURE__ */ b("option", {
212
557
  value: "",
213
- children: "none"
558
+ children: n("geometry.none")
214
559
  }),
215
- /* @__PURE__ */ y("option", {
560
+ /* @__PURE__ */ b("option", {
216
561
  value: "16:9",
217
562
  children: "16:9"
218
563
  }),
219
- /* @__PURE__ */ y("option", {
564
+ /* @__PURE__ */ b("option", {
220
565
  value: "4:3",
221
566
  children: "4:3"
222
567
  }),
223
- /* @__PURE__ */ y("option", {
568
+ /* @__PURE__ */ b("option", {
224
569
  value: "1:1",
225
570
  children: "1:1"
226
571
  })
227
572
  ]
228
573
  }),
229
- n !== "" && /* @__PURE__ */ b(x, { children: [
230
- /* @__PURE__ */ b("select", {
231
- "aria-label": "Aspect mode",
232
- value: i,
233
- onChange: (e) => a(e.target.value),
574
+ r !== "" && /* @__PURE__ */ x(S, { children: [
575
+ /* @__PURE__ */ x("select", {
576
+ "aria-label": n("geometry.aspectMode"),
577
+ value: a,
578
+ onChange: (e) => o(e.target.value),
234
579
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed appearance-none pr-6 min-w-[80px]",
235
- children: [/* @__PURE__ */ y("option", {
580
+ children: [/* @__PURE__ */ b("option", {
236
581
  value: "pad",
237
- children: "pad"
238
- }), /* @__PURE__ */ y("option", {
582
+ children: n("geometry.pad")
583
+ }), /* @__PURE__ */ b("option", {
239
584
  value: "crop",
240
- children: "crop"
585
+ children: n("geometry.crop")
241
586
  })]
242
587
  }),
243
- /* @__PURE__ */ y("input", {
588
+ /* @__PURE__ */ b("input", {
244
589
  type: "number",
245
- "aria-label": "Aspect width",
246
- value: o,
247
- onChange: (e) => s(e.target.value),
590
+ "aria-label": n("geometry.aspectWidth"),
591
+ value: s,
592
+ onChange: (e) => c(e.target.value),
248
593
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-20 text-right"
249
594
  }),
250
- /* @__PURE__ */ y("span", {
595
+ /* @__PURE__ */ b("span", {
251
596
  className: "text-[11px] text-foreground-subtle",
252
597
  children: "×"
253
598
  }),
254
- /* @__PURE__ */ y("input", {
599
+ /* @__PURE__ */ b("input", {
255
600
  type: "number",
256
- "aria-label": "Aspect height",
257
- value: c,
258
- onChange: (e) => l(e.target.value),
601
+ "aria-label": n("geometry.aspectHeight"),
602
+ value: l,
603
+ onChange: (e) => u(e.target.value),
259
604
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-20 text-right"
260
605
  })
261
606
  ] })
262
607
  ]
263
608
  }),
264
- /* @__PURE__ */ b("div", {
609
+ /* @__PURE__ */ x("div", {
265
610
  className: "flex flex-wrap items-center gap-2",
266
- children: [/* @__PURE__ */ b("label", {
611
+ children: [/* @__PURE__ */ x("label", {
267
612
  className: "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium inline-flex items-center gap-1",
268
- children: [/* @__PURE__ */ y("input", {
613
+ children: [/* @__PURE__ */ b("input", {
269
614
  type: "checkbox",
270
- checked: u,
271
- onChange: (e) => d(e.target.checked)
272
- }), "Crop / zoom"]
273
- }), u && /* @__PURE__ */ b(x, { children: [
274
- /* @__PURE__ */ y("input", {
615
+ checked: d,
616
+ onChange: (e) => f(e.target.checked)
617
+ }), n("geometry.cropZoom")]
618
+ }), d && /* @__PURE__ */ x(S, { children: [
619
+ /* @__PURE__ */ b("input", {
275
620
  type: "number",
276
- "aria-label": "Crop x",
277
- value: f,
278
- onChange: (e) => p(e.target.value),
621
+ "aria-label": n("geometry.cropX"),
622
+ value: p,
623
+ onChange: (e) => m(e.target.value),
279
624
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-16 text-right",
280
625
  placeholder: "x"
281
626
  }),
282
- /* @__PURE__ */ y("input", {
627
+ /* @__PURE__ */ b("input", {
283
628
  type: "number",
284
- "aria-label": "Crop y",
285
- value: m,
286
- onChange: (e) => h(e.target.value),
629
+ "aria-label": n("geometry.cropY"),
630
+ value: h,
631
+ onChange: (e) => g(e.target.value),
287
632
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-16 text-right",
288
633
  placeholder: "y"
289
634
  }),
290
- /* @__PURE__ */ y("input", {
635
+ /* @__PURE__ */ b("input", {
291
636
  type: "number",
292
- "aria-label": "Crop width",
293
- value: _,
294
- onChange: (e) => v(e.target.value),
637
+ "aria-label": n("geometry.cropWidth"),
638
+ value: v,
639
+ onChange: (e) => y(e.target.value),
295
640
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-20 text-right",
296
641
  placeholder: "w"
297
642
  }),
298
- /* @__PURE__ */ y("input", {
643
+ /* @__PURE__ */ b("input", {
299
644
  type: "number",
300
- "aria-label": "Crop height",
301
- value: S,
302
- onChange: (e) => C(e.target.value),
645
+ "aria-label": n("geometry.cropHeight"),
646
+ value: C,
647
+ onChange: (e) => w(e.target.value),
303
648
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed w-20 text-right",
304
649
  placeholder: "h"
305
650
  })
306
651
  ] })]
307
652
  }),
308
- /* @__PURE__ */ b("div", {
653
+ /* @__PURE__ */ x("div", {
309
654
  className: "flex flex-wrap items-center gap-2",
310
655
  children: [
311
- /* @__PURE__ */ y("label", {
312
- className: L,
656
+ /* @__PURE__ */ b("label", {
657
+ className: B,
313
658
  htmlFor: "geom-rotate",
314
- children: "Rotate"
659
+ children: n("geometry.rotate")
315
660
  }),
316
- /* @__PURE__ */ b("select", {
661
+ /* @__PURE__ */ x("select", {
317
662
  id: "geom-rotate",
318
- value: String(w),
319
- onChange: (e) => T(Number(e.target.value)),
663
+ value: String(T),
664
+ onChange: (e) => E(Number(e.target.value)),
320
665
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed appearance-none pr-6 min-w-[80px]",
321
666
  children: [
322
- /* @__PURE__ */ y("option", {
667
+ /* @__PURE__ */ b("option", {
323
668
  value: "0",
324
669
  children: "0°"
325
670
  }),
326
- /* @__PURE__ */ y("option", {
671
+ /* @__PURE__ */ b("option", {
327
672
  value: "90",
328
673
  children: "90°"
329
674
  }),
330
- /* @__PURE__ */ y("option", {
675
+ /* @__PURE__ */ b("option", {
331
676
  value: "180",
332
677
  children: "180°"
333
678
  }),
334
- /* @__PURE__ */ y("option", {
679
+ /* @__PURE__ */ b("option", {
335
680
  value: "270",
336
681
  children: "270°"
337
682
  })
338
683
  ]
339
684
  }),
340
- /* @__PURE__ */ b("label", {
685
+ /* @__PURE__ */ x("label", {
341
686
  className: "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium inline-flex items-center gap-1",
342
- children: [/* @__PURE__ */ y("input", {
687
+ children: [/* @__PURE__ */ b("input", {
343
688
  type: "checkbox",
344
- checked: E,
345
- onChange: (e) => D(e.target.checked)
689
+ checked: D,
690
+ onChange: (e) => O(e.target.checked)
346
691
  }), "hflip"]
347
692
  }),
348
- /* @__PURE__ */ b("label", {
693
+ /* @__PURE__ */ x("label", {
349
694
  className: "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium inline-flex items-center gap-1",
350
- children: [/* @__PURE__ */ y("input", {
695
+ children: [/* @__PURE__ */ b("input", {
351
696
  type: "checkbox",
352
- checked: O,
353
- onChange: (e) => k(e.target.checked)
697
+ checked: k,
698
+ onChange: (e) => A(e.target.checked)
354
699
  }), "vflip"]
355
700
  })
356
701
  ]
357
702
  }),
358
- /* @__PURE__ */ b("div", {
703
+ /* @__PURE__ */ x("div", {
359
704
  className: "font-mono text-[10px] text-foreground-subtle break-all",
360
- children: ["-vf ", A.length > 0 ? A : /* @__PURE__ */ y("span", {
705
+ children: ["-vf ", j.length > 0 ? j : /* @__PURE__ */ b("span", {
361
706
  className: "italic",
362
- children: "(empty)"
707
+ children: n("geometry.empty")
363
708
  })]
364
709
  })
365
710
  ]
@@ -367,210 +712,210 @@ function ce({ outputArgs: e, onChange: t }) {
367
712
  }
368
713
  //#endregion
369
714
  //#region src/stream-broker/widgets/FfmpegParamsField.tsx
370
- var le = [
715
+ var ce = [
371
716
  {
372
- group: "Demuxer",
717
+ group: "flagGroups.demuxer",
373
718
  label: "-thread_queue_size 1024",
374
719
  args: ["-thread_queue_size", "1024"],
375
- description: "Larger input packet queue (helps with high-bitrate sources)"
720
+ descriptionKey: "flags.threadQueueSize1024"
376
721
  },
377
722
  {
378
- group: "Demuxer",
723
+ group: "flagGroups.demuxer",
379
724
  label: "-fflags +genpts",
380
725
  args: ["-fflags", "+genpts"],
381
- description: "Generate PTS when the source lacks them"
726
+ descriptionKey: "flags.fflagsGenpts"
382
727
  },
383
728
  {
384
- group: "Demuxer",
729
+ group: "flagGroups.demuxer",
385
730
  label: "-re",
386
731
  args: ["-re"],
387
- description: "Read input at native frame rate (file replay)"
732
+ descriptionKey: "flags.re"
388
733
  },
389
734
  {
390
- group: "Demuxer",
735
+ group: "flagGroups.demuxer",
391
736
  label: "-probesize 32",
392
737
  args: ["-probesize", "32"],
393
- description: "Minimal probe size — faster start"
738
+ descriptionKey: "flags.probesize32"
394
739
  },
395
740
  {
396
- group: "Demuxer",
741
+ group: "flagGroups.demuxer",
397
742
  label: "-analyzeduration 0",
398
743
  args: ["-analyzeduration", "0"],
399
- description: "Skip stream analysis — faster start"
744
+ descriptionKey: "flags.analyzeduration0"
400
745
  },
401
746
  {
402
- group: "RTSP",
747
+ group: "flagGroups.rtsp",
403
748
  label: "-rtsp_transport tcp",
404
749
  args: ["-rtsp_transport", "tcp"],
405
- description: "Force TCP transport for RTSP source"
750
+ descriptionKey: "flags.rtspTransportTcp"
406
751
  },
407
752
  {
408
- group: "RTSP",
753
+ group: "flagGroups.rtsp",
409
754
  label: "-stimeout 5000000",
410
755
  args: ["-stimeout", "5000000"],
411
- description: "Socket I/O timeout (microseconds, 5s)"
756
+ descriptionKey: "flags.stimeout5000000"
412
757
  },
413
758
  {
414
- group: "Timestamps",
759
+ group: "flagGroups.timestamps",
415
760
  label: "-use_wallclock_as_timestamps 1",
416
761
  args: ["-use_wallclock_as_timestamps", "1"],
417
- description: "Rewrite timestamps from wall-clock (fixes non-monotonic cloud sources)"
762
+ descriptionKey: "flags.useWallclockAsTimestamps1"
418
763
  },
419
764
  {
420
- group: "Timestamps",
765
+ group: "flagGroups.timestamps",
421
766
  label: "-fflags +genpts+igndts",
422
767
  args: ["-fflags", "+genpts+igndts"],
423
- description: "Generate PTS + ignore DTS"
768
+ descriptionKey: "flags.fflagsGenptsIgndts"
424
769
  }
425
- ], ue = [
770
+ ], le = [
426
771
  {
427
- group: "Muxer",
772
+ group: "flagGroups.muxer",
428
773
  label: "-flush_packets 1",
429
774
  args: ["-flush_packets", "1"],
430
- description: "Flush each packet immediately"
775
+ descriptionKey: "flags.flushPackets1"
431
776
  },
432
777
  {
433
- group: "Muxer",
778
+ group: "flagGroups.muxer",
434
779
  label: "-movflags +faststart",
435
780
  args: ["-movflags", "+faststart"],
436
- description: "Move MOOV atom to front (MP4)"
781
+ descriptionKey: "flags.movflagsFaststart"
437
782
  },
438
783
  {
439
- group: "Bitstream",
784
+ group: "flagGroups.bitstream",
440
785
  label: "-bsf:v h264_mp4toannexb",
441
786
  args: ["-bsf:v", "h264_mp4toannexb"],
442
- description: "Convert MP4-format H.264 to Annex-B"
787
+ descriptionKey: "flags.bsfVH264Mp4toannexb"
443
788
  },
444
789
  {
445
- group: "Bitstream",
790
+ group: "flagGroups.bitstream",
446
791
  label: "-bsf:v hevc_mp4toannexb",
447
792
  args: ["-bsf:v", "hevc_mp4toannexb"],
448
- description: "Convert MP4-format HEVC to Annex-B"
793
+ descriptionKey: "flags.bsfVHevcMp4toannexb"
449
794
  },
450
795
  {
451
- group: "x264",
796
+ group: "flagGroups.x264",
452
797
  label: "-x264-params keyint_min=15",
453
798
  args: ["-x264-params", "keyint_min=15"],
454
- description: "Force minimum keyframe interval to 15 frames"
799
+ descriptionKey: "flags.x264ParamsKeyintMin15"
455
800
  },
456
801
  {
457
- group: "x264",
802
+ group: "flagGroups.x264",
458
803
  label: "-x264-params scenecut=0",
459
804
  args: ["-x264-params", "scenecut=0"],
460
- description: "Disable scene-change keyframes (predictable GOP)"
805
+ descriptionKey: "flags.x264ParamsScenecut0"
461
806
  },
462
807
  {
463
- group: "x264",
808
+ group: "flagGroups.x264",
464
809
  label: "-x264-params nal-hrd=cbr",
465
810
  args: ["-x264-params", "nal-hrd=cbr"],
466
- description: "Force CBR HRD signalling (HomeKit-friendly)"
811
+ descriptionKey: "flags.x264ParamsNalHrdCbr"
467
812
  },
468
813
  {
469
- group: "x264",
814
+ group: "flagGroups.x264",
470
815
  label: "-aq-mode 3",
471
816
  args: ["-aq-mode", "3"],
472
- description: "Auto-variance adaptive quantisation (mode 3)"
817
+ descriptionKey: "flags.aqMode3"
473
818
  },
474
819
  {
475
- group: "x265",
820
+ group: "flagGroups.x265",
476
821
  label: "-x265-params keyint=30",
477
822
  args: ["-x265-params", "keyint=30"],
478
- description: "Force maximum keyframe interval to 30 frames"
823
+ descriptionKey: "flags.x265ParamsKeyint30"
479
824
  },
480
825
  {
481
- group: "x265",
826
+ group: "flagGroups.x265",
482
827
  label: "-x265-params no-scenecut=1",
483
828
  args: ["-x265-params", "no-scenecut=1"],
484
- description: "Disable scene-change keyframes"
829
+ descriptionKey: "flags.x265ParamsNoScenecut1"
485
830
  },
486
831
  {
487
- group: "Global",
832
+ group: "flagGroups.global",
488
833
  label: "-fps_mode passthrough",
489
834
  args: ["-fps_mode", "passthrough"],
490
- description: "Preserve source framerate exactly"
835
+ descriptionKey: "flags.fpsModePassthrough"
491
836
  },
492
837
  {
493
- group: "Global",
838
+ group: "flagGroups.global",
494
839
  label: "-copyts",
495
840
  args: ["-copyts"],
496
- description: "Preserve source timestamps"
841
+ descriptionKey: "flags.copyts"
497
842
  },
498
843
  {
499
- group: "Timestamps",
844
+ group: "flagGroups.timestamps",
500
845
  label: "-avoid_negative_ts make_zero",
501
846
  args: ["-avoid_negative_ts", "make_zero"],
502
- description: "Shift timestamps so they start at zero"
847
+ descriptionKey: "flags.avoidNegativeTsMakeZero"
503
848
  },
504
849
  {
505
- group: "Audio",
850
+ group: "flagGroups.audio",
506
851
  label: "-af aresample=async=1",
507
852
  args: ["-af", "aresample=async=1"],
508
- description: "Resample audio to correct drift / gaps"
853
+ descriptionKey: "flags.afAresampleAsync1"
509
854
  },
510
855
  {
511
- group: "Muxer",
856
+ group: "flagGroups.muxer",
512
857
  label: "-muxdelay 0",
513
858
  args: ["-muxdelay", "0"],
514
- description: "No mux buffering delay"
859
+ descriptionKey: "flags.muxdelay0"
515
860
  }
516
- ], de = {
861
+ ], ue = {
517
862
  video: { codec: "copy" },
518
863
  audio: "passthrough"
519
- }, R = "w-full rounded border border-border bg-surface-2 px-2 py-1.5 text-[11px] font-mono text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 read-only:opacity-60 min-h-[60px] resize-y", z = "flex items-center justify-between gap-3 py-1.5", B = "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium", V = "rounded-lg border border-border bg-surface overflow-hidden", H = "border-b border-border px-3 py-1.5 flex items-center justify-between bg-surface-hover/30", U = "text-[11px] font-semibold text-foreground uppercase tracking-wider";
520
- function fe({ config: e, value: t, onSave: n, saveStatus: r }) {
521
- let [i, a] = g(!1), o = e.argsOnly === !0, s = t ?? de, [c, l] = g(() => (s.inputArgs ?? []).join("\n")), [u, d] = g(() => (s.outputArgs ?? []).join("\n")), f = p(s);
522
- f.current !== s && (f.current = s, l((s.inputArgs ?? []).join("\n")), d((s.outputArgs ?? []).join("\n")));
523
- let m = (e) => {
524
- n(e(s));
525
- }, h = (e) => m((t) => ({
864
+ }, V = "w-full rounded border border-border bg-surface-2 px-2 py-1.5 text-[11px] font-mono text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 read-only:opacity-60 min-h-[60px] resize-y", H = "flex items-center justify-between gap-3 py-1.5", U = "text-[11px] uppercase tracking-wider text-foreground-subtle font-medium", W = "rounded-lg border border-border bg-surface overflow-hidden", G = "border-b border-border px-3 py-1.5 flex items-center justify-between bg-surface-hover/30", K = "text-[11px] font-semibold text-foreground uppercase tracking-wider";
865
+ function de({ config: e, value: t, onSave: n, saveStatus: r }) {
866
+ let { t: i } = z(), [a, o] = _(!1), s = e.argsOnly === !0, c = t ?? ue, [l, u] = _(() => (c.inputArgs ?? []).join("\n")), [d, f] = _(() => (c.outputArgs ?? []).join("\n")), p = m(c);
867
+ p.current !== c && (p.current = c, u((c.inputArgs ?? []).join("\n")), f((c.outputArgs ?? []).join("\n")));
868
+ let h = (e) => {
869
+ n(e(c));
870
+ }, g = (e) => h((t) => ({
526
871
  ...t,
527
872
  video: {
528
873
  ...t.video,
529
874
  codec: e
530
875
  }
531
- })), _ = (e) => {
532
- !Number.isFinite(e) || e <= 0 || m((t) => ({
876
+ })), v = (e) => {
877
+ !Number.isFinite(e) || e <= 0 || h((t) => ({
533
878
  ...t,
534
879
  video: {
535
880
  ...t.video,
536
881
  width: e
537
882
  }
538
883
  }));
539
- }, v = (e) => {
540
- !Number.isFinite(e) || e <= 0 || m((t) => ({
884
+ }, y = (e) => {
885
+ !Number.isFinite(e) || e <= 0 || h((t) => ({
541
886
  ...t,
542
887
  video: {
543
888
  ...t.video,
544
889
  height: e
545
890
  }
546
891
  }));
547
- }, S = (e) => {
548
- !Number.isFinite(e) || e <= 0 || m((t) => ({
892
+ }, C = (e) => {
893
+ !Number.isFinite(e) || e <= 0 || h((t) => ({
549
894
  ...t,
550
895
  video: {
551
896
  ...t.video,
552
897
  fps: e
553
898
  }
554
899
  }));
555
- }, C = (e) => {
556
- !Number.isFinite(e) || e <= 0 || m((t) => ({
900
+ }, w = (e) => {
901
+ !Number.isFinite(e) || e <= 0 || h((t) => ({
557
902
  ...t,
558
903
  video: {
559
904
  ...t.video,
560
905
  bitrateKbps: e
561
906
  }
562
907
  }));
563
- }, w = () => m((e) => ({
908
+ }, T = () => h((e) => ({
564
909
  ...e,
565
910
  audio: "passthrough"
566
- })), T = (e) => m((t) => ({
911
+ })), E = (e) => h((t) => ({
567
912
  ...t,
568
913
  audio: typeof t.audio == "object" ? {
569
914
  ...t.audio,
570
915
  codec: e
571
916
  } : { codec: e }
572
- })), E = (e) => {
573
- !Number.isFinite(e) || e <= 0 || m((t) => ({
917
+ })), D = (e) => {
918
+ !Number.isFinite(e) || e <= 0 || h((t) => ({
574
919
  ...t,
575
920
  audio: typeof t.audio == "object" ? {
576
921
  ...t.audio,
@@ -580,275 +925,275 @@ function fe({ config: e, value: t, onSave: n, saveStatus: r }) {
580
925
  bitrateKbps: e
581
926
  }
582
927
  }));
583
- }, D = (e) => m((t) => ({
928
+ }, O = (e) => h((t) => ({
584
929
  ...t,
585
930
  inputArgs: e.split("\n").map((e) => e.trim()).filter((e) => e.length > 0)
586
- })), O = (e) => m((t) => ({
931
+ })), k = (e) => h((t) => ({
587
932
  ...t,
588
933
  outputArgs: e.split("\n").map((e) => e.trim()).filter((e) => e.length > 0)
589
- })), k = (e, t) => {
934
+ })), A = (e, t) => {
590
935
  let n = t.args.join(" ");
591
936
  if (e === "input") {
592
- let e = c.length === 0 ? n : `${c}\n${n}`;
593
- l(e), D(e);
937
+ let e = l.length === 0 ? n : `${l}\n${n}`;
938
+ u(e), O(e);
594
939
  } else {
595
- let e = u.length === 0 ? n : `${u}\n${n}`;
596
- d(e), O(e);
940
+ let e = d.length === 0 ? n : `${d}\n${n}`;
941
+ f(e), k(e);
597
942
  }
598
- }, A = /* @__PURE__ */ b("div", {
943
+ }, j = /* @__PURE__ */ x("div", {
599
944
  className: "space-y-1.5",
600
- children: [/* @__PURE__ */ b("div", {
945
+ children: [/* @__PURE__ */ x("div", {
601
946
  className: "flex items-center justify-between",
602
- children: [/* @__PURE__ */ b("label", {
947
+ children: [/* @__PURE__ */ x("label", {
603
948
  htmlFor: `${e.fieldKey}-input-args`,
604
- className: B,
605
- children: ["Input args", /* @__PURE__ */ y("span", {
949
+ className: U,
950
+ children: [i("ffmpeg.inputArgs"), /* @__PURE__ */ b("span", {
606
951
  className: "ml-2 text-[10px] normal-case text-foreground-subtle italic",
607
- children: "one per line · inserted between globals and -i"
952
+ children: i("ffmpeg.inputArgsHint")
608
953
  })]
609
- }), /* @__PURE__ */ y(W, {
954
+ }), /* @__PURE__ */ b(q, {
610
955
  id: `${e.fieldKey}-input-picker`,
611
956
  disabled: !1,
612
- catalogue: le,
613
- onPick: (e) => k("input", e)
957
+ catalogue: ce,
958
+ onPick: (e) => A("input", e)
614
959
  })]
615
- }), /* @__PURE__ */ y("textarea", {
960
+ }), /* @__PURE__ */ b("textarea", {
616
961
  id: `${e.fieldKey}-input-args`,
617
- value: c,
618
- onChange: (e) => l(e.target.value),
619
- onBlur: (e) => D(e.target.value),
962
+ value: l,
963
+ onChange: (e) => u(e.target.value),
964
+ onBlur: (e) => O(e.target.value),
620
965
  placeholder: "-thread_queue_size 1024",
621
- className: R
966
+ className: V
622
967
  })]
623
- }), j = /* @__PURE__ */ b("div", {
968
+ }), M = /* @__PURE__ */ x("div", {
624
969
  className: "space-y-1.5",
625
- children: [/* @__PURE__ */ b("div", {
970
+ children: [/* @__PURE__ */ x("div", {
626
971
  className: "flex items-center justify-between",
627
- children: [/* @__PURE__ */ b("label", {
972
+ children: [/* @__PURE__ */ x("label", {
628
973
  htmlFor: `${e.fieldKey}-output-args`,
629
- className: B,
630
- children: ["Output args", /* @__PURE__ */ y("span", {
974
+ className: U,
975
+ children: [i("ffmpeg.outputArgs"), /* @__PURE__ */ b("span", {
631
976
  className: "ml-2 text-[10px] normal-case text-foreground-subtle italic",
632
- children: "one per line · inserted before the final muxer"
977
+ children: i("ffmpeg.outputArgsHint")
633
978
  })]
634
- }), /* @__PURE__ */ y(W, {
979
+ }), /* @__PURE__ */ b(q, {
635
980
  id: `${e.fieldKey}-output-picker`,
636
981
  disabled: !1,
637
- catalogue: ue,
638
- onPick: (e) => k("output", e)
982
+ catalogue: le,
983
+ onPick: (e) => A("output", e)
639
984
  })]
640
- }), /* @__PURE__ */ y("textarea", {
985
+ }), /* @__PURE__ */ b("textarea", {
641
986
  id: `${e.fieldKey}-output-args`,
642
- value: u,
643
- onChange: (e) => d(e.target.value),
644
- onBlur: (e) => O(e.target.value),
987
+ value: d,
988
+ onChange: (e) => f(e.target.value),
989
+ onBlur: (e) => k(e.target.value),
645
990
  placeholder: "-bsf:v h264_mp4toannexb",
646
- className: R
991
+ className: V
647
992
  })]
648
993
  });
649
- return /* @__PURE__ */ b("div", {
994
+ return /* @__PURE__ */ x("div", {
650
995
  className: "space-y-3",
651
996
  children: [
652
- r !== void 0 && /* @__PURE__ */ y("div", {
997
+ r !== void 0 && /* @__PURE__ */ b("div", {
653
998
  className: "flex items-center justify-end",
654
- children: /* @__PURE__ */ y(pe, { status: r })
999
+ children: /* @__PURE__ */ b(fe, { status: r })
655
1000
  }),
656
- e.sourceParams !== void 0 && /* @__PURE__ */ b("div", {
657
- className: V,
658
- children: [/* @__PURE__ */ b("div", {
659
- className: H,
660
- children: [/* @__PURE__ */ y("h3", {
661
- className: U,
662
- children: "Source (probed)"
663
- }), /* @__PURE__ */ y("span", {
1001
+ e.sourceParams !== void 0 && /* @__PURE__ */ x("div", {
1002
+ className: W,
1003
+ children: [/* @__PURE__ */ x("div", {
1004
+ className: G,
1005
+ children: [/* @__PURE__ */ b("h3", {
1006
+ className: K,
1007
+ children: i("ffmpeg.sourceProbed")
1008
+ }), /* @__PURE__ */ b("span", {
664
1009
  className: "text-[10px] text-foreground-subtle italic",
665
- children: "From the publisher"
1010
+ children: i("ffmpeg.fromPublisher")
666
1011
  })]
667
- }), /* @__PURE__ */ y("div", {
1012
+ }), /* @__PURE__ */ b("div", {
668
1013
  className: "px-3 py-2 flex flex-wrap gap-1.5",
669
- children: /* @__PURE__ */ y(me, { profile: e.sourceParams })
1014
+ children: /* @__PURE__ */ b(pe, { profile: e.sourceParams })
670
1015
  })]
671
1016
  }),
672
- !o && /* @__PURE__ */ y("div", {
1017
+ !s && /* @__PURE__ */ b("div", {
673
1018
  className: "@container",
674
- children: /* @__PURE__ */ b("div", {
1019
+ children: /* @__PURE__ */ x("div", {
675
1020
  className: "grid grid-cols-1 @[480px]:grid-cols-2 gap-3",
676
- children: [/* @__PURE__ */ b("div", {
677
- className: V,
678
- children: [/* @__PURE__ */ y("div", {
679
- className: H,
680
- children: /* @__PURE__ */ y("h3", {
681
- className: U,
682
- children: "Video"
1021
+ children: [/* @__PURE__ */ x("div", {
1022
+ className: W,
1023
+ children: [/* @__PURE__ */ b("div", {
1024
+ className: G,
1025
+ children: /* @__PURE__ */ b("h3", {
1026
+ className: K,
1027
+ children: i("ffmpeg.video")
683
1028
  })
684
- }), /* @__PURE__ */ b("div", {
1029
+ }), /* @__PURE__ */ x("div", {
685
1030
  className: "px-3 py-2 divide-y divide-border/30",
686
- children: [/* @__PURE__ */ b("div", {
687
- className: z,
688
- children: [/* @__PURE__ */ y("label", {
1031
+ children: [/* @__PURE__ */ x("div", {
1032
+ className: H,
1033
+ children: [/* @__PURE__ */ b("label", {
689
1034
  htmlFor: `${e.fieldKey}-video-codec`,
690
- className: B,
691
- children: "Codec"
692
- }), /* @__PURE__ */ b("select", {
1035
+ className: U,
1036
+ children: i("ffmpeg.codec")
1037
+ }), /* @__PURE__ */ x("select", {
693
1038
  id: `${e.fieldKey}-video-codec`,
694
- value: s.video.codec,
695
- onChange: (e) => h(e.target.value),
1039
+ value: c.video.codec,
1040
+ onChange: (e) => g(e.target.value),
696
1041
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed appearance-none pr-6 min-w-[120px]",
697
1042
  children: [
698
- /* @__PURE__ */ y("option", {
1043
+ /* @__PURE__ */ b("option", {
699
1044
  value: "h264",
700
1045
  children: "h264"
701
1046
  }),
702
- /* @__PURE__ */ y("option", {
1047
+ /* @__PURE__ */ b("option", {
703
1048
  value: "h265",
704
1049
  children: "h265"
705
1050
  }),
706
- /* @__PURE__ */ y("option", {
1051
+ /* @__PURE__ */ b("option", {
707
1052
  value: "copy",
708
- children: "copy (passthrough)"
1053
+ children: i("ffmpeg.copyPassthrough")
709
1054
  })
710
1055
  ]
711
1056
  })]
712
- }), s.video.codec !== "copy" && /* @__PURE__ */ b(x, { children: [
713
- /* @__PURE__ */ b("div", {
714
- className: z,
715
- children: [/* @__PURE__ */ y("label", {
1057
+ }), c.video.codec !== "copy" && /* @__PURE__ */ x(S, { children: [
1058
+ /* @__PURE__ */ x("div", {
1059
+ className: H,
1060
+ children: [/* @__PURE__ */ b("label", {
716
1061
  htmlFor: `${e.fieldKey}-video-width`,
717
- className: B,
718
- children: "Width"
719
- }), /* @__PURE__ */ y("input", {
1062
+ className: U,
1063
+ children: i("ffmpeg.width")
1064
+ }), /* @__PURE__ */ b("input", {
720
1065
  id: `${e.fieldKey}-video-width`,
721
1066
  type: "number",
722
- "aria-label": "Width",
723
- value: s.video.width ?? "",
724
- onChange: (e) => _(Number(e.target.value)),
1067
+ "aria-label": i("ffmpeg.width"),
1068
+ value: c.video.width ?? "",
1069
+ onChange: (e) => v(Number(e.target.value)),
725
1070
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed w-24 text-right"
726
1071
  })]
727
1072
  }),
728
- /* @__PURE__ */ b("div", {
729
- className: z,
730
- children: [/* @__PURE__ */ y("label", {
1073
+ /* @__PURE__ */ x("div", {
1074
+ className: H,
1075
+ children: [/* @__PURE__ */ b("label", {
731
1076
  htmlFor: `${e.fieldKey}-video-height`,
732
- className: B,
733
- children: "Height"
734
- }), /* @__PURE__ */ y("input", {
1077
+ className: U,
1078
+ children: i("ffmpeg.height")
1079
+ }), /* @__PURE__ */ b("input", {
735
1080
  id: `${e.fieldKey}-video-height`,
736
1081
  type: "number",
737
- value: s.video.height ?? "",
738
- onChange: (e) => v(Number(e.target.value)),
1082
+ value: c.video.height ?? "",
1083
+ onChange: (e) => y(Number(e.target.value)),
739
1084
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed w-24 text-right"
740
1085
  })]
741
1086
  }),
742
- /* @__PURE__ */ b("div", {
743
- className: z,
744
- children: [/* @__PURE__ */ y("label", {
1087
+ /* @__PURE__ */ x("div", {
1088
+ className: H,
1089
+ children: [/* @__PURE__ */ b("label", {
745
1090
  htmlFor: `${e.fieldKey}-video-fps`,
746
- className: B,
747
- children: "FPS"
748
- }), /* @__PURE__ */ y("input", {
1091
+ className: U,
1092
+ children: i("ffmpeg.fps")
1093
+ }), /* @__PURE__ */ b("input", {
749
1094
  id: `${e.fieldKey}-video-fps`,
750
1095
  type: "number",
751
- value: s.video.fps ?? "",
752
- onChange: (e) => S(Number(e.target.value)),
1096
+ value: c.video.fps ?? "",
1097
+ onChange: (e) => C(Number(e.target.value)),
753
1098
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed w-24 text-right"
754
1099
  })]
755
1100
  }),
756
- /* @__PURE__ */ b("div", {
757
- className: z,
758
- children: [/* @__PURE__ */ y("label", {
1101
+ /* @__PURE__ */ x("div", {
1102
+ className: H,
1103
+ children: [/* @__PURE__ */ b("label", {
759
1104
  htmlFor: `${e.fieldKey}-video-bitrate`,
760
- className: B,
761
- children: "Bitrate (kbps)"
762
- }), /* @__PURE__ */ y("input", {
1105
+ className: U,
1106
+ children: i("ffmpeg.bitrateKbps")
1107
+ }), /* @__PURE__ */ b("input", {
763
1108
  id: `${e.fieldKey}-video-bitrate`,
764
1109
  type: "number",
765
- value: s.video.bitrateKbps ?? "",
766
- onChange: (e) => C(Number(e.target.value)),
1110
+ value: c.video.bitrateKbps ?? "",
1111
+ onChange: (e) => w(Number(e.target.value)),
767
1112
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed w-24 text-right"
768
1113
  })]
769
1114
  })
770
1115
  ] })]
771
1116
  })]
772
- }), /* @__PURE__ */ b("div", {
773
- className: V,
774
- children: [/* @__PURE__ */ y("div", {
775
- className: H,
776
- children: /* @__PURE__ */ y("h3", {
777
- className: U,
778
- children: "Audio"
1117
+ }), /* @__PURE__ */ x("div", {
1118
+ className: W,
1119
+ children: [/* @__PURE__ */ b("div", {
1120
+ className: G,
1121
+ children: /* @__PURE__ */ b("h3", {
1122
+ className: K,
1123
+ children: i("ffmpeg.audio")
779
1124
  })
780
- }), /* @__PURE__ */ y("div", {
1125
+ }), /* @__PURE__ */ b("div", {
781
1126
  className: "px-3 py-2",
782
- children: s.audio === "passthrough" ? /* @__PURE__ */ b("div", {
1127
+ children: c.audio === "passthrough" ? /* @__PURE__ */ x("div", {
783
1128
  className: "flex items-center justify-between gap-3",
784
- children: [/* @__PURE__ */ y("span", {
1129
+ children: [/* @__PURE__ */ b("span", {
785
1130
  className: "text-[11px] text-foreground-subtle italic",
786
- children: "Source audio forwarded without re-encode."
787
- }), /* @__PURE__ */ y("button", {
1131
+ children: i("ffmpeg.audioPassthroughNote")
1132
+ }), /* @__PURE__ */ b("button", {
788
1133
  type: "button",
789
- onClick: () => T("opus"),
1134
+ onClick: () => E("opus"),
790
1135
  className: "rounded-md border border-border bg-surface-hover px-2 py-1 text-[11px] text-foreground hover:bg-surface-hover/70 transition-colors",
791
- children: "Switch to custom encode"
1136
+ children: i("ffmpeg.switchToCustom")
792
1137
  })]
793
- }) : /* @__PURE__ */ b("div", {
1138
+ }) : /* @__PURE__ */ x("div", {
794
1139
  className: "divide-y divide-border/30",
795
1140
  children: [
796
- /* @__PURE__ */ b("div", {
797
- className: z,
798
- children: [/* @__PURE__ */ y("label", {
1141
+ /* @__PURE__ */ x("div", {
1142
+ className: H,
1143
+ children: [/* @__PURE__ */ b("label", {
799
1144
  htmlFor: `${e.fieldKey}-audio-codec`,
800
- className: B,
801
- children: "Codec"
802
- }), /* @__PURE__ */ b("select", {
1145
+ className: U,
1146
+ children: i("ffmpeg.codec")
1147
+ }), /* @__PURE__ */ x("select", {
803
1148
  id: `${e.fieldKey}-audio-codec`,
804
- value: s.audio.codec,
805
- onChange: (e) => T(e.target.value),
1149
+ value: c.audio.codec,
1150
+ onChange: (e) => E(e.target.value),
806
1151
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed appearance-none pr-6 min-w-[120px]",
807
1152
  children: [
808
- /* @__PURE__ */ y("option", {
1153
+ /* @__PURE__ */ b("option", {
809
1154
  value: "opus",
810
1155
  children: "opus"
811
1156
  }),
812
- /* @__PURE__ */ y("option", {
1157
+ /* @__PURE__ */ b("option", {
813
1158
  value: "aac",
814
1159
  children: "aac"
815
1160
  }),
816
- /* @__PURE__ */ y("option", {
1161
+ /* @__PURE__ */ b("option", {
817
1162
  value: "pcmu",
818
1163
  children: "pcmu"
819
1164
  }),
820
- /* @__PURE__ */ y("option", {
1165
+ /* @__PURE__ */ b("option", {
821
1166
  value: "pcma",
822
1167
  children: "pcma"
823
1168
  }),
824
- /* @__PURE__ */ y("option", {
1169
+ /* @__PURE__ */ b("option", {
825
1170
  value: "copy",
826
- children: "copy (passthrough)"
1171
+ children: i("ffmpeg.copyPassthrough")
827
1172
  })
828
1173
  ]
829
1174
  })]
830
1175
  }),
831
- /* @__PURE__ */ b("div", {
832
- className: z,
833
- children: [/* @__PURE__ */ y("label", {
1176
+ /* @__PURE__ */ x("div", {
1177
+ className: H,
1178
+ children: [/* @__PURE__ */ b("label", {
834
1179
  htmlFor: `${e.fieldKey}-audio-bitrate`,
835
- className: B,
836
- children: "Bitrate (kbps)"
837
- }), /* @__PURE__ */ y("input", {
1180
+ className: U,
1181
+ children: i("ffmpeg.bitrateKbps")
1182
+ }), /* @__PURE__ */ b("input", {
838
1183
  id: `${e.fieldKey}-audio-bitrate`,
839
1184
  type: "number",
840
- value: s.audio.bitrateKbps ?? "",
841
- onChange: (e) => E(Number(e.target.value)),
1185
+ value: c.audio.bitrateKbps ?? "",
1186
+ onChange: (e) => D(Number(e.target.value)),
842
1187
  className: "rounded border border-border bg-surface-2 px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 disabled:cursor-not-allowed read-only:opacity-60 read-only:cursor-not-allowed w-24 text-right"
843
1188
  })]
844
1189
  }),
845
- /* @__PURE__ */ y("div", {
1190
+ /* @__PURE__ */ b("div", {
846
1191
  className: "pt-2",
847
- children: /* @__PURE__ */ y("button", {
1192
+ children: /* @__PURE__ */ b("button", {
848
1193
  type: "button",
849
- onClick: w,
1194
+ onClick: T,
850
1195
  className: "text-[11px] text-foreground-subtle hover:text-foreground underline-offset-2 hover:underline",
851
- children: "Switch back to passthrough"
1196
+ children: i("ffmpeg.switchToPassthrough")
852
1197
  })
853
1198
  })
854
1199
  ]
@@ -857,201 +1202,201 @@ function fe({ config: e, value: t, onSave: n, saveStatus: r }) {
857
1202
  })]
858
1203
  })
859
1204
  }),
860
- o ? /* @__PURE__ */ b(x, { children: [/* @__PURE__ */ b("div", {
861
- className: V,
862
- children: [/* @__PURE__ */ y("div", {
863
- className: H,
864
- children: /* @__PURE__ */ y("h3", {
865
- className: U,
866
- children: "Input args"
1205
+ s ? /* @__PURE__ */ x(S, { children: [/* @__PURE__ */ x("div", {
1206
+ className: W,
1207
+ children: [/* @__PURE__ */ b("div", {
1208
+ className: G,
1209
+ children: /* @__PURE__ */ b("h3", {
1210
+ className: K,
1211
+ children: i("ffmpeg.inputArgs")
867
1212
  })
868
- }), /* @__PURE__ */ y("div", {
1213
+ }), /* @__PURE__ */ b("div", {
869
1214
  className: "px-3 py-2",
870
- children: A
1215
+ children: j
871
1216
  })]
872
- }), /* @__PURE__ */ b("div", {
873
- className: V,
874
- children: [/* @__PURE__ */ y("div", {
875
- className: H,
876
- children: /* @__PURE__ */ y("h3", {
877
- className: U,
878
- children: "Output args"
1217
+ }), /* @__PURE__ */ x("div", {
1218
+ className: W,
1219
+ children: [/* @__PURE__ */ b("div", {
1220
+ className: G,
1221
+ children: /* @__PURE__ */ b("h3", {
1222
+ className: K,
1223
+ children: i("ffmpeg.outputArgs")
879
1224
  })
880
- }), /* @__PURE__ */ y("div", {
1225
+ }), /* @__PURE__ */ b("div", {
881
1226
  className: "px-3 py-2",
882
- children: j
1227
+ children: M
883
1228
  })]
884
- })] }) : /* @__PURE__ */ b("div", {
885
- className: V,
886
- children: [/* @__PURE__ */ b("button", {
1229
+ })] }) : /* @__PURE__ */ x("div", {
1230
+ className: W,
1231
+ children: [/* @__PURE__ */ x("button", {
887
1232
  type: "button",
888
- onClick: () => a((e) => !e),
1233
+ onClick: () => o((e) => !e),
889
1234
  className: "w-full px-3 py-1.5 flex items-center justify-between bg-surface-hover/30 hover:bg-surface-hover transition-colors",
890
- children: [/* @__PURE__ */ b("span", {
1235
+ children: [/* @__PURE__ */ x("span", {
891
1236
  className: "inline-flex items-center gap-1.5 text-[11px] font-semibold text-foreground uppercase tracking-wider",
892
- children: [y(i ? P : F, { className: "h-3 w-3" }), "Advanced — raw ffmpeg args"]
1237
+ children: [b(a ? F : I, { className: "h-3 w-3" }), i("ffmpeg.advanced")]
893
1238
  }), /* @__PURE__ */ b("span", {
894
1239
  className: "text-[10px] text-foreground-subtle italic",
895
- children: [(s.inputArgs?.length ?? 0) + (s.outputArgs?.length ?? 0), " args"]
1240
+ children: i("ffmpeg.argsCount", { count: (c.inputArgs?.length ?? 0) + (c.outputArgs?.length ?? 0) })
896
1241
  })]
897
- }), i && /* @__PURE__ */ b("div", {
1242
+ }), a && /* @__PURE__ */ x("div", {
898
1243
  className: "px-3 py-2 space-y-3 border-t border-border/50",
899
1244
  children: [
900
- A,
901
- /* @__PURE__ */ y(ce, {
902
- outputArgs: s.outputArgs ?? [],
1245
+ j,
1246
+ /* @__PURE__ */ b(se, {
1247
+ outputArgs: c.outputArgs ?? [],
903
1248
  onChange: (e) => {
904
- d(e.join("\n")), O(e.join("\n"));
1249
+ f(e.join("\n")), k(e.join("\n"));
905
1250
  }
906
1251
  }),
907
- j
1252
+ M
908
1253
  ]
909
1254
  })]
910
1255
  })
911
1256
  ]
912
1257
  });
913
1258
  }
914
- function pe({ status: e }) {
915
- let t = "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium border";
916
- return e === "saving" ? /* @__PURE__ */ b("span", {
917
- className: `${t} bg-accent/10 text-accent border-accent/30`,
918
- children: [/* @__PURE__ */ y(te, { className: "h-2.5 w-2.5 animate-spin" }), "Saving…"]
919
- }) : e === "saved" ? /* @__PURE__ */ b("span", {
920
- className: `${t} bg-success/10 text-success border-success/30`,
921
- children: [/* @__PURE__ */ y(N, { className: "h-2.5 w-2.5" }), "Saved"]
922
- }) : e === "error" ? /* @__PURE__ */ b("span", {
923
- className: `${t} bg-red-500/10 text-red-400 border-red-500/30`,
924
- children: [/* @__PURE__ */ y(ee, { className: "h-2.5 w-2.5" }), "Save failed"]
925
- }) : /* @__PURE__ */ y("span", {
926
- className: `${t} bg-foreground-subtle/10 text-foreground-subtle border-border`,
927
- children: "Autosaves"
1259
+ function fe({ status: e }) {
1260
+ let { t } = z(), n = "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium border";
1261
+ return e === "saving" ? /* @__PURE__ */ x("span", {
1262
+ className: `${n} bg-accent/10 text-accent border-accent/30`,
1263
+ children: [/* @__PURE__ */ b(ee, { className: "h-2.5 w-2.5 animate-spin" }), t("ffmpeg.saving")]
1264
+ }) : e === "saved" ? /* @__PURE__ */ x("span", {
1265
+ className: `${n} bg-success/10 text-success border-success/30`,
1266
+ children: [/* @__PURE__ */ b(P, { className: "h-2.5 w-2.5" }), t("ffmpeg.saved")]
1267
+ }) : e === "error" ? /* @__PURE__ */ x("span", {
1268
+ className: `${n} bg-red-500/10 text-red-400 border-red-500/30`,
1269
+ children: [/* @__PURE__ */ b(L, { className: "h-2.5 w-2.5" }), t("ffmpeg.saveFailed")]
1270
+ }) : /* @__PURE__ */ b("span", {
1271
+ className: `${n} bg-foreground-subtle/10 text-foreground-subtle border-border`,
1272
+ children: t("ffmpeg.autosaves")
928
1273
  });
929
1274
  }
930
- function me({ profile: e }) {
931
- let t = "inline-flex items-center gap-1 rounded-full bg-foreground-subtle/10 border border-border px-2 py-0.5 text-[11px] font-mono text-foreground-subtle", { video: n, audio: r } = e, i = n.width !== void 0 && n.height !== void 0 ? `${n.width}×${n.height}` : void 0;
932
- return /* @__PURE__ */ b(x, { children: [
933
- /* @__PURE__ */ b("span", {
934
- className: t,
935
- children: [/* @__PURE__ */ y("span", {
1275
+ function pe({ profile: e }) {
1276
+ let { t } = z(), n = "inline-flex items-center gap-1 rounded-full bg-foreground-subtle/10 border border-border px-2 py-0.5 text-[11px] font-mono text-foreground-subtle", { video: r, audio: i } = e, a = r.width !== void 0 && r.height !== void 0 ? `${r.width}×${r.height}` : void 0;
1277
+ return /* @__PURE__ */ x(S, { children: [
1278
+ /* @__PURE__ */ x("span", {
1279
+ className: n,
1280
+ children: [/* @__PURE__ */ b("span", {
936
1281
  className: "opacity-60",
937
- children: "codec"
938
- }), n.codec]
1282
+ children: t("ffmpeg.chipCodec")
1283
+ }), r.codec]
939
1284
  }),
940
- i !== void 0 && /* @__PURE__ */ b("span", {
941
- className: t,
942
- children: [/* @__PURE__ */ y("span", {
1285
+ a !== void 0 && /* @__PURE__ */ x("span", {
1286
+ className: n,
1287
+ children: [/* @__PURE__ */ b("span", {
943
1288
  className: "opacity-60",
944
- children: "res"
945
- }), i]
1289
+ children: t("ffmpeg.chipRes")
1290
+ }), a]
946
1291
  }),
947
- n.fps !== void 0 && /* @__PURE__ */ b("span", {
948
- className: t,
949
- children: [/* @__PURE__ */ y("span", {
1292
+ r.fps !== void 0 && /* @__PURE__ */ x("span", {
1293
+ className: n,
1294
+ children: [/* @__PURE__ */ b("span", {
950
1295
  className: "opacity-60",
951
- children: "fps"
952
- }), n.fps]
1296
+ children: t("ffmpeg.chipFps")
1297
+ }), r.fps]
953
1298
  }),
954
- n.bitrateKbps !== void 0 && /* @__PURE__ */ b("span", {
955
- className: t,
1299
+ r.bitrateKbps !== void 0 && /* @__PURE__ */ x("span", {
1300
+ className: n,
956
1301
  children: [
957
- /* @__PURE__ */ y("span", {
1302
+ /* @__PURE__ */ b("span", {
958
1303
  className: "opacity-60",
959
- children: "bitrate"
1304
+ children: t("ffmpeg.chipBitrate")
960
1305
  }),
961
- n.bitrateKbps,
1306
+ r.bitrateKbps,
962
1307
  "k"
963
1308
  ]
964
1309
  }),
965
- r === "passthrough" ? /* @__PURE__ */ b("span", {
966
- className: t,
967
- children: [/* @__PURE__ */ y("span", {
1310
+ i === "passthrough" ? /* @__PURE__ */ x("span", {
1311
+ className: n,
1312
+ children: [/* @__PURE__ */ b("span", {
968
1313
  className: "opacity-60",
969
- children: "audio"
970
- }), "passthrough"]
971
- }) : /* @__PURE__ */ b(x, { children: [
972
- /* @__PURE__ */ b("span", {
973
- className: t,
974
- children: [/* @__PURE__ */ y("span", {
1314
+ children: t("ffmpeg.chipAudio")
1315
+ }), t("ffmpeg.chipPassthrough")]
1316
+ }) : /* @__PURE__ */ x(S, { children: [
1317
+ /* @__PURE__ */ x("span", {
1318
+ className: n,
1319
+ children: [/* @__PURE__ */ b("span", {
975
1320
  className: "opacity-60",
976
- children: "audio"
977
- }), r.codec]
1321
+ children: t("ffmpeg.chipAudio")
1322
+ }), i.codec]
978
1323
  }),
979
- r.bitrateKbps !== void 0 && /* @__PURE__ */ b("span", {
980
- className: t,
1324
+ i.bitrateKbps !== void 0 && /* @__PURE__ */ x("span", {
1325
+ className: n,
981
1326
  children: [
982
- /* @__PURE__ */ y("span", {
1327
+ /* @__PURE__ */ b("span", {
983
1328
  className: "opacity-60",
984
- children: "a-bitrate"
1329
+ children: t("ffmpeg.chipAudioBitrate")
985
1330
  }),
986
- r.bitrateKbps,
1331
+ i.bitrateKbps,
987
1332
  "k"
988
1333
  ]
989
1334
  }),
990
- r.sampleRateHz !== void 0 && /* @__PURE__ */ b("span", {
991
- className: t,
1335
+ i.sampleRateHz !== void 0 && /* @__PURE__ */ x("span", {
1336
+ className: n,
992
1337
  children: [
993
- /* @__PURE__ */ y("span", {
1338
+ /* @__PURE__ */ b("span", {
994
1339
  className: "opacity-60",
995
- children: "a-sr"
1340
+ children: t("ffmpeg.chipSampleRate")
996
1341
  }),
997
- r.sampleRateHz,
1342
+ i.sampleRateHz,
998
1343
  "Hz"
999
1344
  ]
1000
1345
  }),
1001
- r.channels !== void 0 && /* @__PURE__ */ b("span", {
1002
- className: t,
1003
- children: [/* @__PURE__ */ y("span", {
1346
+ i.channels !== void 0 && /* @__PURE__ */ x("span", {
1347
+ className: n,
1348
+ children: [/* @__PURE__ */ b("span", {
1004
1349
  className: "opacity-60",
1005
- children: "a-ch"
1006
- }), r.channels]
1350
+ children: t("ffmpeg.chipChannels")
1351
+ }), i.channels]
1007
1352
  })
1008
1353
  ] })
1009
1354
  ] });
1010
1355
  }
1011
- function he(e) {
1012
- let t = e.config ?? {}, n = d(), [r, i] = g(() => t.initialValue), a = _((r) => {
1013
- if (i(r), e.deviceId === void 0) return;
1014
- let a = t.writerCapName, o = t.writerAddonId, s = t.fieldKey;
1015
- if (a === void 0 || o === void 0 || s === void 0) {
1356
+ function me(e) {
1357
+ let { t } = z(), n = e.config ?? {}, r = f(), [i, a] = _(() => n.initialValue), o = v((t) => {
1358
+ if (a(t), e.deviceId === void 0) return;
1359
+ let i = n.writerCapName, o = n.writerAddonId, s = n.fieldKey;
1360
+ if (i === void 0 || o === void 0 || s === void 0) {
1016
1361
  console.warn(`[ffmpeg-params] widgetConfig is missing writerCapName/writerAddonId/fieldKey — field ${s ?? "(unknown)"} cannot be saved. Fix the contribution builder.`);
1017
1362
  return;
1018
1363
  }
1019
- n.mutate({
1364
+ r.mutate({
1020
1365
  deviceId: e.deviceId,
1021
- writerCapName: a,
1366
+ writerCapName: i,
1022
1367
  writerAddonId: o,
1023
1368
  key: s,
1024
- value: r ?? null
1369
+ value: t ?? null
1025
1370
  });
1026
1371
  }, [
1027
1372
  e.deviceId,
1028
- t.fieldKey,
1029
- t.writerCapName,
1030
- t.writerAddonId,
1031
- n
1373
+ n.fieldKey,
1374
+ n.writerCapName,
1375
+ n.writerAddonId,
1376
+ r
1032
1377
  ]);
1033
- if (e.deviceId === void 0) return /* @__PURE__ */ y("div", {
1378
+ if (e.deviceId === void 0) return /* @__PURE__ */ b("div", {
1034
1379
  className: "rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning",
1035
- children: "ffmpeg-params: no deviceId in widget context — this widget only renders inside a device tab."
1380
+ children: t("ffmpeg.noDeviceId")
1036
1381
  });
1037
- let o = t.fieldKey;
1038
- if (o === void 0 || o.length === 0) return /* @__PURE__ */ y("div", {
1382
+ let s = n.fieldKey;
1383
+ if (s === void 0 || s.length === 0) return /* @__PURE__ */ b("div", {
1039
1384
  className: "rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning",
1040
- children: "ffmpeg-params: widgetConfig.fieldKey is required — fix the contribution builder."
1385
+ children: t("ffmpeg.fieldKeyRequired")
1041
1386
  });
1042
- let s = n.isPending ? "saving" : n.isError ? "error" : n.isSuccess ? "saved" : "idle";
1043
- return /* @__PURE__ */ y(fe, {
1387
+ let c = r.isPending ? "saving" : r.isError ? "error" : r.isSuccess ? "saved" : "idle";
1388
+ return /* @__PURE__ */ b(de, {
1044
1389
  config: {
1045
- ...t,
1046
- fieldKey: o
1390
+ ...n,
1391
+ fieldKey: s
1047
1392
  },
1048
- value: r,
1049
- onSave: a,
1050
- saveStatus: s
1393
+ value: i,
1394
+ onSave: o,
1395
+ saveStatus: c
1051
1396
  });
1052
1397
  }
1053
- function W({ id: e, disabled: t, catalogue: n, onPick: r }) {
1054
- let [i, a] = g(!1), o = m(() => {
1398
+ function q({ id: e, disabled: t, catalogue: n, onPick: r }) {
1399
+ let { t: i } = z(), [a, o] = _(!1), s = h(() => {
1055
1400
  let e = /* @__PURE__ */ new Map();
1056
1401
  for (let t of n) {
1057
1402
  let n = e.get(t.group) ?? [];
@@ -1059,39 +1404,39 @@ function W({ id: e, disabled: t, catalogue: n, onPick: r }) {
1059
1404
  }
1060
1405
  return e;
1061
1406
  }, [n]);
1062
- return /* @__PURE__ */ b("div", {
1407
+ return /* @__PURE__ */ x("div", {
1063
1408
  className: "relative",
1064
- children: [/* @__PURE__ */ b("button", {
1409
+ children: [/* @__PURE__ */ x("button", {
1065
1410
  id: e,
1066
1411
  type: "button",
1067
1412
  disabled: t,
1068
- onClick: () => a((e) => !e),
1413
+ onClick: () => o((e) => !e),
1069
1414
  className: "inline-flex items-center gap-1 rounded-md border border-border bg-surface-hover px-2 py-0.5 text-[10px] font-medium text-foreground-subtle hover:bg-surface-hover/70 disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
1070
- children: [/* @__PURE__ */ y(ne, { className: "h-3 w-3" }), "Add flag…"]
1071
- }), i && !t && /* @__PURE__ */ b(x, { children: [/* @__PURE__ */ y("div", {
1415
+ children: [/* @__PURE__ */ b(te, { className: "h-3 w-3" }), i("ffmpeg.addFlag")]
1416
+ }), a && !t && /* @__PURE__ */ x(S, { children: [/* @__PURE__ */ b("div", {
1072
1417
  className: "fixed inset-0 z-40",
1073
- onClick: () => a(!1),
1418
+ onClick: () => o(!1),
1074
1419
  "aria-hidden": "true"
1075
- }), /* @__PURE__ */ y("div", {
1420
+ }), /* @__PURE__ */ b("div", {
1076
1421
  className: "absolute right-0 top-full z-50 mt-1 max-h-72 w-72 overflow-y-auto rounded-lg border border-border bg-surface shadow-lg",
1077
1422
  role: "menu",
1078
- children: Array.from(o.entries()).map(([e, t]) => /* @__PURE__ */ b("div", {
1423
+ children: Array.from(s.entries()).map(([e, t]) => /* @__PURE__ */ x("div", {
1079
1424
  className: "border-b border-border/30 last:border-b-0",
1080
- children: [/* @__PURE__ */ y("div", {
1425
+ children: [/* @__PURE__ */ b("div", {
1081
1426
  className: "sticky top-0 bg-surface-hover/80 backdrop-blur px-2 py-1 text-[9px] font-semibold uppercase tracking-wider text-foreground-subtle",
1082
- children: e
1083
- }), t.map((e) => /* @__PURE__ */ b("button", {
1427
+ children: i(e)
1428
+ }), t.map((e) => /* @__PURE__ */ x("button", {
1084
1429
  type: "button",
1085
1430
  onClick: () => {
1086
- r(e), a(!1);
1431
+ r(e), o(!1);
1087
1432
  },
1088
1433
  className: "w-full text-left px-2 py-1.5 hover:bg-surface-hover transition-colors group",
1089
- children: [/* @__PURE__ */ y("div", {
1434
+ children: [/* @__PURE__ */ b("div", {
1090
1435
  className: "font-mono text-[11px] text-foreground",
1091
1436
  children: e.label
1092
- }), e.description !== void 0 && /* @__PURE__ */ y("div", {
1437
+ }), e.descriptionKey !== void 0 && /* @__PURE__ */ b("div", {
1093
1438
  className: "text-[10px] text-foreground-subtle leading-snug mt-0.5",
1094
- children: e.description
1439
+ children: i(e.descriptionKey)
1095
1440
  })]
1096
1441
  }, e.label))]
1097
1442
  }, e))
@@ -1100,18 +1445,15 @@ function W({ id: e, disabled: t, catalogue: n, onPick: r }) {
1100
1445
  }
1101
1446
  //#endregion
1102
1447
  //#region src/stream-broker/widgets/broker-audio-switch.ts
1103
- var ge = "Audio", _e = "This node distributes no audio for the camera — live subscribers and new recordings are silent. The camera itself keeps capturing sound.";
1104
- function ve(e) {
1448
+ function he(e) {
1105
1449
  let t = e.sourceNodeId !== null && e.sourceNodeId !== "", n = t && e.muted !== null ? !e.muted : null, r = e.pendingOn ?? null;
1106
1450
  return {
1107
- label: ge,
1108
1451
  on: n === null ? null : r ?? n,
1109
1452
  available: n !== null,
1110
- costWhenOff: _e,
1111
1453
  nodeId: t ? e.sourceNodeId : null
1112
1454
  };
1113
1455
  }
1114
- function ye(e, t) {
1456
+ function ge(e, t) {
1115
1457
  return !e.available || e.on === null || e.nodeId === null ? null : {
1116
1458
  deviceId: t,
1117
1459
  muted: e.on,
@@ -1120,41 +1462,37 @@ function ye(e, t) {
1120
1462
  }
1121
1463
  //#endregion
1122
1464
  //#region src/stream-broker/widgets/format-ua.ts
1123
- var G = 24;
1124
- function be(e) {
1465
+ var _e = 24;
1466
+ function ve(e) {
1125
1467
  return /\bEdg\b|\bEdgA\b|\bEdgiOS\b|Edge\//.test(e) ? "Edge" : /\bOPR\b|Opera/.test(e) ? "Opera" : /Firefox\/|\bFxiOS\b/.test(e) ? "Firefox" : /Chrome\/|\bCriOS\b/.test(e) ? "Chrome" : /Safari\//.test(e) ? "Safari" : null;
1126
1468
  }
1127
- function xe(e) {
1469
+ function ye(e) {
1128
1470
  return /iPhone|iPad|iPod|\biOS\b|CriOS|FxiOS/.test(e) ? "iOS" : /Mac OS X|Macintosh/.test(e) ? "macOS" : /Windows/.test(e) ? "Windows" : /Android/.test(e) ? "Android" : /Linux/.test(e) ? "Linux" : null;
1129
1471
  }
1130
- function K(e) {
1472
+ function J(e) {
1131
1473
  let t = e.trim();
1132
1474
  if (t.length === 0) return "";
1133
- let n = be(t), r = xe(t);
1134
- return n && r ? `${n}/${r}` : n || r || (t.length > G ? `${t.slice(0, G)}…` : t);
1475
+ let n = ve(t), r = ye(t);
1476
+ return n && r ? `${n}/${r}` : n || r || (t.length > _e ? `${t.slice(0, _e)}…` : t);
1135
1477
  }
1136
1478
  //#endregion
1137
1479
  //#region src/stream-broker/widgets/StreamBrokerPanel.tsx
1138
- function Se(e) {
1480
+ function be(e) {
1139
1481
  if (typeof e != "object" || !e) return null;
1140
1482
  let t = { ...e }.muted;
1141
1483
  return typeof t == "boolean" ? t : null;
1142
1484
  }
1143
- function Ce(e) {
1485
+ function xe(e) {
1144
1486
  let t = Math.floor(e / 1e3);
1145
1487
  if (t < 60) return `${t}s`;
1146
1488
  let n = Math.floor(t / 60);
1147
1489
  return n < 60 ? `${n}m` : `${Math.floor(n / 60)}h ${n % 60}m`;
1148
1490
  }
1149
- var q = {
1150
- high: "High",
1151
- mid: "Mid",
1152
- low: "Low"
1153
- }, J = [
1491
+ var Se = [
1154
1492
  "high",
1155
1493
  "mid",
1156
1494
  "low"
1157
- ], we = {
1495
+ ], Ce = {
1158
1496
  alexa: "bg-blue-500/15 text-blue-400",
1159
1497
  homekit: "bg-purple-500/15 text-purple-400",
1160
1498
  "webrtc-browser": "bg-emerald-500/15 text-emerald-400",
@@ -1167,7 +1505,7 @@ var q = {
1167
1505
  snapshot: "bg-cyan-500/15 text-cyan-400",
1168
1506
  warmup: "bg-foreground-subtle/10 text-foreground-subtle",
1169
1507
  unknown: "bg-foreground-subtle/10 text-foreground-subtle"
1170
- }, Y = {
1508
+ }, we = {
1171
1509
  alexa: "ALEXA",
1172
1510
  homekit: "HOMEKIT",
1173
1511
  "webrtc-browser": "BROWSER",
@@ -1182,162 +1520,169 @@ var q = {
1182
1520
  unknown: "—"
1183
1521
  };
1184
1522
  function Te(e) {
1185
- return Y[e] ?? e.toUpperCase().slice(0, 8);
1523
+ return we[e] ?? e.toUpperCase().slice(0, 8);
1186
1524
  }
1187
1525
  function Ee(e) {
1188
- return Y[e] ?? e;
1526
+ return we[e] ?? e;
1189
1527
  }
1190
1528
  function De(e) {
1191
- let t = e.config ?? {};
1192
- return e.deviceId === void 0 ? /* @__PURE__ */ y("div", {
1529
+ let { t } = z(), n = e.config ?? {};
1530
+ return e.deviceId === void 0 ? /* @__PURE__ */ b("div", {
1193
1531
  className: "rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning",
1194
- children: "StreamBrokerPanel requires a deviceId"
1195
- }) : /* @__PURE__ */ y(Oe, {
1532
+ children: t("panel.requiresDeviceId")
1533
+ }) : /* @__PURE__ */ b(Oe, {
1196
1534
  deviceId: e.deviceId,
1197
- title: t.title,
1198
- variant: t.variant,
1199
- hideEmpty: t.hideEmpty
1535
+ title: n.title,
1536
+ variant: n.variant,
1537
+ hideEmpty: n.hideEmpty
1200
1538
  });
1201
1539
  }
1202
- function Oe({ deviceId: t, title: n = "Stream Brokers", variant: i = "full", hideEmpty: a = !1 }) {
1203
- l(["streamBroker", "listAllProfileSlots"], [
1540
+ function Oe({ deviceId: t, title: n, variant: i = "full", hideEmpty: a = !1 }) {
1541
+ let { t: o } = z();
1542
+ u(["streamBroker", "listAllProfileSlots"], [
1204
1543
  "device.streams-registered",
1205
1544
  "device.streams-unregistered",
1206
1545
  "device.registered",
1207
1546
  "device.unregistered"
1208
1547
  ]);
1209
- let { data: s } = f(void 0, { staleTime: 3e4 }), d = (s ?? []).filter((e) => e.deviceId === t && e.sourceCamStreamId !== null).slice().toSorted((e, t) => J.indexOf(e.profile) - J.indexOf(t.profile)), p = o(c().trpcClient, t), { data: m } = w({
1548
+ let { data: c } = p(void 0, { staleTime: 3e4 }), f = (c ?? []).filter((e) => e.deviceId === t && e.sourceCamStreamId !== null).slice().toSorted((e, t) => Se.indexOf(e.profile) - Se.indexOf(t.profile)), m = s(l().trpcClient, t), { data: h } = T({
1210
1549
  queryKey: [
1211
1550
  "device",
1212
1551
  t,
1213
1552
  "cameraStreams.getCameraStreams"
1214
1553
  ],
1215
- queryFn: () => p?.cameraStreams?.getCameraStreams({}) ?? [],
1216
- enabled: !!p,
1554
+ queryFn: () => m?.cameraStreams?.getCameraStreams({}) ?? [],
1555
+ enabled: !!m,
1217
1556
  staleTime: 3e4
1218
- }), h = /* @__PURE__ */ new Map();
1219
- for (let e of m ?? []) h.set(e.camStreamId, e);
1220
- let { data: v } = e({ deviceId: t }, { staleTime: 3e4 }), x = v?.assignment.sourceNodeId ?? null, S = C(), [T, E] = g(null), [D, O] = g(null), k = ve({
1221
- muted: Se(u({
1557
+ }), g = /* @__PURE__ */ new Map();
1558
+ for (let e of h ?? []) g.set(e.camStreamId, e);
1559
+ let { data: y } = e({ deviceId: t }, { staleTime: 3e4 }), S = y?.assignment.sourceNodeId ?? null, C = w(), [E, D] = _(null), [O, k] = _(null), A = he({
1560
+ muted: be(d({
1222
1561
  deviceId: t,
1223
- nodeId: x ?? void 0
1562
+ nodeId: S ?? void 0
1224
1563
  }, {
1225
- enabled: x !== null,
1564
+ enabled: S !== null,
1226
1565
  staleTime: 3e4
1227
1566
  }).data),
1228
- sourceNodeId: x,
1229
- pendingOn: T
1230
- }), A = r({
1567
+ sourceNodeId: S,
1568
+ pendingOn: E
1569
+ }), j = r({
1231
1570
  onError: (e) => {
1232
1571
  console.error("[StreamBrokerPanel] audio mute write failed — reverting", {
1233
1572
  tags: { deviceId: t },
1234
1573
  meta: {
1235
- nodeId: x,
1574
+ nodeId: S,
1236
1575
  error: e instanceof Error ? e.message : String(e)
1237
1576
  }
1238
- }), E(null), O(e instanceof Error ? e.message : String(e)), S.invalidateQueries({ queryKey: [["streamBroker", "getDeviceAudioMute"]] });
1577
+ }), D(null), k(e instanceof Error ? e.message : String(e)), C.invalidateQueries({ queryKey: [["streamBroker", "getDeviceAudioMute"]] });
1239
1578
  },
1240
1579
  onSuccess: () => {
1241
- O(null), E(null), S.invalidateQueries({ queryKey: [["streamBroker"]] }), S.invalidateQueries({ queryKey: [["pipelineOrchestrator"]] });
1580
+ k(null), D(null), C.invalidateQueries({ queryKey: [["streamBroker"]] }), C.invalidateQueries({ queryKey: [["pipelineOrchestrator"]] });
1242
1581
  }
1243
- }), j = _(() => {
1244
- let e = ye(k, t);
1245
- e !== null && (E(!e.muted), O(null), A.mutate(e));
1582
+ }), M = v(() => {
1583
+ let e = ge(A, t);
1584
+ e !== null && (D(!e.muted), k(null), j.mutate(e));
1246
1585
  }, [
1247
- k,
1586
+ A,
1248
1587
  t,
1249
- A
1250
- ]), M = new Set(d.map((e) => e.sourceCamStreamId).filter((e) => e !== null)), N = (m ?? []).filter((e) => !M.has(e.camStreamId)), P = d.length > 0, F = N.length > 0;
1251
- return a && !P && !F ? null : i === "compact" ? P ? /* @__PURE__ */ y("div", {
1588
+ j
1589
+ ]), N = new Set(f.map((e) => e.sourceCamStreamId).filter((e) => e !== null)), P = (h ?? []).filter((e) => !N.has(e.camStreamId)), F = A.nodeId ?? o("audio.thisNode"), I = f.length > 0, L = P.length > 0;
1590
+ return a && !I && !L ? null : i === "compact" ? I ? /* @__PURE__ */ b("div", {
1252
1591
  className: "divide-y divide-border/30",
1253
- children: d.map((e) => /* @__PURE__ */ y(je, {
1592
+ children: f.map((e) => /* @__PURE__ */ b(Y, {
1254
1593
  slot: e,
1255
- camStreams: h,
1594
+ camStreams: g,
1256
1595
  compact: !0
1257
1596
  }, e.brokerId))
1258
- }) : /* @__PURE__ */ y("div", {
1259
- className: "text-[11px] text-foreground-subtle italic px-2 py-1",
1260
- children: "No active profile slots"
1261
1597
  }) : /* @__PURE__ */ b("div", {
1598
+ className: "text-[11px] text-foreground-subtle italic px-2 py-1",
1599
+ children: o("panel.noActiveSlots")
1600
+ }) : /* @__PURE__ */ x("div", {
1262
1601
  className: "rounded-lg border border-border bg-surface overflow-hidden",
1263
1602
  children: [
1264
- /* @__PURE__ */ b("div", {
1603
+ /* @__PURE__ */ x("div", {
1265
1604
  className: "border-b border-border px-4 py-2 flex flex-wrap items-center justify-between gap-x-2 gap-y-1",
1266
- children: [/* @__PURE__ */ y("h2", {
1605
+ children: [/* @__PURE__ */ b("h2", {
1267
1606
  className: "text-xs font-semibold text-foreground uppercase tracking-wider shrink-0",
1268
- children: n
1269
- }), /* @__PURE__ */ b("div", {
1607
+ children: n ?? o("panel.title")
1608
+ }), /* @__PURE__ */ x("div", {
1270
1609
  className: "flex items-center gap-1.5 min-w-0",
1271
- children: [x !== null && /* @__PURE__ */ b("span", {
1272
- title: `Cluster node dialing this camera's source: ${x}`,
1610
+ children: [S !== null && /* @__PURE__ */ x("span", {
1611
+ title: o("panel.sourceNodeTitle", { node: S }),
1273
1612
  className: "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[10px] font-medium bg-accent/10 text-accent border border-accent/30 min-w-0 max-w-full",
1274
- children: [/* @__PURE__ */ y(I, { className: "h-2.5 w-2.5 shrink-0" }), /* @__PURE__ */ y("span", {
1613
+ children: [/* @__PURE__ */ b(R, { className: "h-2.5 w-2.5 shrink-0" }), /* @__PURE__ */ b("span", {
1275
1614
  className: "truncate",
1276
- children: x
1615
+ children: S
1277
1616
  })]
1278
- }), P && /* @__PURE__ */ b("span", {
1617
+ }), I && /* @__PURE__ */ b("span", {
1279
1618
  className: "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[10px] font-medium bg-foreground-subtle/10 text-foreground-subtle border border-border shrink-0 whitespace-nowrap",
1280
- children: [d.length, " assigned"]
1619
+ children: o("panel.assigned", { count: f.length })
1281
1620
  })]
1282
1621
  })]
1283
1622
  }),
1284
- /* @__PURE__ */ b("div", {
1623
+ /* @__PURE__ */ x("div", {
1285
1624
  className: "border-b border-border px-4 py-2 flex items-center gap-3",
1286
- children: [/* @__PURE__ */ b("button", {
1625
+ children: [/* @__PURE__ */ x("button", {
1287
1626
  type: "button",
1288
1627
  role: "switch",
1289
- "aria-label": k.label,
1290
- "aria-checked": k.on === !0,
1291
- disabled: !k.available || A.isPending,
1292
- onClick: j,
1293
- title: k.on === null ? "Audio distribution — unknown: the node that serves this camera did not answer." : k.on ? `Audio is distributed by ${k.nodeId ?? "this node"}. Muting it: ${k.costWhenOff}` : `Muted on ${k.nodeId ?? "this node"}. ${k.costWhenOff}`,
1294
- className: `inline-flex items-center gap-1.5 rounded-lg border px-2 py-1 text-[11px] font-medium transition-colors disabled:cursor-not-allowed shrink-0 ${D === null ? k.on === null ? "border-dashed border-border text-foreground-subtle/50" : k.on === !1 ? "border-warning/40 text-warning hover:bg-warning/10" : "border-success/30 text-success hover:bg-success/10" : "border-danger/50 text-danger bg-danger/5"}`,
1295
- children: [k.on === !1 ? /* @__PURE__ */ y(ie, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ y(re, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ y("span", { children: k.on === null ? "Audio unknown" : k.on ? "Audio on" : "Audio muted" })]
1296
- }), /* @__PURE__ */ y("p", {
1628
+ "aria-label": o("audio.label"),
1629
+ "aria-checked": A.on === !0,
1630
+ disabled: !A.available || j.isPending,
1631
+ onClick: M,
1632
+ title: A.on === null ? o("audio.unknownTitle") : A.on ? o("audio.onTitle", {
1633
+ node: F,
1634
+ cost: o("audio.costWhenOff")
1635
+ }) : o("audio.mutedTitle", {
1636
+ node: F,
1637
+ cost: o("audio.costWhenOff")
1638
+ }),
1639
+ className: `inline-flex items-center gap-1.5 rounded-lg border px-2 py-1 text-[11px] font-medium transition-colors disabled:cursor-not-allowed shrink-0 ${O === null ? A.on === null ? "border-dashed border-border text-foreground-subtle/50" : A.on === !1 ? "border-warning/40 text-warning hover:bg-warning/10" : "border-success/30 text-success hover:bg-success/10" : "border-danger/50 text-danger bg-danger/5"}`,
1640
+ children: [A.on === !1 ? /* @__PURE__ */ b(re, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ b(ne, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ b("span", { children: A.on === null ? o("audio.stateUnknown") : A.on ? o("audio.stateOn") : o("audio.stateMuted") })]
1641
+ }), /* @__PURE__ */ b("p", {
1297
1642
  className: "min-w-0 flex-1 text-[10px] leading-relaxed text-foreground-subtle",
1298
- children: D === null ? k.on === null ? "The node that serves this camera did not answer, so its audio policy is unknown." : k.costWhenOff : `Write failed: ${D}`
1643
+ children: O === null ? A.on === null ? o("audio.unknownHint") : o("audio.costWhenOff") : o("audio.writeFailed", { error: O })
1299
1644
  })]
1300
1645
  }),
1301
- P ? /* @__PURE__ */ y("div", {
1646
+ I ? /* @__PURE__ */ b("div", {
1302
1647
  className: "divide-y divide-border/30",
1303
- children: d.map((e) => /* @__PURE__ */ y(je, {
1648
+ children: f.map((e) => /* @__PURE__ */ b(Y, {
1304
1649
  slot: e,
1305
- camStreams: h,
1650
+ camStreams: g,
1306
1651
  compact: !1
1307
1652
  }, e.brokerId))
1308
- }) : /* @__PURE__ */ b("div", {
1653
+ }) : /* @__PURE__ */ x("div", {
1309
1654
  className: "px-4 py-6 flex flex-col items-center text-center text-foreground-subtle",
1310
- children: [/* @__PURE__ */ y(I, { className: "h-5 w-5 mb-2 opacity-30" }), /* @__PURE__ */ y("p", {
1655
+ children: [/* @__PURE__ */ b(R, { className: "h-5 w-5 mb-2 opacity-30" }), /* @__PURE__ */ b("p", {
1311
1656
  className: "text-xs",
1312
- children: "No profile slots assigned for this device"
1657
+ children: o("panel.noSlotsAssigned")
1313
1658
  })]
1314
1659
  }),
1315
- F && /* @__PURE__ */ y(ke, {
1660
+ L && /* @__PURE__ */ b(ke, {
1316
1661
  deviceId: t,
1317
- camStreamIds: N.map((e) => e.camStreamId),
1318
- camStreams: h
1662
+ camStreamIds: P.map((e) => e.camStreamId),
1663
+ camStreams: g
1319
1664
  })
1320
1665
  ]
1321
1666
  });
1322
1667
  }
1323
1668
  function ke({ deviceId: e, camStreamIds: t, camStreams: n }) {
1324
- let [r, i] = g(!1);
1325
- return /* @__PURE__ */ b("div", {
1669
+ let { t: r } = z(), [i, a] = _(!1);
1670
+ return /* @__PURE__ */ x("div", {
1326
1671
  className: "border-t border-border/50",
1327
- children: [/* @__PURE__ */ b("button", {
1672
+ children: [/* @__PURE__ */ x("button", {
1328
1673
  type: "button",
1329
- onClick: () => i((e) => !e),
1674
+ onClick: () => a((e) => !e),
1330
1675
  className: "w-full px-4 py-1.5 flex items-center justify-between bg-surface-hover/30 hover:bg-surface-hover transition-colors",
1331
- children: [/* @__PURE__ */ b("span", {
1676
+ children: [/* @__PURE__ */ x("span", {
1332
1677
  className: "inline-flex items-center gap-1.5 text-[11px] uppercase tracking-wider text-foreground-subtle",
1333
- children: [y(r ? P : F, { className: "h-3 w-3" }), "Other active streams"]
1334
- }), /* @__PURE__ */ y("span", {
1678
+ children: [b(i ? F : I, { className: "h-3 w-3" }), r("unassigned.title")]
1679
+ }), /* @__PURE__ */ b("span", {
1335
1680
  className: "rounded-full px-2 py-0.5 text-[10px] font-medium bg-foreground-subtle/10 text-foreground-subtle border border-border",
1336
1681
  children: t.length
1337
1682
  })]
1338
- }), r && /* @__PURE__ */ y("div", {
1683
+ }), i && /* @__PURE__ */ b("div", {
1339
1684
  className: "divide-y divide-border/30",
1340
- children: t.map((t) => /* @__PURE__ */ y(Ae, {
1685
+ children: t.map((t) => /* @__PURE__ */ b(Ae, {
1341
1686
  deviceId: e,
1342
1687
  camStreamId: t,
1343
1688
  camStreams: n
@@ -1346,81 +1691,81 @@ function ke({ deviceId: e, camStreamIds: t, camStreams: n }) {
1346
1691
  });
1347
1692
  }
1348
1693
  function Ae({ deviceId: e, camStreamId: t, camStreams: n }) {
1349
- let r = S(e, t), a = i("stream-broker.metrics-snapshot", (e) => e.brokerId === r)?.stats, o = n.get(t), s = a?.status === "streaming";
1350
- return /* @__PURE__ */ b("div", {
1694
+ let { t: r } = z(), a = C(e, t), o = i("stream-broker.metrics-snapshot", (e) => e.brokerId === a)?.stats, s = n.get(t), c = o?.status === "streaming";
1695
+ return /* @__PURE__ */ x("div", {
1351
1696
  className: "px-4 py-2",
1352
- children: [/* @__PURE__ */ y("div", {
1697
+ children: [/* @__PURE__ */ b("div", {
1353
1698
  className: "flex items-center justify-between mb-1",
1354
- children: /* @__PURE__ */ b("div", {
1699
+ children: /* @__PURE__ */ x("div", {
1355
1700
  className: "flex items-center gap-1.5",
1356
1701
  children: [
1357
- /* @__PURE__ */ y("span", { className: `h-1.5 w-1.5 rounded-full ${s ? "bg-success" : "bg-foreground-subtle/40"}` }),
1358
- /* @__PURE__ */ y("span", {
1702
+ /* @__PURE__ */ b("span", { className: `h-1.5 w-1.5 rounded-full ${c ? "bg-success" : "bg-foreground-subtle/40"}` }),
1703
+ /* @__PURE__ */ b("span", {
1359
1704
  className: "text-[11px] font-medium text-foreground",
1360
- children: o?.label ?? t
1705
+ children: s?.label ?? t
1361
1706
  }),
1362
- o?.resolution && /* @__PURE__ */ b("span", {
1707
+ s?.resolution && /* @__PURE__ */ x("span", {
1363
1708
  className: "text-[10px] text-foreground-subtle",
1364
1709
  children: [
1365
- o.resolution.width,
1710
+ s.resolution.width,
1366
1711
  "×",
1367
- o.resolution.height
1712
+ s.resolution.height
1368
1713
  ]
1369
1714
  }),
1370
- /* @__PURE__ */ y("span", {
1371
- className: `text-[10px] ${s ? "text-success" : "text-foreground-subtle"}`,
1372
- children: a?.status ?? "idle"
1715
+ /* @__PURE__ */ b("span", {
1716
+ className: `text-[10px] ${c ? "text-success" : "text-foreground-subtle"}`,
1717
+ children: o?.status ?? r("stats.idle")
1373
1718
  })
1374
1719
  ]
1375
1720
  })
1376
- }), a && s && /* @__PURE__ */ b("div", {
1721
+ }), o && c && /* @__PURE__ */ x("div", {
1377
1722
  className: "flex flex-wrap gap-x-3 gap-y-1 text-[10px]",
1378
1723
  children: [
1379
- /* @__PURE__ */ b("span", {
1724
+ /* @__PURE__ */ x("span", {
1380
1725
  className: "inline-flex whitespace-nowrap gap-1",
1381
- children: [/* @__PURE__ */ y("span", {
1726
+ children: [/* @__PURE__ */ b("span", {
1382
1727
  className: "text-foreground-subtle",
1383
- children: "FPS:"
1384
- }), /* @__PURE__ */ y("span", {
1728
+ children: r("stats.fps")
1729
+ }), /* @__PURE__ */ b("span", {
1385
1730
  className: "text-foreground",
1386
- children: a.inputFps.toFixed(1)
1731
+ children: o.inputFps.toFixed(1)
1387
1732
  })]
1388
1733
  }),
1389
- /* @__PURE__ */ b("span", {
1734
+ /* @__PURE__ */ x("span", {
1390
1735
  className: "inline-flex whitespace-nowrap gap-1",
1391
- children: [/* @__PURE__ */ y("span", {
1736
+ children: [/* @__PURE__ */ b("span", {
1392
1737
  className: "text-foreground-subtle",
1393
- children: "Bitrate:"
1394
- }), /* @__PURE__ */ y("span", {
1738
+ children: r("stats.bitrate")
1739
+ }), /* @__PURE__ */ b("span", {
1395
1740
  className: "text-foreground",
1396
- children: a.bitrateKbps >= 1e3 ? `${(a.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${a.bitrateKbps} kbps`
1741
+ children: o.bitrateKbps >= 1e3 ? `${(o.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${o.bitrateKbps} kbps`
1397
1742
  })]
1398
1743
  }),
1399
- /* @__PURE__ */ b("span", {
1744
+ /* @__PURE__ */ x("span", {
1400
1745
  className: "inline-flex whitespace-nowrap gap-1",
1401
- children: [/* @__PURE__ */ y("span", {
1746
+ children: [/* @__PURE__ */ b("span", {
1402
1747
  className: "text-foreground-subtle",
1403
- children: "Codec:"
1404
- }), /* @__PURE__ */ y("span", {
1748
+ children: r("stats.codec")
1749
+ }), /* @__PURE__ */ b("span", {
1405
1750
  className: "text-foreground",
1406
- children: a.codec?.toUpperCase() ?? "—"
1751
+ children: o.codec?.toUpperCase() ?? "—"
1407
1752
  })]
1408
1753
  }),
1409
- /* @__PURE__ */ b("span", {
1754
+ /* @__PURE__ */ x("span", {
1410
1755
  className: "inline-flex whitespace-nowrap gap-1",
1411
- children: [/* @__PURE__ */ y("span", {
1756
+ children: [/* @__PURE__ */ b("span", {
1412
1757
  className: "text-foreground-subtle",
1413
- children: "Pkts:"
1414
- }), /* @__PURE__ */ y("span", {
1758
+ children: r("stats.pkts")
1759
+ }), /* @__PURE__ */ b("span", {
1415
1760
  className: "text-foreground",
1416
- children: a.packetCount > 1e3 ? `${(a.packetCount / 1e3).toFixed(1)}k` : a.packetCount
1761
+ children: o.packetCount > 1e3 ? `${(o.packetCount / 1e3).toFixed(1)}k` : o.packetCount
1417
1762
  })]
1418
1763
  })
1419
1764
  ]
1420
1765
  })]
1421
1766
  });
1422
1767
  }
1423
- function X(e, t) {
1768
+ function je(e, t) {
1424
1769
  let n = (e) => {
1425
1770
  if (!e || typeof e != "object") return;
1426
1771
  let r = e;
@@ -1441,265 +1786,261 @@ function X(e, t) {
1441
1786
  if (t !== void 0) return t;
1442
1787
  }
1443
1788
  }
1444
- function je({ slot: e, camStreams: r, compact: o }) {
1445
- let c = C(), u = i("stream-broker.metrics-snapshot", (t) => t.brokerId === e.brokerId)?.stats;
1446
- l(["streamBroker", "listClients"], ["stream-broker.metrics-snapshot"]);
1447
- let { data: d } = n({ brokerId: e.brokerId }, {
1448
- enabled: u?.status === "streaming",
1789
+ function Y({ slot: e, camStreams: r, compact: o }) {
1790
+ let { t: s } = z(), l = w(), d = i("stream-broker.metrics-snapshot", (t) => t.brokerId === e.brokerId)?.stats;
1791
+ u(["streamBroker", "listClients"], ["stream-broker.metrics-snapshot"]);
1792
+ let { data: f } = n({ brokerId: e.brokerId }, {
1793
+ enabled: d?.status === "streaming",
1449
1794
  staleTime: 2e3
1450
- }), { data: f, isPending: p } = t({ deviceId: e.deviceId }, { staleTime: 15e3 }), m = e.sourceCamStreamId ?? e.profile, h = X(f, `preBufferEnabled:${m}`), g = typeof h == "boolean", v = h === !0, S = X(f, `preBufferSec:${m}`), w = typeof S == "number" ? S : void 0, T = s({ onSuccess: () => {
1451
- c.invalidateQueries({ queryKey: [["streamBroker", "getDeviceSettingsContribution"]] });
1452
- } }), E = (t) => {
1453
- T.mutate({
1795
+ }), { data: p, isPending: m } = t({ deviceId: e.deviceId }, { staleTime: 15e3 }), h = e.sourceCamStreamId ?? e.profile, g = je(p, `preBufferEnabled:${h}`), _ = typeof g == "boolean", y = g === !0, C = je(p, `preBufferSec:${h}`), T = typeof C == "number" ? C : void 0, E = c({ onSuccess: () => {
1796
+ l.invalidateQueries({ queryKey: [["streamBroker", "getDeviceSettingsContribution"]] });
1797
+ } }), D = (t) => {
1798
+ E.mutate({
1454
1799
  deviceId: e.deviceId,
1455
- patch: { [`preBufferEnabled:${m}`]: t }
1800
+ patch: { [`preBufferEnabled:${h}`]: t }
1456
1801
  });
1457
- }, D = a({ onSuccess: () => {
1458
- c.invalidateQueries({ queryKey: [["streamBroker", "listClients"]] });
1459
- } }), O = _((t) => {
1460
- D.mutate({
1802
+ }, O = a({ onSuccess: () => {
1803
+ l.invalidateQueries({ queryKey: [["streamBroker", "listClients"]] });
1804
+ } }), k = v((t) => {
1805
+ O.mutate({
1461
1806
  brokerId: e.brokerId,
1462
1807
  ...t
1463
1808
  });
1464
- }, [D, e.brokerId]), k = (e.sourceCamStreamId ? r.get(e.sourceCamStreamId) : void 0)?.resolution ?? e.resolution, A = u?.status === "streaming", j = k ? `${q[e.profile]} (${k.width}×${k.height})` : q[e.profile], M = u ? u.encodedSubscribers + (u.rtspClients ?? 0) + (u.pipeClients ?? 0) : 0;
1465
- return /* @__PURE__ */ b("div", {
1809
+ }, [O, e.brokerId]), A = (e.sourceCamStreamId ? r.get(e.sourceCamStreamId) : void 0)?.resolution ?? e.resolution, j = d?.status === "streaming", M = s(`profile.${e.profile}`), N = A ? `${M} (${A.width}×${A.height})` : M, P = d ? d.encodedSubscribers + (d.rtspClients ?? 0) + (d.pipeClients ?? 0) : 0;
1810
+ return /* @__PURE__ */ x("div", {
1466
1811
  className: `@container ${o ? "px-3 py-1.5" : "px-4 py-2"}`,
1467
1812
  style: { containerType: "inline-size" },
1468
1813
  children: [
1469
- /* @__PURE__ */ b("div", {
1814
+ /* @__PURE__ */ x("div", {
1470
1815
  className: "flex items-center justify-between gap-2 mb-1.5",
1471
- children: [/* @__PURE__ */ b("div", {
1816
+ children: [/* @__PURE__ */ x("div", {
1472
1817
  className: "flex items-center gap-1.5 min-w-0",
1473
1818
  children: [
1474
- /* @__PURE__ */ y("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${A ? e.profile === "high" ? "bg-success" : e.profile === "mid" ? "bg-warning" : "bg-foreground-subtle" : "bg-foreground-subtle/40"}` }),
1475
- /* @__PURE__ */ y("span", {
1819
+ /* @__PURE__ */ b("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${j ? e.profile === "high" ? "bg-success" : e.profile === "mid" ? "bg-warning" : "bg-foreground-subtle" : "bg-foreground-subtle/40"}` }),
1820
+ /* @__PURE__ */ b("span", {
1476
1821
  className: "text-[11px] font-medium text-foreground whitespace-nowrap shrink-0",
1477
- children: j
1822
+ children: N
1478
1823
  }),
1479
- /* @__PURE__ */ y("span", {
1480
- className: `text-[10px] shrink-0 ${A ? "text-success" : "text-foreground-subtle"}`,
1481
- children: u?.status ?? "loading"
1824
+ /* @__PURE__ */ b("span", {
1825
+ className: `text-[10px] shrink-0 ${j ? "text-success" : "text-foreground-subtle"}`,
1826
+ children: d?.status ?? s("stats.loading")
1482
1827
  }),
1483
- e.sourceCamStreamId && /* @__PURE__ */ b("span", {
1828
+ e.sourceCamStreamId && /* @__PURE__ */ x("span", {
1484
1829
  className: "text-[10px] text-foreground-subtle truncate min-w-0",
1485
1830
  title: e.sourceCamStreamId,
1486
1831
  children: ["← ", e.sourceCamStreamId]
1487
1832
  })
1488
1833
  ]
1489
- }), /* @__PURE__ */ y("span", {
1834
+ }), /* @__PURE__ */ b("span", {
1490
1835
  className: "text-[10px] text-foreground-subtle shrink-0 whitespace-nowrap",
1491
- children: u && u.uptimeMs > 0 ? Ce(u.uptimeMs) : "—"
1836
+ children: d && d.uptimeMs > 0 ? xe(d.uptimeMs) : "—"
1492
1837
  })]
1493
1838
  }),
1494
- u && A ? o ? /* @__PURE__ */ b("div", {
1839
+ d && j ? o ? /* @__PURE__ */ x("div", {
1495
1840
  className: "flex flex-wrap gap-x-3 gap-y-0.5 text-[10px]",
1496
1841
  children: [
1497
- /* @__PURE__ */ b("span", {
1842
+ /* @__PURE__ */ x("span", {
1498
1843
  className: "inline-flex whitespace-nowrap gap-1",
1499
- children: [/* @__PURE__ */ y("span", {
1844
+ children: [/* @__PURE__ */ b("span", {
1500
1845
  className: "text-foreground-subtle",
1501
- children: "FPS:"
1502
- }), /* @__PURE__ */ b("span", {
1846
+ children: s("stats.fps")
1847
+ }), /* @__PURE__ */ x("span", {
1503
1848
  className: "text-foreground",
1504
- children: [u.inputFps.toFixed(1), " fps"]
1849
+ children: [d.inputFps.toFixed(1), " fps"]
1505
1850
  })]
1506
1851
  }),
1507
- /* @__PURE__ */ b("span", {
1852
+ /* @__PURE__ */ x("span", {
1508
1853
  className: "inline-flex whitespace-nowrap gap-1",
1509
- children: [/* @__PURE__ */ y("span", {
1854
+ children: [/* @__PURE__ */ b("span", {
1510
1855
  className: "text-foreground-subtle",
1511
- children: "Bitrate:"
1512
- }), /* @__PURE__ */ y("span", {
1856
+ children: s("stats.bitrate")
1857
+ }), /* @__PURE__ */ b("span", {
1513
1858
  className: "text-foreground",
1514
- children: u.bitrateKbps >= 1e3 ? `${(u.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${u.bitrateKbps} kbps`
1859
+ children: d.bitrateKbps >= 1e3 ? `${(d.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${d.bitrateKbps} kbps`
1515
1860
  })]
1516
1861
  }),
1517
- /* @__PURE__ */ b("span", {
1862
+ /* @__PURE__ */ x("span", {
1518
1863
  className: "inline-flex whitespace-nowrap gap-1",
1519
- children: [/* @__PURE__ */ y("span", {
1864
+ children: [/* @__PURE__ */ b("span", {
1520
1865
  className: "text-foreground-subtle",
1521
- children: "Codec:"
1522
- }), /* @__PURE__ */ y("span", {
1866
+ children: s("stats.codec")
1867
+ }), /* @__PURE__ */ b("span", {
1523
1868
  className: "text-foreground",
1524
- children: u.codec?.toUpperCase() ?? "—"
1869
+ children: d.codec?.toUpperCase() ?? "—"
1525
1870
  })]
1526
1871
  }),
1527
- /* @__PURE__ */ b("span", {
1872
+ /* @__PURE__ */ x("span", {
1528
1873
  className: "inline-flex items-center whitespace-nowrap gap-1",
1529
1874
  children: [
1530
- /* @__PURE__ */ y("span", {
1875
+ /* @__PURE__ */ b("span", {
1531
1876
  className: "text-foreground-subtle",
1532
- children: "Clients:"
1877
+ children: s("stats.clients")
1533
1878
  }),
1534
- /* @__PURE__ */ y("span", {
1879
+ /* @__PURE__ */ b("span", {
1535
1880
  className: "text-foreground font-semibold",
1536
- children: M
1881
+ children: P
1537
1882
  }),
1538
- /* @__PURE__ */ y("span", {
1883
+ /* @__PURE__ */ b("span", {
1539
1884
  className: "text-foreground-subtle/70",
1540
1885
  children: "("
1541
1886
  }),
1542
- /* @__PURE__ */ y(Le, {
1543
- count: u.encodedSubscribers,
1544
- clients: d,
1545
- onKill: O
1887
+ /* @__PURE__ */ b(Ie, {
1888
+ count: d.encodedSubscribers,
1889
+ clients: f,
1890
+ onKill: k
1546
1891
  }),
1547
- /* @__PURE__ */ y("span", {
1892
+ /* @__PURE__ */ b("span", {
1548
1893
  className: "text-foreground-subtle/70",
1549
1894
  children: "·"
1550
1895
  }),
1551
- /* @__PURE__ */ y(ze, {
1552
- count: u.rtspClients ?? 0,
1553
- clients: d,
1554
- onKill: O
1896
+ /* @__PURE__ */ b(Re, {
1897
+ count: d.rtspClients ?? 0,
1898
+ clients: f,
1899
+ onKill: k
1555
1900
  }),
1556
1901
  /* @__PURE__ */ b("span", {
1557
1902
  className: "text-foreground-subtle/70",
1558
- children: [
1559
- "· pipe ",
1560
- u.pipeClients ?? 0,
1561
- ")"
1562
- ]
1903
+ children: s("stats.pipeSuffix", { count: d.pipeClients ?? 0 })
1563
1904
  })
1564
1905
  ]
1565
1906
  })
1566
1907
  ]
1567
- }) : /* @__PURE__ */ b(x, { children: [/* @__PURE__ */ b("div", {
1908
+ }) : /* @__PURE__ */ x(S, { children: [/* @__PURE__ */ x("div", {
1568
1909
  className: "flex flex-wrap gap-x-3 gap-y-1 text-[10px]",
1569
1910
  children: [
1570
- /* @__PURE__ */ b("span", {
1911
+ /* @__PURE__ */ x("span", {
1571
1912
  className: "inline-flex whitespace-nowrap gap-1",
1572
- children: [/* @__PURE__ */ y("span", {
1913
+ children: [/* @__PURE__ */ b("span", {
1573
1914
  className: "text-foreground-subtle",
1574
- children: "In:"
1575
- }), /* @__PURE__ */ b("span", {
1915
+ children: s("stats.in")
1916
+ }), /* @__PURE__ */ x("span", {
1576
1917
  className: "text-foreground",
1577
- children: [u.inputFps.toFixed(1), " fps"]
1918
+ children: [d.inputFps.toFixed(1), " fps"]
1578
1919
  })]
1579
1920
  }),
1580
- /* @__PURE__ */ b("span", {
1921
+ /* @__PURE__ */ x("span", {
1581
1922
  className: "inline-flex whitespace-nowrap gap-1",
1582
- children: [/* @__PURE__ */ y("span", {
1923
+ children: [/* @__PURE__ */ b("span", {
1583
1924
  className: "text-foreground-subtle",
1584
- children: "Bitrate:"
1585
- }), /* @__PURE__ */ y("span", {
1925
+ children: s("stats.bitrate")
1926
+ }), /* @__PURE__ */ b("span", {
1586
1927
  className: "text-foreground",
1587
- children: u.bitrateKbps >= 1e3 ? `${(u.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${u.bitrateKbps} kbps`
1928
+ children: d.bitrateKbps >= 1e3 ? `${(d.bitrateKbps / 1e3).toFixed(1)} Mbps` : `${d.bitrateKbps} kbps`
1588
1929
  })]
1589
1930
  }),
1590
- /* @__PURE__ */ b("span", {
1931
+ /* @__PURE__ */ x("span", {
1591
1932
  className: "hidden @[480px]:inline-flex whitespace-nowrap gap-1",
1592
- children: [/* @__PURE__ */ y("span", {
1933
+ children: [/* @__PURE__ */ b("span", {
1593
1934
  className: "text-foreground-subtle",
1594
- children: "IDR:"
1595
- }), /* @__PURE__ */ y("span", {
1935
+ children: s("stats.idr")
1936
+ }), /* @__PURE__ */ b("span", {
1596
1937
  className: "text-foreground",
1597
- children: u.idrIntervalMs > 0 ? `${(u.idrIntervalMs / 1e3).toFixed(1)}s` : "—"
1938
+ children: d.idrIntervalMs > 0 ? `${(d.idrIntervalMs / 1e3).toFixed(1)}s` : "—"
1598
1939
  })]
1599
1940
  }),
1600
- /* @__PURE__ */ b("span", {
1941
+ /* @__PURE__ */ x("span", {
1601
1942
  className: "inline-flex whitespace-nowrap gap-1",
1602
- children: [/* @__PURE__ */ y("span", {
1943
+ children: [/* @__PURE__ */ b("span", {
1603
1944
  className: "text-foreground-subtle",
1604
- children: "Codec:"
1605
- }), /* @__PURE__ */ y("span", {
1945
+ children: s("stats.codec")
1946
+ }), /* @__PURE__ */ b("span", {
1606
1947
  className: "text-foreground",
1607
- children: u.codec?.toUpperCase() ?? "—"
1948
+ children: d.codec?.toUpperCase() ?? "—"
1608
1949
  })]
1609
1950
  }),
1610
- /* @__PURE__ */ b("span", {
1951
+ /* @__PURE__ */ x("span", {
1611
1952
  className: "hidden @[640px]:inline-flex whitespace-nowrap gap-1",
1612
- children: [/* @__PURE__ */ y("span", {
1953
+ children: [/* @__PURE__ */ b("span", {
1613
1954
  className: "text-foreground-subtle",
1614
- children: "Pipe:"
1615
- }), /* @__PURE__ */ y("span", {
1955
+ children: s("stats.pipe")
1956
+ }), /* @__PURE__ */ b("span", {
1616
1957
  className: "text-foreground",
1617
- children: u.pipeClients ?? 0
1958
+ children: d.pipeClients ?? 0
1618
1959
  })]
1619
1960
  }),
1620
- /* @__PURE__ */ b("span", {
1961
+ /* @__PURE__ */ x("span", {
1621
1962
  className: "hidden @[640px]:inline-flex whitespace-nowrap gap-1",
1622
- children: [/* @__PURE__ */ y("span", {
1963
+ children: [/* @__PURE__ */ b("span", {
1623
1964
  className: "text-foreground-subtle",
1624
- children: "Packets:"
1625
- }), /* @__PURE__ */ y("span", {
1965
+ children: s("stats.packets")
1966
+ }), /* @__PURE__ */ b("span", {
1626
1967
  className: "text-foreground",
1627
- children: u.packetCount > 1e3 ? `${(u.packetCount / 1e3).toFixed(1)}k` : u.packetCount
1968
+ children: d.packetCount > 1e3 ? `${(d.packetCount / 1e3).toFixed(1)}k` : d.packetCount
1628
1969
  })]
1629
1970
  }),
1630
- /* @__PURE__ */ b("span", {
1971
+ /* @__PURE__ */ x("span", {
1631
1972
  className: "hidden @[640px]:inline-flex whitespace-nowrap gap-1",
1632
- children: [/* @__PURE__ */ y("span", {
1973
+ children: [/* @__PURE__ */ b("span", {
1633
1974
  className: "text-foreground-subtle",
1634
- children: "Data:"
1635
- }), /* @__PURE__ */ y("span", {
1975
+ children: s("stats.data")
1976
+ }), /* @__PURE__ */ b("span", {
1636
1977
  className: "text-foreground",
1637
- children: u.totalBytes > 1048576 ? `${(u.totalBytes / 1048576).toFixed(1)} MB` : `${(u.totalBytes / 1024).toFixed(0)} KB`
1978
+ children: d.totalBytes > 1048576 ? `${(d.totalBytes / 1048576).toFixed(1)} MB` : `${(d.totalBytes / 1024).toFixed(0)} KB`
1638
1979
  })]
1639
1980
  }),
1640
- u.audio && /* @__PURE__ */ b("div", {
1981
+ d.audio && /* @__PURE__ */ x("div", {
1641
1982
  className: "basis-full flex flex-wrap items-center gap-x-1.5 gap-y-0.5",
1642
1983
  children: [
1643
- /* @__PURE__ */ y("span", {
1984
+ /* @__PURE__ */ b("span", {
1644
1985
  className: "text-foreground-subtle whitespace-nowrap",
1645
- children: "Audio:"
1986
+ children: s("stats.audio")
1646
1987
  }),
1647
- /* @__PURE__ */ b("span", {
1988
+ /* @__PURE__ */ x("span", {
1648
1989
  className: "inline-flex whitespace-nowrap items-center gap-1.5",
1649
1990
  children: [
1650
- /* @__PURE__ */ y("span", {
1991
+ /* @__PURE__ */ b("span", {
1651
1992
  className: "text-foreground",
1652
- children: u.audio.codec.toUpperCase()
1993
+ children: d.audio.codec.toUpperCase()
1653
1994
  }),
1654
- /* @__PURE__ */ y("span", {
1995
+ /* @__PURE__ */ b("span", {
1655
1996
  className: "text-foreground-subtle",
1656
1997
  children: "·"
1657
1998
  }),
1658
- /* @__PURE__ */ y("span", {
1999
+ /* @__PURE__ */ b("span", {
1659
2000
  className: "text-foreground",
1660
- children: u.audio.sampleRate >= 1e3 ? `${(u.audio.sampleRate / 1e3).toFixed(u.audio.sampleRate % 1e3 == 0 ? 0 : 1)}kHz` : `${u.audio.sampleRate}Hz`
2001
+ children: d.audio.sampleRate >= 1e3 ? `${(d.audio.sampleRate / 1e3).toFixed(d.audio.sampleRate % 1e3 == 0 ? 0 : 1)}kHz` : `${d.audio.sampleRate}Hz`
1661
2002
  }),
1662
- /* @__PURE__ */ y("span", {
2003
+ /* @__PURE__ */ b("span", {
1663
2004
  className: "text-foreground-subtle",
1664
2005
  children: "·"
1665
2006
  }),
1666
- /* @__PURE__ */ y("span", {
2007
+ /* @__PURE__ */ b("span", {
1667
2008
  className: "text-foreground",
1668
- children: u.audio.channels === 1 ? "mono" : u.audio.channels === 2 ? "stereo" : `${u.audio.channels}ch`
2009
+ children: d.audio.channels === 1 ? s("stats.mono") : d.audio.channels === 2 ? s("stats.stereo") : `${d.audio.channels}ch`
1669
2010
  })
1670
2011
  ]
1671
2012
  }),
1672
- /* @__PURE__ */ y("span", {
1673
- className: `px-1 py-px rounded text-[8px] font-medium whitespace-nowrap ${u.audio.supported ? "bg-success/15 text-success" : "bg-amber-500/15 text-amber-500"}`,
1674
- children: u.audio.supported ? "decoded" : "no decoder"
2013
+ /* @__PURE__ */ b("span", {
2014
+ className: `px-1 py-px rounded text-[8px] font-medium whitespace-nowrap ${d.audio.supported ? "bg-success/15 text-success" : "bg-amber-500/15 text-amber-500"}`,
2015
+ children: d.audio.supported ? s("stats.decoded") : s("stats.noDecoder")
1675
2016
  })
1676
2017
  ]
1677
2018
  })
1678
2019
  ]
1679
- }), /* @__PURE__ */ y(Ie, {
1680
- clients: d,
1681
- encodedCount: u.encodedSubscribers,
1682
- onKill: O
1683
- })] }) : /* @__PURE__ */ y("p", {
2020
+ }), /* @__PURE__ */ b(Fe, {
2021
+ clients: f,
2022
+ encodedCount: d.encodedSubscribers,
2023
+ onKill: k
2024
+ })] }) : /* @__PURE__ */ b("p", {
1684
2025
  className: "text-[10px] text-foreground-subtle italic",
1685
- children: "No demand — stream suspended"
2026
+ children: s("stats.noDemand")
1686
2027
  }),
1687
- /* @__PURE__ */ b("div", {
2028
+ /* @__PURE__ */ x("div", {
1688
2029
  className: "mt-1.5 flex items-center gap-1.5 text-[10px]",
1689
2030
  children: [
1690
- /* @__PURE__ */ y("span", {
2031
+ /* @__PURE__ */ b("span", {
1691
2032
  className: "text-foreground-subtle",
1692
- children: "Buffer:"
2033
+ children: s("stats.buffer")
1693
2034
  }),
1694
- /* @__PURE__ */ y(Re, {
1695
- enabled: v,
1696
- known: g,
1697
- onToggle: (e) => E(e),
1698
- disabled: p || !g || T.isPending
2035
+ /* @__PURE__ */ b(Le, {
2036
+ enabled: y,
2037
+ known: _,
2038
+ onToggle: (e) => D(e),
2039
+ disabled: m || !_ || E.isPending
1699
2040
  }),
1700
- /* @__PURE__ */ b("span", {
2041
+ /* @__PURE__ */ x("span", {
1701
2042
  className: "text-foreground",
1702
- children: [g ? `${w ?? u?.preBufferSec ?? 0}s` : "…", g && u && A ? ` (${u.preBufferPackets}p)` : ""]
2043
+ children: [_ ? `${T ?? d?.preBufferSec ?? 0}s` : "…", _ && d && j ? ` (${d.preBufferPackets}p)` : ""]
1703
2044
  })
1704
2045
  ]
1705
2046
  })
@@ -1708,15 +2049,15 @@ function je({ slot: e, camStreams: r, compact: o }) {
1708
2049
  }
1709
2050
  var Me = 280, Ne = 120;
1710
2051
  function Pe({ trigger: e, content: t, widthClass: n }) {
1711
- let r = p(null), i = p(null), [a, o] = g(!1), [s, c] = g(!1), l = _(() => {
2052
+ let r = m(null), i = m(null), [a, o] = _(!1), [s, c] = _(!1), l = v(() => {
1712
2053
  i.current &&= (clearTimeout(i.current), null);
1713
- }, []), u = _(() => {
2054
+ }, []), u = v(() => {
1714
2055
  l(), i.current = setTimeout(() => o(!1), Ne);
1715
2056
  }, [l]);
1716
- return /* @__PURE__ */ b("span", {
2057
+ return /* @__PURE__ */ x("span", {
1717
2058
  ref: r,
1718
2059
  className: "relative inline-block",
1719
- onMouseEnter: _(() => {
2060
+ onMouseEnter: v(() => {
1720
2061
  l();
1721
2062
  let e = r.current;
1722
2063
  if (e) {
@@ -1726,7 +2067,7 @@ function Pe({ trigger: e, content: t, widthClass: n }) {
1726
2067
  o(!0);
1727
2068
  }, [l]),
1728
2069
  onMouseLeave: u,
1729
- children: [e, a && /* @__PURE__ */ y("div", {
2070
+ children: [e, a && /* @__PURE__ */ b("div", {
1730
2071
  className: `absolute left-0 ${s ? "bottom-full mb-1" : "top-full mt-1"} z-50 ${n} rounded-md border border-border bg-surface shadow-xl p-2 text-[10px] normal-case`,
1731
2072
  onMouseEnter: l,
1732
2073
  onMouseLeave: u,
@@ -1734,60 +2075,56 @@ function Pe({ trigger: e, content: t, widthClass: n }) {
1734
2075
  })]
1735
2076
  });
1736
2077
  }
1737
- function Z(e) {
2078
+ function X(e) {
1738
2079
  if (e < 1e3) return `${e}ms`;
1739
2080
  let t = Math.floor(e / 1e3);
1740
2081
  if (t < 60) return `${t}s`;
1741
2082
  let n = Math.floor(t / 60);
1742
2083
  return n < 60 ? `${n}m ${t % 60}s` : `${Math.floor(n / 60)}h ${n % 60}m`;
1743
2084
  }
1744
- function Fe(e) {
2085
+ function Z(e) {
1745
2086
  return e < 1024 ? `${e} B` : e < 1048576 ? `${(e / 1024).toFixed(1)} KB` : e < 1073741824 ? `${(e / 1048576).toFixed(1)} MB` : `${(e / 1073741824).toFixed(2)} GB`;
1746
2087
  }
1747
- function Ie({ clients: e, encodedCount: t, onKill: n }) {
1748
- let r = e?.audio ?? [], i = e?.rtsp ?? [], a = e?.encoded ?? [], o = r.length + i.length + a.length, [s, c] = g(!0);
1749
- return o === 0 ? /* @__PURE__ */ y("div", {
2088
+ function Fe({ clients: e, encodedCount: t, onKill: n }) {
2089
+ let { t: r } = z(), i = e?.audio ?? [], a = e?.rtsp ?? [], o = e?.encoded ?? [], s = i.length + a.length + o.length, [c, l] = _(!0);
2090
+ return s === 0 ? /* @__PURE__ */ b("div", {
1750
2091
  className: "mt-1.5 text-[10px] text-foreground-subtle italic",
1751
- children: "No active subscribers"
1752
- }) : /* @__PURE__ */ b("div", {
2092
+ children: r("subscribers.none")
2093
+ }) : /* @__PURE__ */ x("div", {
1753
2094
  className: "mt-1.5 border-t border-border/30 pt-1.5",
1754
- children: [/* @__PURE__ */ b("button", {
2095
+ children: [/* @__PURE__ */ x("button", {
1755
2096
  type: "button",
1756
- onClick: () => c((e) => !e),
2097
+ onClick: () => l((e) => !e),
1757
2098
  className: "flex items-center gap-1 text-[10px] text-foreground-subtle hover:text-foreground transition-colors",
1758
- children: [y(s ? P : F, { className: "h-3 w-3" }), /* @__PURE__ */ b("span", {
2099
+ children: [b(c ? F : I, { className: "h-3 w-3" }), /* @__PURE__ */ b("span", {
1759
2100
  className: "uppercase tracking-wider",
1760
- children: [
1761
- "Subscribers (",
1762
- o,
1763
- ")"
1764
- ]
2101
+ children: r("subscribers.heading", { count: s })
1765
2102
  })]
1766
- }), s && /* @__PURE__ */ b("div", {
2103
+ }), c && /* @__PURE__ */ x("div", {
1767
2104
  className: "mt-1 divide-y divide-border/20",
1768
2105
  children: [
1769
- r.map((e, t) => /* @__PURE__ */ y(Q, {
1770
- kind: "AUDIO",
2106
+ i.map((e, t) => /* @__PURE__ */ b(Q, {
2107
+ kind: r("subscribers.kindAudio"),
1771
2108
  kindClass: "bg-info/10 text-info",
1772
- tag: e.tag || "unknown",
1773
- metrics: [`${e.chunksDelivered} chunks`],
2109
+ tag: e.tag || r("subscribers.unknown"),
2110
+ metrics: [r("subscribers.chunks", { count: e.chunksDelivered })],
1774
2111
  age: Date.now() - e.subscribedAt,
1775
2112
  onKill: n && e.tag ? () => n({
1776
2113
  channel: "audio",
1777
2114
  handle: e.tag
1778
2115
  }) : void 0
1779
2116
  }, `a-${t}`)),
1780
- i.map((e) => {
1781
- let t = Date.now() - e.lastRtpAt, r = t > 5e3, i = e.playing ? r ? "stalled" : "playing" : "paused", a = e.playing ? r ? "bg-amber-400/10 text-amber-400" : "bg-success/10 text-success" : "bg-foreground-subtle/10 text-foreground-subtle";
1782
- return /* @__PURE__ */ y(Q, {
2117
+ a.map((e) => {
2118
+ let t = Date.now() - e.lastRtpAt, i = t > 5e3, a = e.playing ? r(i ? "subscribers.stalled" : "subscribers.playing") : r("subscribers.paused"), o = e.playing ? i ? "bg-amber-400/10 text-amber-400" : "bg-success/10 text-success" : "bg-foreground-subtle/10 text-foreground-subtle";
2119
+ return /* @__PURE__ */ b(Q, {
1783
2120
  kind: "RTSP",
1784
2121
  kindClass: "bg-warning/10 text-warning",
1785
- tag: e.userAgent ? K(e.userAgent) : e.remoteAddr,
2122
+ tag: e.userAgent ? J(e.userAgent) : e.remoteAddr,
1786
2123
  state: {
1787
- text: i + (e.muted ? " · muted" : ""),
1788
- className: a
2124
+ text: e.muted ? r("subscribers.stateMuted", { state: a }) : a,
2125
+ className: o
1789
2126
  },
1790
- metrics: [Fe(e.bytesSent), `last rtp ${Z(t)} ago`],
2127
+ metrics: [Z(e.bytesSent), r("subscribers.lastRtp", { age: X(t) })],
1791
2128
  age: Date.now() - e.connectedAt,
1792
2129
  onKill: n ? () => n({
1793
2130
  channel: "rtsp",
@@ -1795,203 +2132,193 @@ function Ie({ clients: e, encodedCount: t, onKill: n }) {
1795
2132
  }) : void 0
1796
2133
  }, `r-${e.sessionId}`);
1797
2134
  }),
1798
- a.map((e) => {
1799
- let t = e.attribution, n = we[t.kind] ?? "bg-foreground-subtle/10 text-foreground-subtle", r = t.sessionId ? t.sessionId.slice(0, 8) : null, i = [];
1800
- t.label && i.push(t.label), r && i.push(`sess ${r}`), t.userId && i.push(`user ${t.userId.slice(0, 8)}`), t.remoteAddr && i.push(`@${t.remoteAddr}`), t.userAgent && i.push(K(t.userAgent));
1801
- let a = i.length > 0 ? i.join(" · ") : Ee(t.kind), o = [];
1802
- return t.media && o.push({ text: t.media }), t.targetCodec && o.push(t.targetCodec), t.transport && o.push(t.transport), o.push(`${e.packetsDelivered} pkts`), /* @__PURE__ */ y(Q, {
2135
+ o.map((e) => {
2136
+ let t = e.attribution, n = Ce[t.kind] ?? "bg-foreground-subtle/10 text-foreground-subtle", i = t.sessionId ? t.sessionId.slice(0, 8) : null, a = [];
2137
+ t.label && a.push(t.label), i && a.push(r("subscribers.session", { id: i })), t.userId && a.push(r("subscribers.user", { id: t.userId.slice(0, 8) })), t.remoteAddr && a.push(`@${t.remoteAddr}`), t.userAgent && a.push(J(t.userAgent));
2138
+ let o = a.length > 0 ? a.join(" · ") : Ee(t.kind), s = [];
2139
+ return t.media && s.push({ text: t.media }), t.targetCodec && s.push(t.targetCodec), t.transport && s.push(t.transport), s.push(r("subscribers.pkts", { count: e.packetsDelivered })), /* @__PURE__ */ b(Q, {
1803
2140
  kind: Te(t.kind),
1804
2141
  kindClass: n,
1805
- tag: a,
1806
- metrics: o,
2142
+ tag: o,
2143
+ metrics: s,
1807
2144
  age: Date.now() - e.subscribedAt
1808
2145
  }, e.id);
1809
2146
  }),
1810
- a.length === 0 && t > 0 && /* @__PURE__ */ b("div", {
2147
+ o.length === 0 && t > 0 && /* @__PURE__ */ x("div", {
1811
2148
  className: "py-0.5 text-[10px] text-foreground-subtle",
1812
- children: [
1813
- /* @__PURE__ */ y("span", {
1814
- className: "inline-block px-1 rounded text-[9px] font-bold bg-foreground-subtle/10 text-foreground-subtle mr-2",
1815
- children: "ENCODED"
1816
- }),
1817
- t,
1818
- " callback subscriber(s)"
1819
- ]
2149
+ children: [/* @__PURE__ */ b("span", {
2150
+ className: "inline-block px-1 rounded text-[9px] font-bold bg-foreground-subtle/10 text-foreground-subtle mr-2",
2151
+ children: r("subscribers.kindEncoded")
2152
+ }), r("subscribers.callbackCount", { count: t })]
1820
2153
  })
1821
2154
  ]
1822
2155
  })]
1823
2156
  });
1824
2157
  }
1825
2158
  function Q({ kind: e, kindClass: t, tag: n, state: r, metrics: i, age: a, onKill: o }) {
1826
- return /* @__PURE__ */ b("div", {
2159
+ return /* @__PURE__ */ x("div", {
1827
2160
  className: "flex flex-col gap-y-0.5 py-0.5 text-[10px] @[420px]:flex-row @[420px]:items-center @[420px]:gap-2",
1828
2161
  children: [
1829
- /* @__PURE__ */ b("div", {
2162
+ /* @__PURE__ */ x("div", {
1830
2163
  className: "flex items-center gap-2 min-w-0 @[420px]:flex-1",
1831
2164
  children: [
1832
- /* @__PURE__ */ y("span", {
2165
+ /* @__PURE__ */ b("span", {
1833
2166
  className: `inline-block px-1 rounded text-[9px] font-bold shrink-0 w-14 text-center ${t}`,
1834
2167
  children: e
1835
2168
  }),
1836
- /* @__PURE__ */ y("span", {
2169
+ /* @__PURE__ */ b("span", {
1837
2170
  className: "text-foreground font-medium truncate min-w-0 flex-1",
1838
2171
  title: n,
1839
2172
  children: n
1840
2173
  }),
1841
- o && /* @__PURE__ */ y("div", {
2174
+ o && /* @__PURE__ */ b("div", {
1842
2175
  className: "shrink-0 flex items-center justify-end @[420px]:hidden",
1843
- children: /* @__PURE__ */ y($, { onClick: o })
2176
+ children: /* @__PURE__ */ b($, { onClick: o })
1844
2177
  })
1845
2178
  ]
1846
2179
  }),
1847
- /* @__PURE__ */ b("div", {
2180
+ /* @__PURE__ */ x("div", {
1848
2181
  className: "flex items-center flex-wrap gap-1.5 text-foreground-subtle pl-16 @[420px]:pl-0 @[420px]:flex-nowrap @[420px]:shrink-0",
1849
2182
  children: [
1850
- r && /* @__PURE__ */ y("span", {
2183
+ r && /* @__PURE__ */ b("span", {
1851
2184
  className: `text-[9px] px-1 rounded shrink-0 ${r.className}`,
1852
2185
  children: r.text
1853
2186
  }),
1854
- i.map((e, t) => /* @__PURE__ */ b("span", {
2187
+ i.map((e, t) => /* @__PURE__ */ x("span", {
1855
2188
  className: "whitespace-nowrap",
1856
- children: [t > 0 && /* @__PURE__ */ y("span", {
2189
+ children: [t > 0 && /* @__PURE__ */ b("span", {
1857
2190
  className: "mr-1.5 text-foreground-subtle/50",
1858
2191
  children: "·"
1859
- }), typeof e == "string" ? e : /* @__PURE__ */ y("span", {
2192
+ }), typeof e == "string" ? e : /* @__PURE__ */ b("span", {
1860
2193
  className: e.warn ? "text-amber-400" : "",
1861
2194
  children: e.text
1862
2195
  })]
1863
2196
  }, t)),
1864
- /* @__PURE__ */ b("span", {
2197
+ /* @__PURE__ */ x("span", {
1865
2198
  className: "text-foreground-subtle/70 whitespace-nowrap",
1866
- children: ["· ", Z(a)]
2199
+ children: ["· ", X(a)]
1867
2200
  })
1868
2201
  ]
1869
2202
  }),
1870
- /* @__PURE__ */ y("div", {
2203
+ /* @__PURE__ */ b("div", {
1871
2204
  className: "hidden @[420px]:flex w-5 flex-shrink-0 items-center justify-end",
1872
- children: o ? /* @__PURE__ */ y($, { onClick: o }) : null
2205
+ children: o ? /* @__PURE__ */ b($, { onClick: o }) : null
1873
2206
  })
1874
2207
  ]
1875
2208
  });
1876
2209
  }
1877
- function Le({ count: e, clients: t, onKill: n }) {
1878
- let r = t?.audio ?? [], i = t ? t.encodedSubscribers : 0, a = r.length > 0 || i > 0, o = /* @__PURE__ */ y("span", {
1879
- className: `text-foreground ${a ? "underline decoration-dotted decoration-foreground-subtle/50 underline-offset-2 cursor-help" : ""}`,
2210
+ function Ie({ count: e, clients: t, onKill: n }) {
2211
+ let { t: r } = z(), i = t?.audio ?? [], a = t ? t.encodedSubscribers : 0, o = i.length > 0 || a > 0, s = /* @__PURE__ */ b("span", {
2212
+ className: `text-foreground ${o ? "underline decoration-dotted decoration-foreground-subtle/50 underline-offset-2 cursor-help" : ""}`,
1880
2213
  children: e
1881
2214
  });
1882
- return a ? /* @__PURE__ */ y(Pe, {
1883
- trigger: o,
1884
- content: /* @__PURE__ */ b(x, { children: [r.length > 0 && /* @__PURE__ */ b("div", {
2215
+ return o ? /* @__PURE__ */ b(Pe, {
2216
+ trigger: s,
2217
+ content: /* @__PURE__ */ x(S, { children: [i.length > 0 && /* @__PURE__ */ x("div", {
1885
2218
  className: "mb-2",
1886
- children: [/* @__PURE__ */ y("div", {
2219
+ children: [/* @__PURE__ */ b("div", {
1887
2220
  className: "text-foreground-subtle uppercase text-[9px] tracking-wider mb-1",
1888
- children: "Audio subscribers"
1889
- }), r.map((e, t) => /* @__PURE__ */ b("div", {
2221
+ children: r("subscribers.audioHeading")
2222
+ }), i.map((e, t) => /* @__PURE__ */ x("div", {
1890
2223
  className: "flex items-center justify-between gap-2 py-0.5",
1891
- children: [/* @__PURE__ */ y("span", {
2224
+ children: [/* @__PURE__ */ b("span", {
1892
2225
  className: "text-foreground font-medium truncate",
1893
- children: e.tag || "unknown"
1894
- }), /* @__PURE__ */ b("span", {
2226
+ children: e.tag || r("subscribers.unknown")
2227
+ }), /* @__PURE__ */ x("span", {
1895
2228
  className: "text-foreground-subtle text-[9px] flex items-center gap-1.5 shrink-0",
1896
2229
  children: [
1897
- /* @__PURE__ */ b("span", { children: [e.chunksDelivered, " chunks"] }),
1898
- /* @__PURE__ */ y("span", { children: "·" }),
1899
- /* @__PURE__ */ y("span", { children: Z(Date.now() - e.subscribedAt) }),
1900
- n && e.tag && /* @__PURE__ */ y($, { onClick: () => n({
2230
+ /* @__PURE__ */ b("span", { children: r("subscribers.chunks", { count: e.chunksDelivered }) }),
2231
+ /* @__PURE__ */ b("span", { children: "·" }),
2232
+ /* @__PURE__ */ b("span", { children: X(Date.now() - e.subscribedAt) }),
2233
+ n && e.tag && /* @__PURE__ */ b($, { onClick: () => n({
1901
2234
  channel: "audio",
1902
2235
  handle: e.tag
1903
2236
  }) })
1904
2237
  ]
1905
2238
  })]
1906
2239
  }, `a-${t}`))]
1907
- }), i > 0 && /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("div", {
2240
+ }), a > 0 && /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("div", {
1908
2241
  className: "text-foreground-subtle uppercase text-[9px] tracking-wider mb-1",
1909
- children: "Encoded"
2242
+ children: r("subscribers.encodedHeading")
1910
2243
  }), /* @__PURE__ */ b("div", {
1911
2244
  className: "text-foreground",
1912
- children: [i, " callback subscriber(s)"]
2245
+ children: r("subscribers.callbackCount", { count: a })
1913
2246
  })] })] }),
1914
2247
  widthClass: "min-w-[260px] max-w-[360px]"
1915
- }) : o;
2248
+ }) : s;
1916
2249
  }
1917
- function Re({ enabled: e, known: t, onToggle: n, disabled: r }) {
1918
- return /* @__PURE__ */ y("button", {
2250
+ function Le({ enabled: e, known: t, onToggle: n, disabled: r }) {
2251
+ let { t: i } = z();
2252
+ return /* @__PURE__ */ b("button", {
1919
2253
  type: "button",
1920
2254
  role: "switch",
1921
2255
  "aria-checked": t ? e : "mixed",
1922
2256
  disabled: r,
1923
2257
  onClick: () => n(!e),
1924
2258
  className: `relative inline-flex h-3 w-6 shrink-0 items-center rounded-full transition-colors ${t ? e ? "bg-success/60" : "bg-foreground-subtle/30" : "bg-foreground-subtle/20"} ${r ? "opacity-50 cursor-wait" : "cursor-pointer"}`,
1925
- title: t ? e ? "Pre-buffer enabled — click to disable" : "Pre-buffer disabled — click to enable" : "Pre-buffer — loading",
1926
- children: /* @__PURE__ */ y("span", { className: `inline-block h-2.5 w-2.5 rounded-full bg-white shadow transition-transform ${e ? "translate-x-3" : "translate-x-0.5"}` })
2259
+ title: i(t ? e ? "prebuffer.enabled" : "prebuffer.disabled" : "prebuffer.loading"),
2260
+ children: /* @__PURE__ */ b("span", { className: `inline-block h-2.5 w-2.5 rounded-full bg-white shadow transition-transform ${e ? "translate-x-3" : "translate-x-0.5"}` })
1927
2261
  });
1928
2262
  }
1929
2263
  function $({ onClick: e }) {
1930
- return /* @__PURE__ */ y("button", {
2264
+ let { t } = z();
2265
+ return /* @__PURE__ */ b("button", {
1931
2266
  type: "button",
1932
- title: "Force-disconnect this client",
2267
+ title: t("subscribers.kick"),
1933
2268
  onClick: (t) => {
1934
2269
  t.stopPropagation(), e();
1935
2270
  },
1936
2271
  className: "inline-flex items-center justify-center h-4 w-4 rounded-sm border border-border/60 text-foreground-subtle hover:bg-red-500/10 hover:text-red-400 hover:border-red-500/40 transition-colors",
1937
- children: /* @__PURE__ */ y(ae, { className: "h-2.5 w-2.5" })
2272
+ children: /* @__PURE__ */ b(ie, { className: "h-2.5 w-2.5" })
1938
2273
  });
1939
2274
  }
1940
- function ze({ count: e, clients: t, onKill: n }) {
1941
- let r = t?.rtsp ?? [], i = r.length > 0, a = /* @__PURE__ */ y("span", {
1942
- className: `text-foreground ${i ? "underline decoration-dotted decoration-foreground-subtle/50 underline-offset-2 cursor-help" : ""}`,
2275
+ function Re({ count: e, clients: t, onKill: n }) {
2276
+ let { t: r } = z(), i = t?.rtsp ?? [], a = i.length > 0, o = /* @__PURE__ */ b("span", {
2277
+ className: `text-foreground ${a ? "underline decoration-dotted decoration-foreground-subtle/50 underline-offset-2 cursor-help" : ""}`,
1943
2278
  children: e
1944
2279
  });
1945
- return i ? /* @__PURE__ */ y(Pe, {
1946
- trigger: a,
1947
- content: /* @__PURE__ */ b(x, { children: [/* @__PURE__ */ y("div", {
2280
+ return a ? /* @__PURE__ */ b(Pe, {
2281
+ trigger: o,
2282
+ content: /* @__PURE__ */ x(S, { children: [/* @__PURE__ */ b("div", {
1948
2283
  className: "text-foreground-subtle uppercase text-[9px] tracking-wider mb-1",
1949
- children: "RTSP sessions"
1950
- }), r.map((e) => {
1951
- let t = Date.now() - e.lastRtpAt, r = t > 5e3;
1952
- return /* @__PURE__ */ b("div", {
2284
+ children: r("subscribers.rtspHeading")
2285
+ }), i.map((e) => {
2286
+ let t = Date.now() - e.lastRtpAt, i = t > 5e3, a = e.playing ? r(i ? "subscribers.stalled" : "subscribers.playing") : r("subscribers.paused");
2287
+ return /* @__PURE__ */ x("div", {
1953
2288
  className: "py-1 border-b border-border/40 last:border-b-0",
1954
- children: [/* @__PURE__ */ b("div", {
2289
+ children: [/* @__PURE__ */ x("div", {
1955
2290
  className: "flex items-center justify-between gap-2",
1956
- children: [/* @__PURE__ */ y("span", {
2291
+ children: [/* @__PURE__ */ b("span", {
1957
2292
  className: "text-foreground font-mono",
1958
- children: e.userAgent ? K(e.userAgent) : e.remoteAddr
1959
- }), /* @__PURE__ */ b("span", {
2293
+ children: e.userAgent ? J(e.userAgent) : e.remoteAddr
2294
+ }), /* @__PURE__ */ x("span", {
1960
2295
  className: "flex items-center gap-1 shrink-0",
1961
2296
  children: [/* @__PURE__ */ b("span", {
1962
- className: `text-[9px] px-1 rounded ${e.playing ? r ? "bg-amber-400/10 text-amber-400" : "bg-success/10 text-success" : "bg-foreground-subtle/10 text-foreground-subtle"}`,
1963
- children: [e.playing ? r ? "stalled" : "playing" : "paused", e.muted && " · muted"]
1964
- }), n && /* @__PURE__ */ y($, { onClick: () => n({
2297
+ className: `text-[9px] px-1 rounded ${e.playing ? i ? "bg-amber-400/10 text-amber-400" : "bg-success/10 text-success" : "bg-foreground-subtle/10 text-foreground-subtle"}`,
2298
+ children: e.muted ? r("subscribers.stateMuted", { state: a }) : a
2299
+ }), n && /* @__PURE__ */ b($, { onClick: () => n({
1965
2300
  channel: "rtsp",
1966
2301
  handle: e.sessionId
1967
2302
  }) })]
1968
2303
  })]
1969
- }), /* @__PURE__ */ b("div", {
2304
+ }), /* @__PURE__ */ x("div", {
1970
2305
  className: "flex items-center justify-between gap-2 text-foreground-subtle text-[9px] mt-0.5",
1971
2306
  children: [
1972
- /* @__PURE__ */ b("span", { children: [Fe(e.bytesSent), " sent"] }),
1973
- /* @__PURE__ */ b("span", { children: [
1974
- "connected ",
1975
- Z(Date.now() - e.connectedAt),
1976
- " ago"
1977
- ] }),
1978
- /* @__PURE__ */ b("span", { children: [
1979
- "last rtp ",
1980
- Z(t),
1981
- " ago"
1982
- ] })
2307
+ /* @__PURE__ */ b("span", { children: r("subscribers.sent", { bytes: Z(e.bytesSent) }) }),
2308
+ /* @__PURE__ */ b("span", { children: r("subscribers.connected", { age: X(Date.now() - e.connectedAt) }) }),
2309
+ /* @__PURE__ */ b("span", { children: r("subscribers.lastRtp", { age: X(t) }) })
1983
2310
  ]
1984
2311
  })]
1985
2312
  }, e.sessionId);
1986
2313
  })] }),
1987
2314
  widthClass: "min-w-[300px] max-w-[420px]"
1988
- }) : a;
2315
+ }) : o;
1989
2316
  }
1990
2317
  //#endregion
1991
2318
  //#region src/stream-broker/widgets/index.tsx
1992
- var Be = {
2319
+ var ze = {
1993
2320
  "stream-broker-panel": De,
1994
- "ffmpeg-params": he
2321
+ "ffmpeg-params": me
1995
2322
  };
1996
2323
  //#endregion
1997
- export { Be as default };
2324
+ export { ze as default };