@camstack/addon-pipeline 1.2.270 → 1.2.271

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 (33) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-BfMsW_XK.js → default-detection-model-CnHXu0T5.js} +1 -1
  4. package/dist/{default-detection-model-pXamampo.mjs → default-detection-model-DMz2NcwC.mjs} +1 -1
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-Cqf-U6EN.mjs → dist-D6TktSdc.mjs} +21 -0
  8. package/dist/{dist-CkNVb7Zh.js → dist-omV46PMG.js} +21 -0
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-CqC8R84-.js → node-1Ai8jl-y.js} +53 -1
  12. package/dist/{node-jLmcbaar.mjs → node-BR1TKkR_.mjs} +53 -1
  13. package/dist/pipeline-runner/index.js +3 -3
  14. package/dist/pipeline-runner/index.mjs +3 -3
  15. package/dist/{process-memory-D7LlWXty.js → process-memory-CzAXrCOa.js} +1 -1
  16. package/dist/{process-memory-B1YHg1_g.mjs → process-memory-DL3690gA.mjs} +1 -1
  17. package/dist/recorder/index.js +24 -7
  18. package/dist/recorder/index.mjs +24 -7
  19. package/dist/{segment-demux-js-Bu-_Q7Um.js → segment-demux-js-D8bD_LBq.js} +1 -1
  20. package/dist/{segment-demux-js-B2TLcR_g.mjs → segment-demux-js-Zm-FyEl6.mjs} +1 -1
  21. package/dist/stream-broker/_stub.js +1 -1
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DZlxPoTV.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-MI6wy_av.mjs} +2 -2
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-GublMTFG.mjs +26 -0
  24. package/dist/stream-broker/demux-worker-child.js +1 -1
  25. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  26. package/dist/stream-broker/{hostInit-DFerKhvZ.mjs → hostInit-D51BPmpl.mjs} +2 -2
  27. package/dist/stream-broker/index.js +3 -3
  28. package/dist/stream-broker/index.mjs +3 -3
  29. package/dist/stream-broker/remoteEntry.js +1 -1
  30. package/package.json +1 -1
  31. package/python/inference_pool.py +163 -34
  32. package/python/test_inference_pool_cache_lock.py +185 -0
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DJVznXRG.mjs +0 -26
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CkNVb7Zh.js");
7
- const require_process_memory = require("../process-memory-D7LlWXty.js");
6
+ const require_dist = require("../dist-omV46PMG.js");
7
+ const require_process_memory = require("../process-memory-CzAXrCOa.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
10
10
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-Cqf-U6EN.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-B1YHg1_g.mjs";
2
+ import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-D6TktSdc.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DL3690gA.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CkNVb7Zh.js");
1
+ const require_dist = require("./dist-omV46PMG.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-Cqf-U6EN.mjs";
1
+ import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-D6TktSdc.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CkNVb7Zh.js");
7
- const require_node = require("../node-CqC8R84-.js");
8
- const require_default_detection_model = require("../default-detection-model-BfMsW_XK.js");
6
+ const require_dist = require("../dist-omV46PMG.js");
7
+ const require_node = require("../node-1Ai8jl-y.js");
8
+ const require_default_detection_model = require("../default-detection-model-CnHXu0T5.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-D7LlWXty.js");
10
+ const require_process_memory = require("../process-memory-CzAXrCOa.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-Cqf-U6EN.mjs";
3
- import { s as readProcessCost } from "../node-jLmcbaar.mjs";
4
- import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-pXamampo.mjs";
2
+ import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-D6TktSdc.mjs";
3
+ import { s as readProcessCost } from "../node-BR1TKkR_.mjs";
4
+ import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-DMz2NcwC.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-B1YHg1_g.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DL3690gA.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -8943,6 +8943,7 @@ var CameraSwitchIdSchema = _enum([
8943
8943
  "device-audio",
8944
8944
  "broker-audio",
8945
8945
  "audio-analysis",
8946
+ "event-saving",
8946
8947
  "recording",
8947
8948
  "notifications"
8948
8949
  ]);
@@ -9425,11 +9426,31 @@ var RecordingBandTriggersSchema = RecordingTriggersSchema;
9425
9426
  * band engine's `applies` rule). `start`/`end` are `HH:MM`; an `end <= start`
9426
9427
  * span wraps past midnight (handled by the band engine).
9427
9428
  */
9429
+ /**
9430
+ * Whether a band's footage carries sound.
9431
+ *
9432
+ * The recorder has always attached with `audio: 'aac'`, so every band of every
9433
+ * camera recorded sound whether anyone wanted it or not. The broker already
9434
+ * serves the other answer — `audio: 'none'` takes the video-only `/muted`
9435
+ * restream — so this was a choice the product could always have offered.
9436
+ *
9437
+ * It belongs on the BAND rather than the camera because one camera can want
9438
+ * both: silent across the shop floor during opening hours, sound overnight.
9439
+ * And it applies to BOTH modes — an events band firing on motion has the same
9440
+ * question to answer as a continuous one.
9441
+ */
9442
+ var RecordingBandAudioSchema = _enum(["on", "muted"]);
9428
9443
  var RecordingBandSchema = object({
9429
9444
  days: array(RecordingWeekdaySchema),
9430
9445
  start: string().regex(HHMM),
9431
9446
  end: string().regex(HHMM),
9432
9447
  mode: RecordingBandModeSchema,
9448
+ /**
9449
+ * Sound, or silence. OPTIONAL and absent-means-`on`: every recording
9450
+ * written before this existed carried sound, and a band whose key is
9451
+ * missing must keep meaning what it meant. See {@link RecordingBandAudioSchema}.
9452
+ */
9453
+ audio: RecordingBandAudioSchema.optional(),
9433
9454
  triggers: RecordingBandTriggersSchema.optional(),
9434
9455
  /**
9435
9456
  * RETIRED (D381). A band no longer carries a pre-buffer of its own.
@@ -8943,6 +8943,7 @@ var CameraSwitchIdSchema = _enum([
8943
8943
  "device-audio",
8944
8944
  "broker-audio",
8945
8945
  "audio-analysis",
8946
+ "event-saving",
8946
8947
  "recording",
8947
8948
  "notifications"
8948
8949
  ]);
@@ -9425,11 +9426,31 @@ var RecordingBandTriggersSchema = RecordingTriggersSchema;
9425
9426
  * band engine's `applies` rule). `start`/`end` are `HH:MM`; an `end <= start`
9426
9427
  * span wraps past midnight (handled by the band engine).
9427
9428
  */
9429
+ /**
9430
+ * Whether a band's footage carries sound.
9431
+ *
9432
+ * The recorder has always attached with `audio: 'aac'`, so every band of every
9433
+ * camera recorded sound whether anyone wanted it or not. The broker already
9434
+ * serves the other answer — `audio: 'none'` takes the video-only `/muted`
9435
+ * restream — so this was a choice the product could always have offered.
9436
+ *
9437
+ * It belongs on the BAND rather than the camera because one camera can want
9438
+ * both: silent across the shop floor during opening hours, sound overnight.
9439
+ * And it applies to BOTH modes — an events band firing on motion has the same
9440
+ * question to answer as a continuous one.
9441
+ */
9442
+ var RecordingBandAudioSchema = _enum(["on", "muted"]);
9428
9443
  var RecordingBandSchema = object({
9429
9444
  days: array(RecordingWeekdaySchema),
9430
9445
  start: string().regex(HHMM),
9431
9446
  end: string().regex(HHMM),
9432
9447
  mode: RecordingBandModeSchema,
9448
+ /**
9449
+ * Sound, or silence. OPTIONAL and absent-means-`on`: every recording
9450
+ * written before this existed carried sound, and a band whose key is
9451
+ * missing must keep meaning what it meant. See {@link RecordingBandAudioSchema}.
9452
+ */
9453
+ audio: RecordingBandAudioSchema.optional(),
9433
9454
  triggers: RecordingBandTriggersSchema.optional(),
9434
9455
  /**
9435
9456
  * RETIRED (D381). A band no longer carries a pre-buffer of its own.
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-CkNVb7Zh.js");
5
+ const require_dist = require("../dist-omV46PMG.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-Cqf-U6EN.mjs";
1
+ import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-D6TktSdc.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CkNVb7Zh.js");
2
+ const require_dist = require("./dist-omV46PMG.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_chunk.__toESM(node_fs, 1);
@@ -115,6 +115,58 @@ async function probeFfmpegBinary(path) {
115
115
  ]);
116
116
  return parseFfmpegCapabilities(path, versionOut, hwaccelOut, encoderOut);
117
117
  }
118
+ /**
119
+ * The ffmpeg build every CamStack node downloads, per platform and arch.
120
+ *
121
+ * ## Why a download, on every node, including the container
122
+ *
123
+ * The version of ffmpeg used to be CODE: baked into the image, changeable only
124
+ * by rebuilding and rolling it. Now it is DATA — this file states the release,
125
+ * and a node that boots with a different one downloads it. Changing ffmpeg is a
126
+ * framework bump, not an image rebuild.
127
+ *
128
+ * It also settles the licence question by removing it. FFmpeg's licence is
129
+ * chosen at compile time: the core is LGPL 2.1+, `--enable-gpl` makes it GPL
130
+ * (for x264/x265), `--enable-version3` makes that v3, and `--enable-nonfree`
131
+ * makes the result undistributable. These are GPL v3 builds, and we do not
132
+ * distribute them: the user's own node fetches the archive from the project
133
+ * that publishes it, so we convey no GPL work and inherit none of the
134
+ * obligations that come with conveying one. That is the whole reason the image
135
+ * no longer installs ffmpeg at all — not a technical preference.
136
+ *
137
+ * ## Why jellyfin-ffmpeg
138
+ *
139
+ * One vendor covering linux-amd64, linux-arm64, darwin-arm64 and darwin-x64
140
+ * from one release, with the widest hardware surface of anything maintained:
141
+ * VAAPI, QSV, NVENC/NVDEC, AMF, Vulkan, OpenCL and DRM on amd64, plus Rockchip
142
+ * MPP on arm64. It reaches the vendor libraries through dlopen trampolines,
143
+ * so the binary is not linked against a driver stack it may not find.
144
+ *
145
+ * **What it still needs from the host, measured 2026-09-19.** On the Unraid
146
+ * HOST, which has no libva, `-vaapi_device` aborts the process outright —
147
+ * `implib-gen: libva-drm.so.2: failed to load library ... Assertion '0 &&
148
+ * "Assertion in generated code"' failed`. Inside our container, which installs
149
+ * libva plus the iHD driver, the same command encodes: verified end to end with
150
+ * `testsrc → format=nv12,hwupload → h264_vaapi`. So the image drops ffmpeg and
151
+ * KEEPS the Intel media stack; the drivers are the part a binary cannot bring.
152
+ *
153
+ * ## Why each artifact carries a checksum and a claim
154
+ *
155
+ * The download is now the only source, so `sha256` is verified before anything
156
+ * is extracted — jellyfin publishes no checksums on its release assets, so
157
+ * these are ours, taken at the version bump. And `expectedHwaccels` is what the
158
+ * build is supposed to be able to do: a binary that probes short of its own
159
+ * claim is a source that changed under us, which is precisely what went
160
+ * unnoticed for months when a static build turned out to carry no VAAPI at all
161
+ * (D536).
162
+ */
163
+ /** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
164
+ var FFMPEG_RELEASE = "8.1.2-5";
165
+ var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
166
+ function portable(target) {
167
+ return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
168
+ }
169
+ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
118
170
  var DEFAULT_FIRST_UNIT_TIMEOUT_MS = 12e3;
119
171
  /** Heartbeat cadence — ~2 minutes of 4 s fragments. */
120
172
  var FRAGMENT_LOG_EVERY = 30;
@@ -1,4 +1,4 @@
1
- import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-Cqf-U6EN.mjs";
1
+ import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-D6TktSdc.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -112,6 +112,58 @@ async function probeFfmpegBinary(path) {
112
112
  ]);
113
113
  return parseFfmpegCapabilities(path, versionOut, hwaccelOut, encoderOut);
114
114
  }
115
+ /**
116
+ * The ffmpeg build every CamStack node downloads, per platform and arch.
117
+ *
118
+ * ## Why a download, on every node, including the container
119
+ *
120
+ * The version of ffmpeg used to be CODE: baked into the image, changeable only
121
+ * by rebuilding and rolling it. Now it is DATA — this file states the release,
122
+ * and a node that boots with a different one downloads it. Changing ffmpeg is a
123
+ * framework bump, not an image rebuild.
124
+ *
125
+ * It also settles the licence question by removing it. FFmpeg's licence is
126
+ * chosen at compile time: the core is LGPL 2.1+, `--enable-gpl` makes it GPL
127
+ * (for x264/x265), `--enable-version3` makes that v3, and `--enable-nonfree`
128
+ * makes the result undistributable. These are GPL v3 builds, and we do not
129
+ * distribute them: the user's own node fetches the archive from the project
130
+ * that publishes it, so we convey no GPL work and inherit none of the
131
+ * obligations that come with conveying one. That is the whole reason the image
132
+ * no longer installs ffmpeg at all — not a technical preference.
133
+ *
134
+ * ## Why jellyfin-ffmpeg
135
+ *
136
+ * One vendor covering linux-amd64, linux-arm64, darwin-arm64 and darwin-x64
137
+ * from one release, with the widest hardware surface of anything maintained:
138
+ * VAAPI, QSV, NVENC/NVDEC, AMF, Vulkan, OpenCL and DRM on amd64, plus Rockchip
139
+ * MPP on arm64. It reaches the vendor libraries through dlopen trampolines,
140
+ * so the binary is not linked against a driver stack it may not find.
141
+ *
142
+ * **What it still needs from the host, measured 2026-09-19.** On the Unraid
143
+ * HOST, which has no libva, `-vaapi_device` aborts the process outright —
144
+ * `implib-gen: libva-drm.so.2: failed to load library ... Assertion '0 &&
145
+ * "Assertion in generated code"' failed`. Inside our container, which installs
146
+ * libva plus the iHD driver, the same command encodes: verified end to end with
147
+ * `testsrc → format=nv12,hwupload → h264_vaapi`. So the image drops ffmpeg and
148
+ * KEEPS the Intel media stack; the drivers are the part a binary cannot bring.
149
+ *
150
+ * ## Why each artifact carries a checksum and a claim
151
+ *
152
+ * The download is now the only source, so `sha256` is verified before anything
153
+ * is extracted — jellyfin publishes no checksums on its release assets, so
154
+ * these are ours, taken at the version bump. And `expectedHwaccels` is what the
155
+ * build is supposed to be able to do: a binary that probes short of its own
156
+ * claim is a source that changed under us, which is precisely what went
157
+ * unnoticed for months when a static build turned out to carry no VAAPI at all
158
+ * (D536).
159
+ */
160
+ /** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
161
+ var FFMPEG_RELEASE = "8.1.2-5";
162
+ var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
163
+ function portable(target) {
164
+ return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
165
+ }
166
+ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
115
167
  var DEFAULT_FIRST_UNIT_TIMEOUT_MS = 12e3;
116
168
  /** Heartbeat cadence — ~2 minutes of 4 s fragments. */
117
169
  var FRAGMENT_LOG_EVERY = 30;
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CkNVb7Zh.js");
7
- const require_node = require("../node-CqC8R84-.js");
8
- const require_default_detection_model = require("../default-detection-model-BfMsW_XK.js");
6
+ const require_dist = require("../dist-omV46PMG.js");
7
+ const require_node = require("../node-1Ai8jl-y.js");
8
+ const require_default_detection_model = require("../default-detection-model-CnHXu0T5.js");
9
9
  const require_worker_protocol = require("../worker-protocol-B2MfQLlu.js");
10
10
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
11
11
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
@@ -1,6 +1,6 @@
1
- import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-Cqf-U6EN.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-jLmcbaar.mjs";
3
- import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-pXamampo.mjs";
1
+ import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-D6TktSdc.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BR1TKkR_.mjs";
3
+ import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-DMz2NcwC.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-C_W-P_g-.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CkNVb7Zh.js");
2
+ const require_dist = require("./dist-omV46PMG.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { mt as parseProcStatus } from "./dist-Cqf-U6EN.mjs";
1
+ import { mt as parseProcStatus } from "./dist-D6TktSdc.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CkNVb7Zh.js");
7
- const require_node = require("../node-CqC8R84-.js");
6
+ const require_dist = require("../dist-omV46PMG.js");
7
+ const require_node = require("../node-1Ai8jl-y.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
@@ -13832,6 +13832,20 @@ function eventsBandDemanded(band, triggers, atMs) {
13832
13832
  });
13833
13833
  }
13834
13834
  /**
13835
+ * With sound, or silent, if we record at `at`?
13836
+ *
13837
+ * NOT a recording decision — `shouldRecordAt` owns that. This answers only
13838
+ * how the footage should sound, and the safe answer to a question nobody
13839
+ * configured is the one that loses no evidence: `on`, which is byte-for-byte
13840
+ * what every band did before the key existed.
13841
+ */
13842
+ function bandAudioAt(config, at) {
13843
+ if (!config.enabled) return "on";
13844
+ const bands = effectiveBands(config);
13845
+ if (bands.length === 0) return "on";
13846
+ return activeBandAt({ bands }, at)?.audio ?? "on";
13847
+ }
13848
+ /**
13835
13849
  * Should recording (any mode) be active for this device at `at`? The live
13836
13850
  * attach/detach gate: enabled + a band covers `at` + that band demands now
13837
13851
  * (continuous always; events within `postBufferSec` of a qualifying trigger).
@@ -16277,10 +16291,11 @@ var RecordingController = class {
16277
16291
  const profiles = await this.resolveProfiles(deviceId, config.profiles);
16278
16292
  if (profiles.length === 0) throw new Error(`recorder controller: no assigned broker sources for device ${deviceId}`);
16279
16293
  const segmentSeconds = config.segmentSeconds ?? this.deps.segmentSeconds;
16294
+ const bandAudio = bandAudioAt(config, new Date(this.now()));
16280
16295
  const recordings = [];
16281
16296
  const failed = [];
16282
16297
  for (const profile of profiles) try {
16283
- recordings.push(await this.attachProfile(deviceId, profile, segmentSeconds));
16298
+ recordings.push(await this.attachProfile(deviceId, profile, segmentSeconds, bandAudio));
16284
16299
  } catch (err) {
16285
16300
  failed.push(profile);
16286
16301
  this.deps.logger.warn("recorder: profile attach failed — recording the remaining profiles", {
@@ -16343,6 +16358,7 @@ var RecordingController = class {
16343
16358
  }
16344
16359
  const have = new Set(current.map((r) => r.profile));
16345
16360
  const segmentSeconds = config.segmentSeconds ?? this.deps.segmentSeconds;
16361
+ const bandAudio = bandAudioAt(config, new Date(this.now()));
16346
16362
  const added = [];
16347
16363
  for (const profile of [...skipped]) {
16348
16364
  if (have.has(profile)) {
@@ -16350,7 +16366,7 @@ var RecordingController = class {
16350
16366
  continue;
16351
16367
  }
16352
16368
  try {
16353
- added.push(await this.attachProfile(deviceId, profile, segmentSeconds));
16369
+ added.push(await this.attachProfile(deviceId, profile, segmentSeconds, bandAudio));
16354
16370
  skipped.delete(profile);
16355
16371
  } catch (err) {
16356
16372
  this.deps.logger.warn("recorder: profile attach retry failed — keeping the healthy profiles", {
@@ -16395,13 +16411,13 @@ var RecordingController = class {
16395
16411
  * {@link STAGING_DIR_NAME}), spawn the SegmentWriter, and start the watcher
16396
16412
  * that feeds finalized flat segments into `SegmentStore.onFinalized`.
16397
16413
  */
16398
- async attachProfile(deviceId, profile, segmentSeconds) {
16414
+ async attachProfile(deviceId, profile, segmentSeconds, audio) {
16399
16415
  const attachProfileStartMs = this.now();
16400
16416
  const placement = await this.resolvePlacement(deviceId, profile);
16401
16417
  const source = await this.deps.brokerCall(() => withDeadline(this.deps.api.streamBroker.getStreamWithCodec.mutate({
16402
16418
  deviceId,
16403
16419
  video: "copy",
16404
- audio: "aac",
16420
+ audio: audio === "muted" ? "none" : "aac",
16405
16421
  profile,
16406
16422
  ...this.deps.consumerHostname !== void 0 ? { hostname: this.deps.consumerHostname } : {},
16407
16423
  tag: `recorder:${deviceId}/${profile}`
@@ -16497,7 +16513,8 @@ var RecordingController = class {
16497
16513
  }),
16498
16514
  pipelineKey: source.pipelineKey,
16499
16515
  outDir,
16500
- segmentSeconds
16516
+ segmentSeconds,
16517
+ audio
16501
16518
  };
16502
16519
  }
16503
16520
  /**
@@ -1,5 +1,5 @@
1
- import { $t as hydrateSchema, C as OpsLogEntrySchema, Ct as recordingExportCapability, D as RECORDING_EXPORT_MAX_READ_BYTES, Dt as resolveLocationMode, H as deriveBatteryPresence, I as batteryCapability, Kt as DeviceFeature, Lt as errMsg, Mt as storageOccupancyCapability, O as RecordingConfigSchema, Pt as stripRetiredBandPreBufferSec, Q as evictionPolicyOfLocation, St as recordingCapability, W as deriveRecordingMode, Wt as BaseAddon, Xt as customAction, Y as evaluateSensorEdge, Z as evictionPolicyForMode, Zt as defineCustomActions, _n as record, bn as EventCategory, cn as _enum, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dt as modeMayWrite, et as gbToBytes, g as ExportRecordSchema, gn as preprocess, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, jt as storageEvictableCapability, k as RecordingSignalStatusSchema, kt as resolveRecordingProfiles, ln as array, lt as mayWriteToLocation, mn as number, on as selectAssignedProfileSlots, qt as DeviceType, rn as nodePin, rt as isFirstLevelMacroClass, sn as sleep$1, un as boolean, ut as migrateLegacyDeviceSignalConfig, vn as string, wt as recordingSignalCapability } from "../dist-Cqf-U6EN.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-jLmcbaar.mjs";
1
+ import { $t as hydrateSchema, C as OpsLogEntrySchema, Ct as recordingExportCapability, D as RECORDING_EXPORT_MAX_READ_BYTES, Dt as resolveLocationMode, H as deriveBatteryPresence, I as batteryCapability, Kt as DeviceFeature, Lt as errMsg, Mt as storageOccupancyCapability, O as RecordingConfigSchema, Pt as stripRetiredBandPreBufferSec, Q as evictionPolicyOfLocation, St as recordingCapability, W as deriveRecordingMode, Wt as BaseAddon, Xt as customAction, Y as evaluateSensorEdge, Z as evictionPolicyForMode, Zt as defineCustomActions, _n as record, bn as EventCategory, cn as _enum, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dt as modeMayWrite, et as gbToBytes, g as ExportRecordSchema, gn as preprocess, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, jt as storageEvictableCapability, k as RecordingSignalStatusSchema, kt as resolveRecordingProfiles, ln as array, lt as mayWriteToLocation, mn as number, on as selectAssignedProfileSlots, qt as DeviceType, rn as nodePin, rt as isFirstLevelMacroClass, sn as sleep$1, un as boolean, ut as migrateLegacyDeviceSignalConfig, vn as string, wt as recordingSignalCapability } from "../dist-D6TktSdc.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BR1TKkR_.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { d as PREBUFFER_MAX_MS, l as withRecordingIntent, r as RECORDING_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
@@ -13825,6 +13825,20 @@ function eventsBandDemanded(band, triggers, atMs) {
13825
13825
  });
13826
13826
  }
13827
13827
  /**
13828
+ * With sound, or silent, if we record at `at`?
13829
+ *
13830
+ * NOT a recording decision — `shouldRecordAt` owns that. This answers only
13831
+ * how the footage should sound, and the safe answer to a question nobody
13832
+ * configured is the one that loses no evidence: `on`, which is byte-for-byte
13833
+ * what every band did before the key existed.
13834
+ */
13835
+ function bandAudioAt(config, at) {
13836
+ if (!config.enabled) return "on";
13837
+ const bands = effectiveBands(config);
13838
+ if (bands.length === 0) return "on";
13839
+ return activeBandAt({ bands }, at)?.audio ?? "on";
13840
+ }
13841
+ /**
13828
13842
  * Should recording (any mode) be active for this device at `at`? The live
13829
13843
  * attach/detach gate: enabled + a band covers `at` + that band demands now
13830
13844
  * (continuous always; events within `postBufferSec` of a qualifying trigger).
@@ -16270,10 +16284,11 @@ var RecordingController = class {
16270
16284
  const profiles = await this.resolveProfiles(deviceId, config.profiles);
16271
16285
  if (profiles.length === 0) throw new Error(`recorder controller: no assigned broker sources for device ${deviceId}`);
16272
16286
  const segmentSeconds = config.segmentSeconds ?? this.deps.segmentSeconds;
16287
+ const bandAudio = bandAudioAt(config, new Date(this.now()));
16273
16288
  const recordings = [];
16274
16289
  const failed = [];
16275
16290
  for (const profile of profiles) try {
16276
- recordings.push(await this.attachProfile(deviceId, profile, segmentSeconds));
16291
+ recordings.push(await this.attachProfile(deviceId, profile, segmentSeconds, bandAudio));
16277
16292
  } catch (err) {
16278
16293
  failed.push(profile);
16279
16294
  this.deps.logger.warn("recorder: profile attach failed — recording the remaining profiles", {
@@ -16336,6 +16351,7 @@ var RecordingController = class {
16336
16351
  }
16337
16352
  const have = new Set(current.map((r) => r.profile));
16338
16353
  const segmentSeconds = config.segmentSeconds ?? this.deps.segmentSeconds;
16354
+ const bandAudio = bandAudioAt(config, new Date(this.now()));
16339
16355
  const added = [];
16340
16356
  for (const profile of [...skipped]) {
16341
16357
  if (have.has(profile)) {
@@ -16343,7 +16359,7 @@ var RecordingController = class {
16343
16359
  continue;
16344
16360
  }
16345
16361
  try {
16346
- added.push(await this.attachProfile(deviceId, profile, segmentSeconds));
16362
+ added.push(await this.attachProfile(deviceId, profile, segmentSeconds, bandAudio));
16347
16363
  skipped.delete(profile);
16348
16364
  } catch (err) {
16349
16365
  this.deps.logger.warn("recorder: profile attach retry failed — keeping the healthy profiles", {
@@ -16388,13 +16404,13 @@ var RecordingController = class {
16388
16404
  * {@link STAGING_DIR_NAME}), spawn the SegmentWriter, and start the watcher
16389
16405
  * that feeds finalized flat segments into `SegmentStore.onFinalized`.
16390
16406
  */
16391
- async attachProfile(deviceId, profile, segmentSeconds) {
16407
+ async attachProfile(deviceId, profile, segmentSeconds, audio) {
16392
16408
  const attachProfileStartMs = this.now();
16393
16409
  const placement = await this.resolvePlacement(deviceId, profile);
16394
16410
  const source = await this.deps.brokerCall(() => withDeadline(this.deps.api.streamBroker.getStreamWithCodec.mutate({
16395
16411
  deviceId,
16396
16412
  video: "copy",
16397
- audio: "aac",
16413
+ audio: audio === "muted" ? "none" : "aac",
16398
16414
  profile,
16399
16415
  ...this.deps.consumerHostname !== void 0 ? { hostname: this.deps.consumerHostname } : {},
16400
16416
  tag: `recorder:${deviceId}/${profile}`
@@ -16490,7 +16506,8 @@ var RecordingController = class {
16490
16506
  }),
16491
16507
  pipelineKey: source.pipelineKey,
16492
16508
  outDir,
16493
- segmentSeconds
16509
+ segmentSeconds,
16510
+ audio
16494
16511
  };
16495
16512
  }
16496
16513
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CkNVb7Zh.js");
2
+ const require_dist = require("./dist-omV46PMG.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
5
5
  var require_mp4box_all = /* @__PURE__ */ require_chunk.__commonJSMin(((exports) => {
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { Lt as errMsg } from "./dist-Cqf-U6EN.mjs";
2
+ import { Lt as errMsg } from "./dist-D6TktSdc.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
5
5
  var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -1,7 +1,7 @@
1
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-CeR_IxxU.mjs";
2
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
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-DJVznXRG.mjs";
4
+ import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-GublMTFG.mjs";
5
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";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
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) => {
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.227",
21
+ version: "1.2.231",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.182",
36
+ version: "1.2.189",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",