@camstack/addon-pipeline 1.2.125 → 1.2.126
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/recorder/index.js +69 -63
- package/dist/recorder/index.mjs +69 -63
- package/package.json +1 -1
package/dist/recorder/index.js
CHANGED
|
@@ -3151,65 +3151,6 @@ function buildExportArgs(input) {
|
|
|
3151
3151
|
];
|
|
3152
3152
|
}
|
|
3153
3153
|
//#endregion
|
|
3154
|
-
//#region src/recorder/addon/export-timelapse-chunks.ts
|
|
3155
|
-
/** One hour of concatenated footage — not one hour of wall clock. */
|
|
3156
|
-
var TIMELAPSE_CHUNK_MS = 36e5;
|
|
3157
|
-
/**
|
|
3158
|
-
* Split a concat list into hour-sized chunks. A single file longer than the
|
|
3159
|
-
* chunk stays whole — it is already one open, and cutting it would need a
|
|
3160
|
-
* second demux we do not have.
|
|
3161
|
-
*/
|
|
3162
|
-
function splitTimelapseChunks(entries, chunkMs = TIMELAPSE_CHUNK_MS) {
|
|
3163
|
-
if (entries.length === 0) return [];
|
|
3164
|
-
const chunks = [];
|
|
3165
|
-
let current = [];
|
|
3166
|
-
let currentDur = 0;
|
|
3167
|
-
let streamStartMs = 0;
|
|
3168
|
-
for (const entry of entries) {
|
|
3169
|
-
if (current.length > 0 && currentDur + entry.durMs > chunkMs) {
|
|
3170
|
-
chunks.push({
|
|
3171
|
-
entries: current,
|
|
3172
|
-
streamStartMs
|
|
3173
|
-
});
|
|
3174
|
-
streamStartMs += currentDur;
|
|
3175
|
-
current = [];
|
|
3176
|
-
currentDur = 0;
|
|
3177
|
-
}
|
|
3178
|
-
current.push(entry);
|
|
3179
|
-
currentDur += entry.durMs;
|
|
3180
|
-
}
|
|
3181
|
-
if (current.length > 0) chunks.push({
|
|
3182
|
-
entries: current,
|
|
3183
|
-
streamStartMs
|
|
3184
|
-
});
|
|
3185
|
-
return chunks;
|
|
3186
|
-
}
|
|
3187
|
-
/**
|
|
3188
|
-
* Move stream-time dense ranges onto a chunk's own `t=0`. Ranges that miss
|
|
3189
|
-
* the chunk disappear; a range that straddles the edge is clipped. Empty →
|
|
3190
|
-
* `undefined` so the select stays the single-rate form.
|
|
3191
|
-
*/
|
|
3192
|
-
function denseRangesForChunk(dense, chunkStreamStartMs, chunkDurMs) {
|
|
3193
|
-
if (dense === void 0 || dense.ranges.length === 0) return void 0;
|
|
3194
|
-
const startSec = chunkStreamStartMs / 1e3;
|
|
3195
|
-
const endSec = (chunkStreamStartMs + chunkDurMs) / 1e3;
|
|
3196
|
-
const ranges = [];
|
|
3197
|
-
for (const r of dense.ranges) {
|
|
3198
|
-
const from = Math.max(r.fromSec, startSec);
|
|
3199
|
-
const to = Math.min(r.toSec, endSec);
|
|
3200
|
-
if (to <= from) continue;
|
|
3201
|
-
ranges.push({
|
|
3202
|
-
fromSec: from - startSec,
|
|
3203
|
-
toSec: to - startSec
|
|
3204
|
-
});
|
|
3205
|
-
}
|
|
3206
|
-
if (ranges.length === 0) return void 0;
|
|
3207
|
-
return {
|
|
3208
|
-
everyMs: dense.everyMs,
|
|
3209
|
-
ranges
|
|
3210
|
-
};
|
|
3211
|
-
}
|
|
3212
|
-
//#endregion
|
|
3213
3154
|
//#region src/recorder/addon/export-store.ts
|
|
3214
3155
|
/**
|
|
3215
3156
|
* Recording-export persistence for the recorder addon.
|
|
@@ -3371,6 +3312,65 @@ async function listExportsFor(state, deviceId) {
|
|
|
3371
3312
|
})).map((entry) => entry.value);
|
|
3372
3313
|
}
|
|
3373
3314
|
//#endregion
|
|
3315
|
+
//#region src/recorder/addon/export-timelapse-chunks.ts
|
|
3316
|
+
/** One hour of concatenated footage — not one hour of wall clock. */
|
|
3317
|
+
var TIMELAPSE_CHUNK_MS = 36e5;
|
|
3318
|
+
/**
|
|
3319
|
+
* Split a concat list into hour-sized chunks. A single file longer than the
|
|
3320
|
+
* chunk stays whole — it is already one open, and cutting it would need a
|
|
3321
|
+
* second demux we do not have.
|
|
3322
|
+
*/
|
|
3323
|
+
function splitTimelapseChunks(entries, chunkMs = TIMELAPSE_CHUNK_MS) {
|
|
3324
|
+
if (entries.length === 0) return [];
|
|
3325
|
+
const chunks = [];
|
|
3326
|
+
let current = [];
|
|
3327
|
+
let currentDur = 0;
|
|
3328
|
+
let streamStartMs = 0;
|
|
3329
|
+
for (const entry of entries) {
|
|
3330
|
+
if (current.length > 0 && currentDur + entry.durMs > chunkMs) {
|
|
3331
|
+
chunks.push({
|
|
3332
|
+
entries: current,
|
|
3333
|
+
streamStartMs
|
|
3334
|
+
});
|
|
3335
|
+
streamStartMs += currentDur;
|
|
3336
|
+
current = [];
|
|
3337
|
+
currentDur = 0;
|
|
3338
|
+
}
|
|
3339
|
+
current.push(entry);
|
|
3340
|
+
currentDur += entry.durMs;
|
|
3341
|
+
}
|
|
3342
|
+
if (current.length > 0) chunks.push({
|
|
3343
|
+
entries: current,
|
|
3344
|
+
streamStartMs
|
|
3345
|
+
});
|
|
3346
|
+
return chunks;
|
|
3347
|
+
}
|
|
3348
|
+
/**
|
|
3349
|
+
* Move stream-time dense ranges onto a chunk's own `t=0`. Ranges that miss
|
|
3350
|
+
* the chunk disappear; a range that straddles the edge is clipped. Empty →
|
|
3351
|
+
* `undefined` so the select stays the single-rate form.
|
|
3352
|
+
*/
|
|
3353
|
+
function denseRangesForChunk(dense, chunkStreamStartMs, chunkDurMs) {
|
|
3354
|
+
if (dense === void 0 || dense.ranges.length === 0) return void 0;
|
|
3355
|
+
const startSec = chunkStreamStartMs / 1e3;
|
|
3356
|
+
const endSec = (chunkStreamStartMs + chunkDurMs) / 1e3;
|
|
3357
|
+
const ranges = [];
|
|
3358
|
+
for (const r of dense.ranges) {
|
|
3359
|
+
const from = Math.max(r.fromSec, startSec);
|
|
3360
|
+
const to = Math.min(r.toSec, endSec);
|
|
3361
|
+
if (to <= from) continue;
|
|
3362
|
+
ranges.push({
|
|
3363
|
+
fromSec: from - startSec,
|
|
3364
|
+
toSec: to - startSec
|
|
3365
|
+
});
|
|
3366
|
+
}
|
|
3367
|
+
if (ranges.length === 0) return void 0;
|
|
3368
|
+
return {
|
|
3369
|
+
everyMs: dense.everyMs,
|
|
3370
|
+
ranges
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
//#endregion
|
|
3374
3374
|
//#region src/recorder/addon/spawn-failure.ts
|
|
3375
3375
|
/**
|
|
3376
3376
|
* How the recorder reads a `child_process` `'error'` — ONE owner of the
|
|
@@ -3649,12 +3649,11 @@ var ExportEngine = class {
|
|
|
3649
3649
|
const survivors = [];
|
|
3650
3650
|
const sidecars = [];
|
|
3651
3651
|
try {
|
|
3652
|
-
for (
|
|
3652
|
+
for (const [i, chunk] of chunks.entries()) {
|
|
3653
3653
|
if (this.cancelled.has(id)) {
|
|
3654
3654
|
await this.fail(id, "cancelled");
|
|
3655
3655
|
return;
|
|
3656
3656
|
}
|
|
3657
|
-
const chunk = chunks[i];
|
|
3658
3657
|
const chunkDur = chunk.entries.reduce((s, e) => s + e.durMs, 0);
|
|
3659
3658
|
const listPath = `${outPath}.chunk${i}.ffconcat`;
|
|
3660
3659
|
const concatPath = `${outPath}.chunk${i}.concat.ts`;
|
|
@@ -3687,8 +3686,8 @@ var ExportEngine = class {
|
|
|
3687
3686
|
await this.fail(id, "every timelapse hour failed");
|
|
3688
3687
|
return;
|
|
3689
3688
|
}
|
|
3690
|
-
|
|
3691
|
-
|
|
3689
|
+
const only = survivors[0];
|
|
3690
|
+
if (survivors.length === 1 && only !== void 0) {
|
|
3692
3691
|
const copyArgs = buildExportArgs({
|
|
3693
3692
|
inputPlaylist: only,
|
|
3694
3693
|
outPath,
|
|
@@ -12044,6 +12043,13 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
12044
12043
|
/**
|
|
12045
12044
|
* Opt-in fleet walk — NOT armed at boot (2026-08-22: starved scrub/play).
|
|
12046
12045
|
* Kept so an operator path can still request a full reconcile later.
|
|
12046
|
+
*
|
|
12047
|
+
* ⚠ That operator path DOES NOT EXIST YET. This is the only caller of
|
|
12048
|
+
* `runFullArchiveWalk`, so today the whole walk is unreachable — `tsc` was
|
|
12049
|
+
* flagging it as unused and it was one of the errors keeping this package
|
|
12050
|
+
* red. Made public rather than deleted, because deleting it would have taken
|
|
12051
|
+
* the 100-line walk with it; but a comment promising a path nobody built is
|
|
12052
|
+
* exactly the leftover that reads as verification. Wire it or drop it.
|
|
12047
12053
|
*/
|
|
12048
12054
|
scheduleDeferredFullWalk(deviceIds) {
|
|
12049
12055
|
if (this.fullWalkTimer !== null || this.fullWalkInFlight) return;
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -3150,65 +3150,6 @@ function buildExportArgs(input) {
|
|
|
3150
3150
|
];
|
|
3151
3151
|
}
|
|
3152
3152
|
//#endregion
|
|
3153
|
-
//#region src/recorder/addon/export-timelapse-chunks.ts
|
|
3154
|
-
/** One hour of concatenated footage — not one hour of wall clock. */
|
|
3155
|
-
var TIMELAPSE_CHUNK_MS = 36e5;
|
|
3156
|
-
/**
|
|
3157
|
-
* Split a concat list into hour-sized chunks. A single file longer than the
|
|
3158
|
-
* chunk stays whole — it is already one open, and cutting it would need a
|
|
3159
|
-
* second demux we do not have.
|
|
3160
|
-
*/
|
|
3161
|
-
function splitTimelapseChunks(entries, chunkMs = TIMELAPSE_CHUNK_MS) {
|
|
3162
|
-
if (entries.length === 0) return [];
|
|
3163
|
-
const chunks = [];
|
|
3164
|
-
let current = [];
|
|
3165
|
-
let currentDur = 0;
|
|
3166
|
-
let streamStartMs = 0;
|
|
3167
|
-
for (const entry of entries) {
|
|
3168
|
-
if (current.length > 0 && currentDur + entry.durMs > chunkMs) {
|
|
3169
|
-
chunks.push({
|
|
3170
|
-
entries: current,
|
|
3171
|
-
streamStartMs
|
|
3172
|
-
});
|
|
3173
|
-
streamStartMs += currentDur;
|
|
3174
|
-
current = [];
|
|
3175
|
-
currentDur = 0;
|
|
3176
|
-
}
|
|
3177
|
-
current.push(entry);
|
|
3178
|
-
currentDur += entry.durMs;
|
|
3179
|
-
}
|
|
3180
|
-
if (current.length > 0) chunks.push({
|
|
3181
|
-
entries: current,
|
|
3182
|
-
streamStartMs
|
|
3183
|
-
});
|
|
3184
|
-
return chunks;
|
|
3185
|
-
}
|
|
3186
|
-
/**
|
|
3187
|
-
* Move stream-time dense ranges onto a chunk's own `t=0`. Ranges that miss
|
|
3188
|
-
* the chunk disappear; a range that straddles the edge is clipped. Empty →
|
|
3189
|
-
* `undefined` so the select stays the single-rate form.
|
|
3190
|
-
*/
|
|
3191
|
-
function denseRangesForChunk(dense, chunkStreamStartMs, chunkDurMs) {
|
|
3192
|
-
if (dense === void 0 || dense.ranges.length === 0) return void 0;
|
|
3193
|
-
const startSec = chunkStreamStartMs / 1e3;
|
|
3194
|
-
const endSec = (chunkStreamStartMs + chunkDurMs) / 1e3;
|
|
3195
|
-
const ranges = [];
|
|
3196
|
-
for (const r of dense.ranges) {
|
|
3197
|
-
const from = Math.max(r.fromSec, startSec);
|
|
3198
|
-
const to = Math.min(r.toSec, endSec);
|
|
3199
|
-
if (to <= from) continue;
|
|
3200
|
-
ranges.push({
|
|
3201
|
-
fromSec: from - startSec,
|
|
3202
|
-
toSec: to - startSec
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
|
-
if (ranges.length === 0) return void 0;
|
|
3206
|
-
return {
|
|
3207
|
-
everyMs: dense.everyMs,
|
|
3208
|
-
ranges
|
|
3209
|
-
};
|
|
3210
|
-
}
|
|
3211
|
-
//#endregion
|
|
3212
3153
|
//#region src/recorder/addon/export-store.ts
|
|
3213
3154
|
/**
|
|
3214
3155
|
* Recording-export persistence for the recorder addon.
|
|
@@ -3370,6 +3311,65 @@ async function listExportsFor(state, deviceId) {
|
|
|
3370
3311
|
})).map((entry) => entry.value);
|
|
3371
3312
|
}
|
|
3372
3313
|
//#endregion
|
|
3314
|
+
//#region src/recorder/addon/export-timelapse-chunks.ts
|
|
3315
|
+
/** One hour of concatenated footage — not one hour of wall clock. */
|
|
3316
|
+
var TIMELAPSE_CHUNK_MS = 36e5;
|
|
3317
|
+
/**
|
|
3318
|
+
* Split a concat list into hour-sized chunks. A single file longer than the
|
|
3319
|
+
* chunk stays whole — it is already one open, and cutting it would need a
|
|
3320
|
+
* second demux we do not have.
|
|
3321
|
+
*/
|
|
3322
|
+
function splitTimelapseChunks(entries, chunkMs = TIMELAPSE_CHUNK_MS) {
|
|
3323
|
+
if (entries.length === 0) return [];
|
|
3324
|
+
const chunks = [];
|
|
3325
|
+
let current = [];
|
|
3326
|
+
let currentDur = 0;
|
|
3327
|
+
let streamStartMs = 0;
|
|
3328
|
+
for (const entry of entries) {
|
|
3329
|
+
if (current.length > 0 && currentDur + entry.durMs > chunkMs) {
|
|
3330
|
+
chunks.push({
|
|
3331
|
+
entries: current,
|
|
3332
|
+
streamStartMs
|
|
3333
|
+
});
|
|
3334
|
+
streamStartMs += currentDur;
|
|
3335
|
+
current = [];
|
|
3336
|
+
currentDur = 0;
|
|
3337
|
+
}
|
|
3338
|
+
current.push(entry);
|
|
3339
|
+
currentDur += entry.durMs;
|
|
3340
|
+
}
|
|
3341
|
+
if (current.length > 0) chunks.push({
|
|
3342
|
+
entries: current,
|
|
3343
|
+
streamStartMs
|
|
3344
|
+
});
|
|
3345
|
+
return chunks;
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Move stream-time dense ranges onto a chunk's own `t=0`. Ranges that miss
|
|
3349
|
+
* the chunk disappear; a range that straddles the edge is clipped. Empty →
|
|
3350
|
+
* `undefined` so the select stays the single-rate form.
|
|
3351
|
+
*/
|
|
3352
|
+
function denseRangesForChunk(dense, chunkStreamStartMs, chunkDurMs) {
|
|
3353
|
+
if (dense === void 0 || dense.ranges.length === 0) return void 0;
|
|
3354
|
+
const startSec = chunkStreamStartMs / 1e3;
|
|
3355
|
+
const endSec = (chunkStreamStartMs + chunkDurMs) / 1e3;
|
|
3356
|
+
const ranges = [];
|
|
3357
|
+
for (const r of dense.ranges) {
|
|
3358
|
+
const from = Math.max(r.fromSec, startSec);
|
|
3359
|
+
const to = Math.min(r.toSec, endSec);
|
|
3360
|
+
if (to <= from) continue;
|
|
3361
|
+
ranges.push({
|
|
3362
|
+
fromSec: from - startSec,
|
|
3363
|
+
toSec: to - startSec
|
|
3364
|
+
});
|
|
3365
|
+
}
|
|
3366
|
+
if (ranges.length === 0) return void 0;
|
|
3367
|
+
return {
|
|
3368
|
+
everyMs: dense.everyMs,
|
|
3369
|
+
ranges
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
//#endregion
|
|
3373
3373
|
//#region src/recorder/addon/spawn-failure.ts
|
|
3374
3374
|
/**
|
|
3375
3375
|
* How the recorder reads a `child_process` `'error'` — ONE owner of the
|
|
@@ -3648,12 +3648,11 @@ var ExportEngine = class {
|
|
|
3648
3648
|
const survivors = [];
|
|
3649
3649
|
const sidecars = [];
|
|
3650
3650
|
try {
|
|
3651
|
-
for (
|
|
3651
|
+
for (const [i, chunk] of chunks.entries()) {
|
|
3652
3652
|
if (this.cancelled.has(id)) {
|
|
3653
3653
|
await this.fail(id, "cancelled");
|
|
3654
3654
|
return;
|
|
3655
3655
|
}
|
|
3656
|
-
const chunk = chunks[i];
|
|
3657
3656
|
const chunkDur = chunk.entries.reduce((s, e) => s + e.durMs, 0);
|
|
3658
3657
|
const listPath = `${outPath}.chunk${i}.ffconcat`;
|
|
3659
3658
|
const concatPath = `${outPath}.chunk${i}.concat.ts`;
|
|
@@ -3686,8 +3685,8 @@ var ExportEngine = class {
|
|
|
3686
3685
|
await this.fail(id, "every timelapse hour failed");
|
|
3687
3686
|
return;
|
|
3688
3687
|
}
|
|
3689
|
-
|
|
3690
|
-
|
|
3688
|
+
const only = survivors[0];
|
|
3689
|
+
if (survivors.length === 1 && only !== void 0) {
|
|
3691
3690
|
const copyArgs = buildExportArgs({
|
|
3692
3691
|
inputPlaylist: only,
|
|
3693
3692
|
outPath,
|
|
@@ -12043,6 +12042,13 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
12043
12042
|
/**
|
|
12044
12043
|
* Opt-in fleet walk — NOT armed at boot (2026-08-22: starved scrub/play).
|
|
12045
12044
|
* Kept so an operator path can still request a full reconcile later.
|
|
12045
|
+
*
|
|
12046
|
+
* ⚠ That operator path DOES NOT EXIST YET. This is the only caller of
|
|
12047
|
+
* `runFullArchiveWalk`, so today the whole walk is unreachable — `tsc` was
|
|
12048
|
+
* flagging it as unused and it was one of the errors keeping this package
|
|
12049
|
+
* red. Made public rather than deleted, because deleting it would have taken
|
|
12050
|
+
* the 100-line walk with it; but a comment promising a path nobody built is
|
|
12051
|
+
* exactly the leftover that reads as verification. Wire it or drop it.
|
|
12046
12052
|
*/
|
|
12047
12053
|
scheduleDeferredFullWalk(deviceIds) {
|
|
12048
12054
|
if (this.fullWalkTimer !== null || this.fullWalkInFlight) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.126",
|
|
4
4
|
"description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|