@camstack/addon-pipeline 1.2.320 → 1.2.323
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.
- package/dist/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/{default-detection-model-CO4pZxbd.js → default-detection-model-3nybzgJM.js} +1 -1
- package/dist/{default-detection-model-B-iMtrXt.mjs → default-detection-model-BbGqKJrb.mjs} +1 -1
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-Bce5_ocm.js → dist-BHwYsqDW.js} +3251 -2624
- package/dist/{dist-BK-pWZzI.mjs → dist-CYhfylbW.mjs} +3251 -2624
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-UJwLVGTT.js → node-BPEcDS3W.js} +1 -1
- package/dist/{node-DQsiK6Vt.mjs → node-KuSWIyX-.mjs} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-Cn3QEo37.mjs → process-memory-BArnBFK7.mjs} +1 -1
- package/dist/{process-memory-DR7jI54j.js → process-memory-Maylk0nL.js} +1 -1
- package/dist/recorder/index.js +191 -8
- package/dist/recorder/index.mjs +191 -8
- package/dist/{segment-demux-js-CbazlBOP.js → segment-demux-js-FYxZEbrp.js} +1 -1
- package/dist/{segment-demux-js-CTMbCGRL.mjs → segment-demux-js-am2ssLJA.mjs} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DP4h-J_V.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-XTH7Q8hm.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bm0eNLm_.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-mEJkrfvj.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-CnrH7DvQ.mjs → hostInit-CgW4I0dG.mjs} +2 -2
- package/dist/stream-broker/index.js +47 -13
- package/dist/stream-broker/index.mjs +47 -13
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BAYDyjOG.mjs +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-DHNf76xj.mjs +0 -26
|
@@ -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-
|
|
5
|
+
const require_dist = require("../dist-BHwYsqDW.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 { Sn as hydrateSchema, ct as evaluateZoneRules, dn as DeviceType, kt as motionDetectionCapability, mn as BaseAddon } from "../dist-
|
|
1
|
+
import { Sn as hydrateSchema, ct as evaluateZoneRules, dn as DeviceType, kt as motionDetectionCapability, mn as BaseAddon } from "../dist-CYhfylbW.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-
|
|
2
|
+
const require_dist = require("./dist-BHwYsqDW.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);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { an as Fmp4BoxSplitter, fn as errMsg, ln as isSoftwareDecode, on as buildFfmpegArgs } from "./dist-
|
|
1
|
+
import { an as Fmp4BoxSplitter, fn as errMsg, ln as isSoftwareDecode, on as buildFfmpegArgs } from "./dist-CYhfylbW.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -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-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_default_detection_model = require("../default-detection-model-
|
|
6
|
+
const require_dist = require("../dist-BHwYsqDW.js");
|
|
7
|
+
const require_node = require("../node-BPEcDS3W.js");
|
|
8
|
+
const require_default_detection_model = require("../default-detection-model-3nybzgJM.js");
|
|
9
9
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
10
10
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
11
11
|
const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as NativeLeaseAdmissionSchema, En as nodePin, Fn as lazy, In as literal, It as pipelineRunnerCapability, Ln as number, Mn as array, Nn as boolean, Nt as pickDetailCropConvention, O as NativeLeaseSettingsSchema, Pt as pickNativeLeaseOverride, Rn as object, Un as EventCategory, Vn as string, a as BackgroundRunRegistry, bn as defineCustomActions, bt as loadContributionCapability, fn as errMsg, ft as failureContributionCapability, g as DEFAULT_DETAIL_CROP_CONVENTION, jn as _enum, mn as BaseAddon, nt as deriveDetailCropRect, q as cameraOwnsMotionViaSensor, v as DEFAULT_NATIVE_LEASE_SETTINGS, vn as createEvent, w as FailureCounters, yn as customAction } from "../dist-
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import { b as RETIRED_MODEL_IDS, c as macroGateVerdict, d as isSessionDecodeReadGone, f as createSessionDecodeCoordinator, l as rootObjectGate, o as placeDetailStep, p as resolveFrameViewGeometry, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as getStepDefinition } from "../default-detection-model-
|
|
1
|
+
import { D as NativeLeaseAdmissionSchema, En as nodePin, Fn as lazy, In as literal, It as pipelineRunnerCapability, Ln as number, Mn as array, Nn as boolean, Nt as pickDetailCropConvention, O as NativeLeaseSettingsSchema, Pt as pickNativeLeaseOverride, Rn as object, Un as EventCategory, Vn as string, a as BackgroundRunRegistry, bn as defineCustomActions, bt as loadContributionCapability, fn as errMsg, ft as failureContributionCapability, g as DEFAULT_DETAIL_CROP_CONVENTION, jn as _enum, mn as BaseAddon, nt as deriveDetailCropRect, q as cameraOwnsMotionViaSensor, v as DEFAULT_NATIVE_LEASE_SETTINGS, vn as createEvent, w as FailureCounters, yn as customAction } from "../dist-CYhfylbW.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-KuSWIyX-.mjs";
|
|
3
|
+
import { b as RETIRED_MODEL_IDS, c as macroGateVerdict, d as isSessionDecodeReadGone, f as createSessionDecodeCoordinator, l as rootObjectGate, o as placeDetailStep, p as resolveFrameViewGeometry, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as getStepDefinition } from "../default-detection-model-BbGqKJrb.mjs";
|
|
4
4
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
6
6
|
import { c as withDetectionIntent, o as preRollRequestOf, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BHwYsqDW.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");
|
package/dist/recorder/index.js
CHANGED
|
@@ -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-
|
|
7
|
-
const require_node = require("../node-
|
|
6
|
+
const require_dist = require("../dist-BHwYsqDW.js");
|
|
7
|
+
const require_node = require("../node-BPEcDS3W.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");
|
|
@@ -6025,12 +6025,18 @@ Object.freeze({
|
|
|
6025
6025
|
"lookbackMinutes": 60
|
|
6026
6026
|
}
|
|
6027
6027
|
},
|
|
6028
|
-
"osd-manager": {
|
|
6029
|
-
"
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6028
|
+
"osd-manager": {
|
|
6029
|
+
"setSlotBinding": { "binding": { "__nested__": {
|
|
6030
|
+
"enabled": true,
|
|
6031
|
+
"template": "${value}",
|
|
6032
|
+
"maxDecimals": 1,
|
|
6033
|
+
"fallbackText": ""
|
|
6034
|
+
} } },
|
|
6035
|
+
"upsertTemplate": { "template": { "__nested__": {
|
|
6036
|
+
"bindings": [],
|
|
6037
|
+
"parser": ""
|
|
6038
|
+
} } }
|
|
6039
|
+
},
|
|
6034
6040
|
"pipeline-analytics": {
|
|
6035
6041
|
"getAudioEvents": { "limit": 1e3 },
|
|
6036
6042
|
"getKeyEvents": { "limit": 50 },
|
|
@@ -6135,6 +6141,7 @@ Object.freeze({
|
|
|
6135
6141
|
"addon-routes": ["getRoutes"],
|
|
6136
6142
|
"addon-widgets-source": ["listWidgets"],
|
|
6137
6143
|
"broker": ["list", "listProviders"],
|
|
6144
|
+
"calendar-source": ["listCalendars", "listEvents"],
|
|
6138
6145
|
"custom-model-registry": ["listModels"],
|
|
6139
6146
|
"data-store-provider": ["histogram", "query"],
|
|
6140
6147
|
"device-export": ["listExposedDevices", "listSupportedDeviceKinds"],
|
|
@@ -7957,6 +7964,127 @@ async function reconcileInterruptedExports(deps) {
|
|
|
7957
7964
|
};
|
|
7958
7965
|
}
|
|
7959
7966
|
//#endregion
|
|
7967
|
+
//#region src/recorder/addon/export-shrink-for-read.ts
|
|
7968
|
+
/**
|
|
7969
|
+
* Shrink a rendered export so `readExportBytes` can answer under
|
|
7970
|
+
* {@link RECORDING_EXPORT_MAX_READ_BYTES}.
|
|
7971
|
+
*
|
|
7972
|
+
* A ten-hour overnight timelapse with dense slowdown routinely lands at
|
|
7973
|
+
* 80–200 MB. The byte-read ceiling is the roomiest notifier cap (Telegram
|
|
7974
|
+
* 50 MB) AND the base64 envelope bound (D9/D18) — raising it would OOM the
|
|
7975
|
+
* hub and still be refused by the notifier. So the read shrinks, once, into
|
|
7976
|
+
* a temp file sized for delivery, and the original render stays on disk for
|
|
7977
|
+
* the authenticated tap-through.
|
|
7978
|
+
*
|
|
7979
|
+
* Pure argv builders here; the spawn and temp I/O are injected by the
|
|
7980
|
+
* provider so the suite never needs a real ffmpeg.
|
|
7981
|
+
*/
|
|
7982
|
+
/** CRF ladder tried until the output fits. Higher = smaller, uglier. */
|
|
7983
|
+
var EXPORT_SHRINK_CRF_LADDER = [
|
|
7984
|
+
28,
|
|
7985
|
+
32,
|
|
7986
|
+
36,
|
|
7987
|
+
40
|
|
7988
|
+
];
|
|
7989
|
+
/**
|
|
7990
|
+
* ffmpeg argv that re-encodes a rendered MP4 for notification delivery.
|
|
7991
|
+
*
|
|
7992
|
+
* - `libx264` + `veryfast`: the morning drain must not pin the hub the way
|
|
7993
|
+
* the original night render did.
|
|
7994
|
+
* - `-an`: a timelapse has no audio worth keeping, and dropping it is free
|
|
7995
|
+
* size.
|
|
7996
|
+
* - `640:-2`: notification phones; matching the band the cheapest profile
|
|
7997
|
+
* already aims for.
|
|
7998
|
+
* - `+faststart`: the artifact plane serves the whole file; moov-first is
|
|
7999
|
+
* what a phone needs to start playing before the download finishes.
|
|
8000
|
+
*/
|
|
8001
|
+
function buildExportShrinkArgs(input) {
|
|
8002
|
+
return [
|
|
8003
|
+
"-hide_banner",
|
|
8004
|
+
"-loglevel",
|
|
8005
|
+
"error",
|
|
8006
|
+
"-y",
|
|
8007
|
+
"-i",
|
|
8008
|
+
input.inputPath,
|
|
8009
|
+
"-vf",
|
|
8010
|
+
"scale=640:-2",
|
|
8011
|
+
"-c:v",
|
|
8012
|
+
"libx264",
|
|
8013
|
+
"-preset",
|
|
8014
|
+
"veryfast",
|
|
8015
|
+
"-crf",
|
|
8016
|
+
String(input.crf),
|
|
8017
|
+
"-an",
|
|
8018
|
+
"-movflags",
|
|
8019
|
+
"+faststart",
|
|
8020
|
+
input.outputPath
|
|
8021
|
+
];
|
|
8022
|
+
}
|
|
8023
|
+
/**
|
|
8024
|
+
* Pick the next CRF to try, or `null` when the ladder is exhausted.
|
|
8025
|
+
*
|
|
8026
|
+
* @param attempted — CRFs already tried (may be empty).
|
|
8027
|
+
*/
|
|
8028
|
+
function nextShrinkCrf(attempted) {
|
|
8029
|
+
for (const crf of EXPORT_SHRINK_CRF_LADDER) if (!attempted.includes(crf)) return crf;
|
|
8030
|
+
return null;
|
|
8031
|
+
}
|
|
8032
|
+
/**
|
|
8033
|
+
* Re-encode `inputPath` down the CRF ladder until the file is ≤ `maxBytes`.
|
|
8034
|
+
*
|
|
8035
|
+
* @returns the fitted buffer, or `null` when every rung still overflows (or
|
|
8036
|
+
* ffmpeg refuses). Never throws — the caller treats `null` as "refuse
|
|
8037
|
+
* the inline read", same as the historical oversized gate.
|
|
8038
|
+
*/
|
|
8039
|
+
async function shrinkExportToBound(inputPath, maxBytes, ports) {
|
|
8040
|
+
const attempted = [];
|
|
8041
|
+
for (;;) {
|
|
8042
|
+
const crf = nextShrinkCrf(attempted);
|
|
8043
|
+
if (crf === null) return null;
|
|
8044
|
+
attempted.push(crf);
|
|
8045
|
+
const outPath = `${ports.writePath}.crf${String(crf)}.mp4`;
|
|
8046
|
+
try {
|
|
8047
|
+
const ffmpeg = await ports.resolveFfmpeg();
|
|
8048
|
+
await runShrinkFfmpeg(ports.spawn, ffmpeg, buildExportShrinkArgs({
|
|
8049
|
+
inputPath,
|
|
8050
|
+
outputPath: outPath,
|
|
8051
|
+
crf
|
|
8052
|
+
}));
|
|
8053
|
+
if (await ports.statBytes(outPath) > maxBytes) {
|
|
8054
|
+
await ports.removeFile(outPath);
|
|
8055
|
+
continue;
|
|
8056
|
+
}
|
|
8057
|
+
const buf = await ports.readFile(outPath);
|
|
8058
|
+
await ports.removeFile(outPath);
|
|
8059
|
+
return buf;
|
|
8060
|
+
} catch {
|
|
8061
|
+
await ports.removeFile(outPath).catch(() => void 0);
|
|
8062
|
+
continue;
|
|
8063
|
+
}
|
|
8064
|
+
}
|
|
8065
|
+
}
|
|
8066
|
+
function runShrinkFfmpeg(spawn, ffmpegPath, args) {
|
|
8067
|
+
return new Promise((resolve, reject) => {
|
|
8068
|
+
const proc = spawn(ffmpegPath, args);
|
|
8069
|
+
let stderr = "";
|
|
8070
|
+
proc.stderr?.on("data", (chunk) => {
|
|
8071
|
+
stderr += chunk.toString("utf8");
|
|
8072
|
+
});
|
|
8073
|
+
proc.on("error", (...args) => {
|
|
8074
|
+
const err = args[0];
|
|
8075
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
8076
|
+
});
|
|
8077
|
+
proc.on("close", (...args) => {
|
|
8078
|
+
const code = args[0];
|
|
8079
|
+
if (code === 0) {
|
|
8080
|
+
resolve();
|
|
8081
|
+
return;
|
|
8082
|
+
}
|
|
8083
|
+
reject(/* @__PURE__ */ new Error(`export shrink ffmpeg exited ${String(code)}: ${stderr.slice(0, 400)}`));
|
|
8084
|
+
});
|
|
8085
|
+
});
|
|
8086
|
+
}
|
|
8087
|
+
//#endregion
|
|
7960
8088
|
//#region src/recorder/playlist.ts
|
|
7961
8089
|
/** A VOD variant playlist with an absolute wall-clock anchor per segment. */
|
|
7962
8090
|
function buildVariantPlaylist(segments) {
|
|
@@ -18294,6 +18422,47 @@ function buildRecordingExportProvider(deps) {
|
|
|
18294
18422
|
throw new Error(`recording-export: export "${exportId}" has no file on disk`, { cause: err });
|
|
18295
18423
|
}
|
|
18296
18424
|
if (size > 52428800) {
|
|
18425
|
+
const shrink = deps.shrinkToBound;
|
|
18426
|
+
if (shrink !== void 0) {
|
|
18427
|
+
deps.logger.info("export byte read: shrinking oversized file for inline delivery", {
|
|
18428
|
+
tags,
|
|
18429
|
+
meta: {
|
|
18430
|
+
exportId,
|
|
18431
|
+
bytes: size,
|
|
18432
|
+
maxBytes: require_dist.RECORDING_EXPORT_MAX_READ_BYTES
|
|
18433
|
+
}
|
|
18434
|
+
});
|
|
18435
|
+
const shrunk = await shrink(file, require_dist.RECORDING_EXPORT_MAX_READ_BYTES);
|
|
18436
|
+
if (shrunk !== null && shrunk.byteLength <= 52428800) {
|
|
18437
|
+
deps.logger.info("export byte read: shrink fitted under the inline ceiling", {
|
|
18438
|
+
tags,
|
|
18439
|
+
meta: {
|
|
18440
|
+
exportId,
|
|
18441
|
+
originalBytes: size,
|
|
18442
|
+
bytes: shrunk.byteLength,
|
|
18443
|
+
maxBytes: require_dist.RECORDING_EXPORT_MAX_READ_BYTES
|
|
18444
|
+
}
|
|
18445
|
+
});
|
|
18446
|
+
return {
|
|
18447
|
+
base64: shrunk.toString("base64"),
|
|
18448
|
+
contentType: EXPORT_CONTENT_TYPE,
|
|
18449
|
+
name: exportFileName({
|
|
18450
|
+
id: rec.id,
|
|
18451
|
+
...rec.options.title !== void 0 ? { title: rec.options.title } : {}
|
|
18452
|
+
}),
|
|
18453
|
+
bytes: shrunk.byteLength
|
|
18454
|
+
};
|
|
18455
|
+
}
|
|
18456
|
+
deps.logger.warn("export byte read: shrink could not fit under the inline ceiling", {
|
|
18457
|
+
tags,
|
|
18458
|
+
meta: {
|
|
18459
|
+
exportId,
|
|
18460
|
+
originalBytes: size,
|
|
18461
|
+
shrunkBytes: shrunk?.byteLength ?? null,
|
|
18462
|
+
maxBytes: require_dist.RECORDING_EXPORT_MAX_READ_BYTES
|
|
18463
|
+
}
|
|
18464
|
+
});
|
|
18465
|
+
}
|
|
18297
18466
|
deps.logger.warn("export byte read refused: file is too large to inline", {
|
|
18298
18467
|
tags,
|
|
18299
18468
|
meta: {
|
|
@@ -21813,6 +21982,20 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
21813
21982
|
downloadUrlFor: (id) => `/addon/${RECORDER_ADDON_ID}/${EXPORTS_PREFIX}/${id}.mp4`,
|
|
21814
21983
|
statBytes: async (p) => (await node_fs.promises.stat(p)).size,
|
|
21815
21984
|
readFile: (p) => node_fs.promises.readFile(p),
|
|
21985
|
+
shrinkToBound: async (inputPath, maxBytes) => {
|
|
21986
|
+
const writePath = node_path.default.join(this.exportsDirOrThrow(), ".shrink", `${node_path.default.basename(inputPath, ".mp4")}-${(0, node_crypto.randomUUID)()}`);
|
|
21987
|
+
await node_fs.promises.mkdir(node_path.default.dirname(writePath), { recursive: true });
|
|
21988
|
+
return shrinkExportToBound(inputPath, maxBytes, {
|
|
21989
|
+
resolveFfmpeg: this.pinnedFfmpeg,
|
|
21990
|
+
spawn: node_child_process.spawn,
|
|
21991
|
+
writePath,
|
|
21992
|
+
readFile: (p) => node_fs.promises.readFile(p),
|
|
21993
|
+
removeFile: async (p) => {
|
|
21994
|
+
await node_fs.promises.rm(p, { force: true });
|
|
21995
|
+
},
|
|
21996
|
+
statBytes: async (p) => (await node_fs.promises.stat(p)).size
|
|
21997
|
+
});
|
|
21998
|
+
},
|
|
21816
21999
|
logger: this.ctx.logger.child("export")
|
|
21817
22000
|
});
|
|
21818
22001
|
try {
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $t as stripRetiredBandPreBufferSec, An as sleep$1, B as VISIT_MERGE_GAP_MS, Bn as record, Bt as recordingExportCapability, C as ExportRecordSchema, Dt as migrateLegacyDeviceSignalConfig, En as nodePin, Et as memoizePinnedFfmpeg, F as RECORDING_SOURCE_CAMSTACK_ADDON, Gt as resolveLocationMode, I as RecordingConfigSchema, K as batteryCapability, L as RecordingSignalStatusSchema, Ln as number, Mn as array, N as RECORDING_EXPORT_MAX_READ_BYTES, Nn as boolean, Ot as modeMayWrite, P as RECORDING_SOURCE_CAMSTACK, Rn as object, Rt as recordingArchiveCapability, Sn as hydrateSchema, Tt as mayWriteToLocation, Un as EventCategory, Ut as resolveCreateExportSubject, Vn as string, Vt as recordingSignalCapability, X as clipExportFailureOf, Xt as storageEvictableCapability, Y as clipExportFailure, Zt as storageOccupancyCapability, _ as DEFAULT_EVENTS_BAND_BUFFER_SEC, b as EVENT_OWNER_TYPES, bn as defineCustomActions, bt as loadContributionCapability, dn as DeviceType, dt as exportSubjectOf, fn as errMsg$1, jn as _enum, k as OpsLogEntrySchema, kn as selectAssignedProfileSlots, lt as evictionPolicyForMode, mn as BaseAddon, mt as gbToBytes, o as BatteryStatusSchema, qt as resolveRecordingProfiles, rt as deriveRecordingMode, s as CLIP_BROKER_PACED_RATES, sn as evaluateSensorEdge, tn as videoclipsCapability, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyOfLocation, wt as mayReadLocation, x as EVENT_PAD_MS, yn as customAction, yt as isFirstLevelMacroClass, z as VIDEOCLIPS_MAX_OFFER_BYTES, zn as preprocess, zt as recordingCapability } from "../dist-
|
|
2
|
-
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
1
|
+
import { $t as stripRetiredBandPreBufferSec, An as sleep$1, B as VISIT_MERGE_GAP_MS, Bn as record, Bt as recordingExportCapability, C as ExportRecordSchema, Dt as migrateLegacyDeviceSignalConfig, En as nodePin, Et as memoizePinnedFfmpeg, F as RECORDING_SOURCE_CAMSTACK_ADDON, Gt as resolveLocationMode, I as RecordingConfigSchema, K as batteryCapability, L as RecordingSignalStatusSchema, Ln as number, Mn as array, N as RECORDING_EXPORT_MAX_READ_BYTES, Nn as boolean, Ot as modeMayWrite, P as RECORDING_SOURCE_CAMSTACK, Rn as object, Rt as recordingArchiveCapability, Sn as hydrateSchema, Tt as mayWriteToLocation, Un as EventCategory, Ut as resolveCreateExportSubject, Vn as string, Vt as recordingSignalCapability, X as clipExportFailureOf, Xt as storageEvictableCapability, Y as clipExportFailure, Zt as storageOccupancyCapability, _ as DEFAULT_EVENTS_BAND_BUFFER_SEC, b as EVENT_OWNER_TYPES, bn as defineCustomActions, bt as loadContributionCapability, dn as DeviceType, dt as exportSubjectOf, fn as errMsg$1, jn as _enum, k as OpsLogEntrySchema, kn as selectAssignedProfileSlots, lt as evictionPolicyForMode, mn as BaseAddon, mt as gbToBytes, o as BatteryStatusSchema, qt as resolveRecordingProfiles, rt as deriveRecordingMode, s as CLIP_BROKER_PACED_RATES, sn as evaluateSensorEdge, tn as videoclipsCapability, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyOfLocation, wt as mayReadLocation, x as EVENT_PAD_MS, yn as customAction, yt as isFirstLevelMacroClass, z as VIDEOCLIPS_MAX_OFFER_BYTES, zn as preprocess, zt as recordingCapability } from "../dist-CYhfylbW.mjs";
|
|
2
|
+
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-KuSWIyX-.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";
|
|
@@ -6017,12 +6017,18 @@ Object.freeze({
|
|
|
6017
6017
|
"lookbackMinutes": 60
|
|
6018
6018
|
}
|
|
6019
6019
|
},
|
|
6020
|
-
"osd-manager": {
|
|
6021
|
-
"
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6020
|
+
"osd-manager": {
|
|
6021
|
+
"setSlotBinding": { "binding": { "__nested__": {
|
|
6022
|
+
"enabled": true,
|
|
6023
|
+
"template": "${value}",
|
|
6024
|
+
"maxDecimals": 1,
|
|
6025
|
+
"fallbackText": ""
|
|
6026
|
+
} } },
|
|
6027
|
+
"upsertTemplate": { "template": { "__nested__": {
|
|
6028
|
+
"bindings": [],
|
|
6029
|
+
"parser": ""
|
|
6030
|
+
} } }
|
|
6031
|
+
},
|
|
6026
6032
|
"pipeline-analytics": {
|
|
6027
6033
|
"getAudioEvents": { "limit": 1e3 },
|
|
6028
6034
|
"getKeyEvents": { "limit": 50 },
|
|
@@ -6127,6 +6133,7 @@ Object.freeze({
|
|
|
6127
6133
|
"addon-routes": ["getRoutes"],
|
|
6128
6134
|
"addon-widgets-source": ["listWidgets"],
|
|
6129
6135
|
"broker": ["list", "listProviders"],
|
|
6136
|
+
"calendar-source": ["listCalendars", "listEvents"],
|
|
6130
6137
|
"custom-model-registry": ["listModels"],
|
|
6131
6138
|
"data-store-provider": ["histogram", "query"],
|
|
6132
6139
|
"device-export": ["listExposedDevices", "listSupportedDeviceKinds"],
|
|
@@ -7949,6 +7956,127 @@ async function reconcileInterruptedExports(deps) {
|
|
|
7949
7956
|
};
|
|
7950
7957
|
}
|
|
7951
7958
|
//#endregion
|
|
7959
|
+
//#region src/recorder/addon/export-shrink-for-read.ts
|
|
7960
|
+
/**
|
|
7961
|
+
* Shrink a rendered export so `readExportBytes` can answer under
|
|
7962
|
+
* {@link RECORDING_EXPORT_MAX_READ_BYTES}.
|
|
7963
|
+
*
|
|
7964
|
+
* A ten-hour overnight timelapse with dense slowdown routinely lands at
|
|
7965
|
+
* 80–200 MB. The byte-read ceiling is the roomiest notifier cap (Telegram
|
|
7966
|
+
* 50 MB) AND the base64 envelope bound (D9/D18) — raising it would OOM the
|
|
7967
|
+
* hub and still be refused by the notifier. So the read shrinks, once, into
|
|
7968
|
+
* a temp file sized for delivery, and the original render stays on disk for
|
|
7969
|
+
* the authenticated tap-through.
|
|
7970
|
+
*
|
|
7971
|
+
* Pure argv builders here; the spawn and temp I/O are injected by the
|
|
7972
|
+
* provider so the suite never needs a real ffmpeg.
|
|
7973
|
+
*/
|
|
7974
|
+
/** CRF ladder tried until the output fits. Higher = smaller, uglier. */
|
|
7975
|
+
var EXPORT_SHRINK_CRF_LADDER = [
|
|
7976
|
+
28,
|
|
7977
|
+
32,
|
|
7978
|
+
36,
|
|
7979
|
+
40
|
|
7980
|
+
];
|
|
7981
|
+
/**
|
|
7982
|
+
* ffmpeg argv that re-encodes a rendered MP4 for notification delivery.
|
|
7983
|
+
*
|
|
7984
|
+
* - `libx264` + `veryfast`: the morning drain must not pin the hub the way
|
|
7985
|
+
* the original night render did.
|
|
7986
|
+
* - `-an`: a timelapse has no audio worth keeping, and dropping it is free
|
|
7987
|
+
* size.
|
|
7988
|
+
* - `640:-2`: notification phones; matching the band the cheapest profile
|
|
7989
|
+
* already aims for.
|
|
7990
|
+
* - `+faststart`: the artifact plane serves the whole file; moov-first is
|
|
7991
|
+
* what a phone needs to start playing before the download finishes.
|
|
7992
|
+
*/
|
|
7993
|
+
function buildExportShrinkArgs(input) {
|
|
7994
|
+
return [
|
|
7995
|
+
"-hide_banner",
|
|
7996
|
+
"-loglevel",
|
|
7997
|
+
"error",
|
|
7998
|
+
"-y",
|
|
7999
|
+
"-i",
|
|
8000
|
+
input.inputPath,
|
|
8001
|
+
"-vf",
|
|
8002
|
+
"scale=640:-2",
|
|
8003
|
+
"-c:v",
|
|
8004
|
+
"libx264",
|
|
8005
|
+
"-preset",
|
|
8006
|
+
"veryfast",
|
|
8007
|
+
"-crf",
|
|
8008
|
+
String(input.crf),
|
|
8009
|
+
"-an",
|
|
8010
|
+
"-movflags",
|
|
8011
|
+
"+faststart",
|
|
8012
|
+
input.outputPath
|
|
8013
|
+
];
|
|
8014
|
+
}
|
|
8015
|
+
/**
|
|
8016
|
+
* Pick the next CRF to try, or `null` when the ladder is exhausted.
|
|
8017
|
+
*
|
|
8018
|
+
* @param attempted — CRFs already tried (may be empty).
|
|
8019
|
+
*/
|
|
8020
|
+
function nextShrinkCrf(attempted) {
|
|
8021
|
+
for (const crf of EXPORT_SHRINK_CRF_LADDER) if (!attempted.includes(crf)) return crf;
|
|
8022
|
+
return null;
|
|
8023
|
+
}
|
|
8024
|
+
/**
|
|
8025
|
+
* Re-encode `inputPath` down the CRF ladder until the file is ≤ `maxBytes`.
|
|
8026
|
+
*
|
|
8027
|
+
* @returns the fitted buffer, or `null` when every rung still overflows (or
|
|
8028
|
+
* ffmpeg refuses). Never throws — the caller treats `null` as "refuse
|
|
8029
|
+
* the inline read", same as the historical oversized gate.
|
|
8030
|
+
*/
|
|
8031
|
+
async function shrinkExportToBound(inputPath, maxBytes, ports) {
|
|
8032
|
+
const attempted = [];
|
|
8033
|
+
for (;;) {
|
|
8034
|
+
const crf = nextShrinkCrf(attempted);
|
|
8035
|
+
if (crf === null) return null;
|
|
8036
|
+
attempted.push(crf);
|
|
8037
|
+
const outPath = `${ports.writePath}.crf${String(crf)}.mp4`;
|
|
8038
|
+
try {
|
|
8039
|
+
const ffmpeg = await ports.resolveFfmpeg();
|
|
8040
|
+
await runShrinkFfmpeg(ports.spawn, ffmpeg, buildExportShrinkArgs({
|
|
8041
|
+
inputPath,
|
|
8042
|
+
outputPath: outPath,
|
|
8043
|
+
crf
|
|
8044
|
+
}));
|
|
8045
|
+
if (await ports.statBytes(outPath) > maxBytes) {
|
|
8046
|
+
await ports.removeFile(outPath);
|
|
8047
|
+
continue;
|
|
8048
|
+
}
|
|
8049
|
+
const buf = await ports.readFile(outPath);
|
|
8050
|
+
await ports.removeFile(outPath);
|
|
8051
|
+
return buf;
|
|
8052
|
+
} catch {
|
|
8053
|
+
await ports.removeFile(outPath).catch(() => void 0);
|
|
8054
|
+
continue;
|
|
8055
|
+
}
|
|
8056
|
+
}
|
|
8057
|
+
}
|
|
8058
|
+
function runShrinkFfmpeg(spawn, ffmpegPath, args) {
|
|
8059
|
+
return new Promise((resolve, reject) => {
|
|
8060
|
+
const proc = spawn(ffmpegPath, args);
|
|
8061
|
+
let stderr = "";
|
|
8062
|
+
proc.stderr?.on("data", (chunk) => {
|
|
8063
|
+
stderr += chunk.toString("utf8");
|
|
8064
|
+
});
|
|
8065
|
+
proc.on("error", (...args) => {
|
|
8066
|
+
const err = args[0];
|
|
8067
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
8068
|
+
});
|
|
8069
|
+
proc.on("close", (...args) => {
|
|
8070
|
+
const code = args[0];
|
|
8071
|
+
if (code === 0) {
|
|
8072
|
+
resolve();
|
|
8073
|
+
return;
|
|
8074
|
+
}
|
|
8075
|
+
reject(/* @__PURE__ */ new Error(`export shrink ffmpeg exited ${String(code)}: ${stderr.slice(0, 400)}`));
|
|
8076
|
+
});
|
|
8077
|
+
});
|
|
8078
|
+
}
|
|
8079
|
+
//#endregion
|
|
7952
8080
|
//#region src/recorder/playlist.ts
|
|
7953
8081
|
/** A VOD variant playlist with an absolute wall-clock anchor per segment. */
|
|
7954
8082
|
function buildVariantPlaylist(segments) {
|
|
@@ -18286,6 +18414,47 @@ function buildRecordingExportProvider(deps) {
|
|
|
18286
18414
|
throw new Error(`recording-export: export "${exportId}" has no file on disk`, { cause: err });
|
|
18287
18415
|
}
|
|
18288
18416
|
if (size > 52428800) {
|
|
18417
|
+
const shrink = deps.shrinkToBound;
|
|
18418
|
+
if (shrink !== void 0) {
|
|
18419
|
+
deps.logger.info("export byte read: shrinking oversized file for inline delivery", {
|
|
18420
|
+
tags,
|
|
18421
|
+
meta: {
|
|
18422
|
+
exportId,
|
|
18423
|
+
bytes: size,
|
|
18424
|
+
maxBytes: RECORDING_EXPORT_MAX_READ_BYTES
|
|
18425
|
+
}
|
|
18426
|
+
});
|
|
18427
|
+
const shrunk = await shrink(file, RECORDING_EXPORT_MAX_READ_BYTES);
|
|
18428
|
+
if (shrunk !== null && shrunk.byteLength <= 52428800) {
|
|
18429
|
+
deps.logger.info("export byte read: shrink fitted under the inline ceiling", {
|
|
18430
|
+
tags,
|
|
18431
|
+
meta: {
|
|
18432
|
+
exportId,
|
|
18433
|
+
originalBytes: size,
|
|
18434
|
+
bytes: shrunk.byteLength,
|
|
18435
|
+
maxBytes: RECORDING_EXPORT_MAX_READ_BYTES
|
|
18436
|
+
}
|
|
18437
|
+
});
|
|
18438
|
+
return {
|
|
18439
|
+
base64: shrunk.toString("base64"),
|
|
18440
|
+
contentType: EXPORT_CONTENT_TYPE,
|
|
18441
|
+
name: exportFileName({
|
|
18442
|
+
id: rec.id,
|
|
18443
|
+
...rec.options.title !== void 0 ? { title: rec.options.title } : {}
|
|
18444
|
+
}),
|
|
18445
|
+
bytes: shrunk.byteLength
|
|
18446
|
+
};
|
|
18447
|
+
}
|
|
18448
|
+
deps.logger.warn("export byte read: shrink could not fit under the inline ceiling", {
|
|
18449
|
+
tags,
|
|
18450
|
+
meta: {
|
|
18451
|
+
exportId,
|
|
18452
|
+
originalBytes: size,
|
|
18453
|
+
shrunkBytes: shrunk?.byteLength ?? null,
|
|
18454
|
+
maxBytes: RECORDING_EXPORT_MAX_READ_BYTES
|
|
18455
|
+
}
|
|
18456
|
+
});
|
|
18457
|
+
}
|
|
18289
18458
|
deps.logger.warn("export byte read refused: file is too large to inline", {
|
|
18290
18459
|
tags,
|
|
18291
18460
|
meta: {
|
|
@@ -21805,6 +21974,20 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
21805
21974
|
downloadUrlFor: (id) => `/addon/${RECORDER_ADDON_ID}/${EXPORTS_PREFIX}/${id}.mp4`,
|
|
21806
21975
|
statBytes: async (p) => (await promises.stat(p)).size,
|
|
21807
21976
|
readFile: (p) => promises.readFile(p),
|
|
21977
|
+
shrinkToBound: async (inputPath, maxBytes) => {
|
|
21978
|
+
const writePath = path.join(this.exportsDirOrThrow(), ".shrink", `${path.basename(inputPath, ".mp4")}-${randomUUID()}`);
|
|
21979
|
+
await promises.mkdir(path.dirname(writePath), { recursive: true });
|
|
21980
|
+
return shrinkExportToBound(inputPath, maxBytes, {
|
|
21981
|
+
resolveFfmpeg: this.pinnedFfmpeg,
|
|
21982
|
+
spawn,
|
|
21983
|
+
writePath,
|
|
21984
|
+
readFile: (p) => promises.readFile(p),
|
|
21985
|
+
removeFile: async (p) => {
|
|
21986
|
+
await promises.rm(p, { force: true });
|
|
21987
|
+
},
|
|
21988
|
+
statBytes: async (p) => (await promises.stat(p)).size
|
|
21989
|
+
});
|
|
21990
|
+
},
|
|
21808
21991
|
logger: this.ctx.logger.child("export")
|
|
21809
21992
|
});
|
|
21810
21993
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BHwYsqDW.js");
|
|
3
3
|
let node_child_process = require("node:child_process");
|
|
4
4
|
//#region src/stream-broker/recorded/avcc-annexb.ts
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { fn as errMsg } from "./dist-
|
|
2
|
+
import { fn as errMsg } from "./dist-CYhfylbW.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region src/stream-broker/recorded/avcc-annexb.ts
|
|
5
5
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
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-
|
|
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-mEJkrfvj.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-
|
|
4
|
+
import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bm0eNLm_.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.
|
|
21
|
+
version: "1.2.302",
|
|
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.
|
|
36
|
+
version: "1.2.228",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|