omnius 1.0.434 → 1.0.435
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/index.js +448 -29
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9286,6 +9286,74 @@ function uniqueStrings(values) {
|
|
|
9286
9286
|
}
|
|
9287
9287
|
return out;
|
|
9288
9288
|
}
|
|
9289
|
+
function optionalPositiveInteger(value2) {
|
|
9290
|
+
if (value2 === void 0 || value2 === null || value2 === "")
|
|
9291
|
+
return void 0;
|
|
9292
|
+
const parsed = typeof value2 === "number" ? value2 : Number(String(value2).trim());
|
|
9293
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
9294
|
+
return void 0;
|
|
9295
|
+
return Math.round(parsed);
|
|
9296
|
+
}
|
|
9297
|
+
function normalizeCameraPresetFps(value2) {
|
|
9298
|
+
const parsed = optionalPositiveInteger(typeof value2 === "string" ? value2.replace(/\s*fps$/i, "") : value2);
|
|
9299
|
+
return parsed === void 0 ? void 0 : Math.max(1, Math.min(30, parsed));
|
|
9300
|
+
}
|
|
9301
|
+
function parseCameraPresetResolution(value2) {
|
|
9302
|
+
const raw = String(value2 ?? "").trim().toLowerCase();
|
|
9303
|
+
if (!raw || raw === "native" || raw === "auto")
|
|
9304
|
+
return null;
|
|
9305
|
+
const alias = {
|
|
9306
|
+
"480": "640x480",
|
|
9307
|
+
"480p": "640x480",
|
|
9308
|
+
"720": "1280x720",
|
|
9309
|
+
"720p": "1280x720",
|
|
9310
|
+
"1080": "1920x1080",
|
|
9311
|
+
"1080p": "1920x1080",
|
|
9312
|
+
"1440": "2560x1440",
|
|
9313
|
+
"1440p": "2560x1440",
|
|
9314
|
+
"2k": "2560x1440",
|
|
9315
|
+
"2160": "3840x2160",
|
|
9316
|
+
"2160p": "3840x2160",
|
|
9317
|
+
"4k": "3840x2160",
|
|
9318
|
+
"uhd": "3840x2160"
|
|
9319
|
+
};
|
|
9320
|
+
const normalized = alias[raw] ?? raw;
|
|
9321
|
+
const match = normalized.match(/^(\d{3,5})x(\d{3,5})$/);
|
|
9322
|
+
if (!match)
|
|
9323
|
+
return null;
|
|
9324
|
+
const width = Number(match[1]);
|
|
9325
|
+
const height = Number(match[2]);
|
|
9326
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
|
|
9327
|
+
return null;
|
|
9328
|
+
return { width, height, label: `${width}x${height}` };
|
|
9329
|
+
}
|
|
9330
|
+
function loadLiveCameraPreset(requestedDevice) {
|
|
9331
|
+
const repoRoot = process.env["OMNIUS_REPO_ROOT"] || process.cwd();
|
|
9332
|
+
const configPath2 = join13(repoRoot, ".omnius", "live", "config.json");
|
|
9333
|
+
try {
|
|
9334
|
+
const parsed = JSON.parse(readFileSync13(configPath2, "utf8"));
|
|
9335
|
+
const streams = parsed["cameraStreams"] && typeof parsed["cameraStreams"] === "object" ? parsed["cameraStreams"] : {};
|
|
9336
|
+
const orientations = parsed["cameraOrientation"] && typeof parsed["cameraOrientation"] === "object" ? parsed["cameraOrientation"] : {};
|
|
9337
|
+
const selected = typeof parsed["selectedCamera"] === "string" ? parsed["selectedCamera"] : void 0;
|
|
9338
|
+
const device = requestedDevice || selected;
|
|
9339
|
+
if (!device)
|
|
9340
|
+
return {};
|
|
9341
|
+
const stream = streams[device] ?? {};
|
|
9342
|
+
const orientation = orientations[device] ?? {};
|
|
9343
|
+
const resolution = parseCameraPresetResolution(stream["resolution"]);
|
|
9344
|
+
const rotation = orientation["rotation"] !== void 0 ? normalizeCameraRotationDegrees(orientation["rotation"]) : void 0;
|
|
9345
|
+
return {
|
|
9346
|
+
device,
|
|
9347
|
+
width: resolution?.width,
|
|
9348
|
+
height: resolution?.height,
|
|
9349
|
+
resolution: resolution?.label ?? String(stream["resolution"] ?? "native"),
|
|
9350
|
+
rotation,
|
|
9351
|
+
fps: normalizeCameraPresetFps(stream["fps"] ?? stream["framerate"])
|
|
9352
|
+
};
|
|
9353
|
+
} catch {
|
|
9354
|
+
return {};
|
|
9355
|
+
}
|
|
9356
|
+
}
|
|
9289
9357
|
function buildV4l2CaptureAttempts(width, height, formats) {
|
|
9290
9358
|
const requested = width > 0 && height > 0 ? `${width}x${height}` : void 0;
|
|
9291
9359
|
const sizeArea = (size) => {
|
|
@@ -9465,6 +9533,14 @@ var init_camera_capture = __esm({
|
|
|
9465
9533
|
type: "number",
|
|
9466
9534
|
description: "Capture height in pixels (default: camera native format)"
|
|
9467
9535
|
},
|
|
9536
|
+
fps: {
|
|
9537
|
+
type: "number",
|
|
9538
|
+
description: "Requested capture frame rate for v4l2 devices. Defaults to the shared /live or /camera preset when available."
|
|
9539
|
+
},
|
|
9540
|
+
framerate: {
|
|
9541
|
+
type: "number",
|
|
9542
|
+
description: "Alias for fps."
|
|
9543
|
+
},
|
|
9468
9544
|
rotate_degrees: {
|
|
9469
9545
|
type: "number",
|
|
9470
9546
|
enum: [0, 90, 180, 270],
|
|
@@ -9564,20 +9640,33 @@ ${formatRouterPlan(plan)}`,
|
|
|
9564
9640
|
// Capture frame — auto-selects v4l2 or QooCam
|
|
9565
9641
|
// =========================================================================
|
|
9566
9642
|
async captureFrame(args, start2) {
|
|
9567
|
-
const
|
|
9643
|
+
const requestedDevice = args["device"] || "";
|
|
9644
|
+
const preset = loadLiveCameraPreset(requestedDevice);
|
|
9645
|
+
const device = requestedDevice || preset.device || "";
|
|
9646
|
+
const effectiveArgs = { ...args, device };
|
|
9647
|
+
if (effectiveArgs["width"] === void 0 && preset.width !== void 0)
|
|
9648
|
+
effectiveArgs["width"] = preset.width;
|
|
9649
|
+
if (effectiveArgs["height"] === void 0 && preset.height !== void 0)
|
|
9650
|
+
effectiveArgs["height"] = preset.height;
|
|
9651
|
+
if (effectiveArgs["rotate_degrees"] === void 0 && effectiveArgs["rotation_degrees"] === void 0 && effectiveArgs["rotate"] === void 0 && preset.rotation !== void 0) {
|
|
9652
|
+
effectiveArgs["rotate_degrees"] = preset.rotation;
|
|
9653
|
+
}
|
|
9654
|
+
if (effectiveArgs["fps"] === void 0 && effectiveArgs["framerate"] === void 0 && preset.fps !== void 0) {
|
|
9655
|
+
effectiveArgs["framerate"] = preset.fps;
|
|
9656
|
+
}
|
|
9568
9657
|
const outputPath3 = args["output_path"];
|
|
9569
9658
|
if (device === "qoocam" || device.startsWith("qoocam")) {
|
|
9570
|
-
return this.captureQooCam(
|
|
9659
|
+
return this.captureQooCam(effectiveArgs, start2);
|
|
9571
9660
|
}
|
|
9572
9661
|
const v4l2Device = await this.resolveV4l2Device(device);
|
|
9573
9662
|
if (!v4l2Device) {
|
|
9574
9663
|
const qoocam = await this.discoverQooCam();
|
|
9575
9664
|
if (qoocam.found) {
|
|
9576
|
-
return this.captureQooCam(
|
|
9665
|
+
return this.captureQooCam(effectiveArgs, start2);
|
|
9577
9666
|
}
|
|
9578
9667
|
return { success: false, output: "", error: "No camera found. Connect a USB camera or enable QooCam WiFi hotspot.", durationMs: performance.now() - start2 };
|
|
9579
9668
|
}
|
|
9580
|
-
return this.captureV4l2(v4l2Device,
|
|
9669
|
+
return this.captureV4l2(v4l2Device, effectiveArgs, start2);
|
|
9581
9670
|
}
|
|
9582
9671
|
// =========================================================================
|
|
9583
9672
|
// Camera info
|
|
@@ -9687,10 +9776,11 @@ ${formatRouterPlan(plan)}`,
|
|
|
9687
9776
|
return rawDevice;
|
|
9688
9777
|
}
|
|
9689
9778
|
async captureV4l2(device, args, start2) {
|
|
9690
|
-
const width = args["width"]
|
|
9691
|
-
const height = args["height"]
|
|
9779
|
+
const width = optionalPositiveInteger(args["width"]) ?? 0;
|
|
9780
|
+
const height = optionalPositiveInteger(args["height"]) ?? 0;
|
|
9692
9781
|
const outputPath3 = args["output_path"];
|
|
9693
9782
|
const rotation = normalizeCameraRotationDegrees(args["rotate_degrees"] ?? args["rotation_degrees"] ?? args["rotate"]);
|
|
9783
|
+
const fps = normalizeCameraPresetFps(args["framerate"] ?? args["fps"]);
|
|
9694
9784
|
const captureDir = join13(tmpdir2(), "omnius-camera");
|
|
9695
9785
|
if (!existsSync15(captureDir))
|
|
9696
9786
|
mkdirSync9(captureDir, { recursive: true });
|
|
@@ -9722,7 +9812,7 @@ ${formatRouterPlan(plan)}`,
|
|
|
9722
9812
|
unlinkSync2(tempFile);
|
|
9723
9813
|
} catch {
|
|
9724
9814
|
}
|
|
9725
|
-
const argv = this.ffmpegCaptureArgs(device, tempFile, attempt);
|
|
9815
|
+
const argv = this.ffmpegCaptureArgs(device, tempFile, attempt, fps);
|
|
9726
9816
|
try {
|
|
9727
9817
|
await runProcessBuffer(ffmpegBin(), argv, { timeout: 15e3 });
|
|
9728
9818
|
if (existsSync15(tempFile) && readFileSync13(tempFile).length > 0) {
|
|
@@ -9765,8 +9855,10 @@ ${formatRouterPlan(plan)}`,
|
|
|
9765
9855
|
Recovered with capture profile: ${captureState.successfulAttempt?.label ?? "unknown"}. Last failed attempt: ${errors[errors.length - 1].slice(0, 260)}` : "";
|
|
9766
9856
|
const rotationNote = rotation !== 0 ? `
|
|
9767
9857
|
Applied camera rotation correction: ${rotation} degrees clockwise.` : "";
|
|
9858
|
+
const fpsNote = fps ? `
|
|
9859
|
+
Applied camera capture FPS preset: ${fps} fps.` : "";
|
|
9768
9860
|
const result = this.returnCapturedFile(tempFile, captureState.successfulAttempt?.videoSize ?? (width && height ? `${width}x${height}` : "native"), device, outputPath3, start2);
|
|
9769
|
-
const notes = `${firstSuccess}${rotationNote}`;
|
|
9861
|
+
const notes = `${firstSuccess}${rotationNote}${fpsNote}`;
|
|
9770
9862
|
return result.success && notes ? { ...result, output: result.output + notes, llmContent: result.llmContent ? result.llmContent + notes : result.llmContent } : result;
|
|
9771
9863
|
}
|
|
9772
9864
|
const allErrors = errors.join("\n\n");
|
|
@@ -9841,8 +9933,10 @@ ${allErrors.slice(0, 900)}`, durationMs: performance.now() - start2 };
|
|
|
9841
9933
|
return [];
|
|
9842
9934
|
}
|
|
9843
9935
|
}
|
|
9844
|
-
ffmpegCaptureArgs(device, outputPath3, attempt) {
|
|
9936
|
+
ffmpegCaptureArgs(device, outputPath3, attempt, fps) {
|
|
9845
9937
|
const argv = ["-hide_banner", "-loglevel", "error", "-f", "v4l2", "-thread_queue_size", "4"];
|
|
9938
|
+
if (fps)
|
|
9939
|
+
argv.push("-framerate", String(fps));
|
|
9846
9940
|
if (attempt.inputFormat)
|
|
9847
9941
|
argv.push("-input_format", attempt.inputFormat);
|
|
9848
9942
|
if (attempt.videoSize)
|
|
@@ -604669,8 +604763,8 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
604669
604763
|
import { spawn as spawn30 } from "node:child_process";
|
|
604670
604764
|
import { existsSync as existsSync112, mkdirSync as mkdirSync69, statSync as statSync43, unlinkSync as unlinkSync20 } from "node:fs";
|
|
604671
604765
|
import { join as join127 } from "node:path";
|
|
604672
|
-
function streamFps() {
|
|
604673
|
-
const raw = Number(process.env["OMNIUS_LIVE_STREAM_FPS"] ?? "");
|
|
604766
|
+
function streamFps(configured) {
|
|
604767
|
+
const raw = configured ?? Number(process.env["OMNIUS_LIVE_STREAM_FPS"] ?? "");
|
|
604674
604768
|
if (Number.isFinite(raw) && raw > 0) return Math.max(1, Math.min(30, Math.round(raw)));
|
|
604675
604769
|
return 8;
|
|
604676
604770
|
}
|
|
@@ -604751,7 +604845,7 @@ var init_camera_streamer = __esm({
|
|
|
604751
604845
|
* Only v4l2 device paths are streamable; other backends (OSC/WiFi cams)
|
|
604752
604846
|
* keep the one-shot capture path.
|
|
604753
604847
|
*/
|
|
604754
|
-
sync(sources, rotationFor, resolutionFor) {
|
|
604848
|
+
sync(sources, rotationFor, resolutionFor, fpsFor) {
|
|
604755
604849
|
const wanted = new Set(sources.filter((source) => source.startsWith("/dev/video")));
|
|
604756
604850
|
for (const [source, stream] of this.streams) {
|
|
604757
604851
|
if (!wanted.has(source)) {
|
|
@@ -604762,20 +604856,21 @@ var init_camera_streamer = __esm({
|
|
|
604762
604856
|
for (const source of wanted) {
|
|
604763
604857
|
const rotation = rotationFor(source);
|
|
604764
604858
|
const resolution = resolutionFor(source);
|
|
604859
|
+
const fps = streamFps(fpsFor(source));
|
|
604765
604860
|
const existing = this.streams.get(source);
|
|
604766
|
-
if (existing && existing.rotation === rotation && existing.resolution === resolution && !existing.stopped) continue;
|
|
604861
|
+
if (existing && existing.rotation === rotation && existing.resolution === resolution && existing.fps === fps && !existing.stopped) continue;
|
|
604767
604862
|
if (existing) {
|
|
604768
604863
|
this.stopStream(existing);
|
|
604769
604864
|
this.streams.delete(source);
|
|
604770
604865
|
}
|
|
604771
|
-
this.startStream(source, rotation, resolution);
|
|
604866
|
+
this.startStream(source, rotation, resolution, fps);
|
|
604772
604867
|
}
|
|
604773
604868
|
}
|
|
604774
604869
|
stopAll() {
|
|
604775
604870
|
for (const stream of this.streams.values()) this.stopStream(stream);
|
|
604776
604871
|
this.streams.clear();
|
|
604777
604872
|
}
|
|
604778
|
-
startStream(source, rotation, resolution) {
|
|
604873
|
+
startStream(source, rotation, resolution, fps) {
|
|
604779
604874
|
try {
|
|
604780
604875
|
mkdirSync69(this.streamDir, { recursive: true });
|
|
604781
604876
|
} catch {
|
|
@@ -604785,6 +604880,7 @@ var init_camera_streamer = __esm({
|
|
|
604785
604880
|
framePath: join127(this.streamDir, `${slugForSource(source)}.jpg`),
|
|
604786
604881
|
rotation,
|
|
604787
604882
|
resolution,
|
|
604883
|
+
fps,
|
|
604788
604884
|
process: null,
|
|
604789
604885
|
attempt: 0,
|
|
604790
604886
|
consecutiveFailures: 0,
|
|
@@ -604798,7 +604894,7 @@ var init_camera_streamer = __esm({
|
|
|
604798
604894
|
}
|
|
604799
604895
|
spawnStream(stream) {
|
|
604800
604896
|
if (stream.stopped) return;
|
|
604801
|
-
const fps = streamFps();
|
|
604897
|
+
const fps = streamFps(stream.fps);
|
|
604802
604898
|
const resolution = parseResolution(stream.resolution);
|
|
604803
604899
|
const filters = [`fps=${fps}`];
|
|
604804
604900
|
const scale = scaleFilter(resolution);
|
|
@@ -605482,6 +605578,17 @@ function formatLiveCameraResolution(value2) {
|
|
|
605482
605578
|
if (res === "3840x2160") return "4K (3840x2160)";
|
|
605483
605579
|
return res;
|
|
605484
605580
|
}
|
|
605581
|
+
function normalizeLiveCameraFps(value2) {
|
|
605582
|
+
if (value2 === void 0 || value2 === null || value2 === "") return DEFAULT_CAMERA_FPS;
|
|
605583
|
+
const parsed = typeof value2 === "number" ? value2 : Number(String(value2).trim().toLowerCase().replace(/\s*fps$/, ""));
|
|
605584
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
605585
|
+
throw new Error(`Unsupported live camera FPS: ${String(value2)}. Use a number from 1 to 30.`);
|
|
605586
|
+
}
|
|
605587
|
+
return Math.max(1, Math.min(30, Math.round(parsed)));
|
|
605588
|
+
}
|
|
605589
|
+
function formatLiveCameraFps(value2) {
|
|
605590
|
+
return `${normalizeLiveCameraFps(value2)} fps`;
|
|
605591
|
+
}
|
|
605485
605592
|
function liveCameraResolutionSize(value2) {
|
|
605486
605593
|
const res = value2 ?? DEFAULT_CAMERA_RESOLUTION;
|
|
605487
605594
|
if (res === "native") return null;
|
|
@@ -605499,10 +605606,11 @@ function sanitizeCameraStreams(value2) {
|
|
|
605499
605606
|
try {
|
|
605500
605607
|
out[device] = {
|
|
605501
605608
|
enabled: entry["enabled"] !== false,
|
|
605502
|
-
resolution: normalizeLiveCameraResolution(entry["resolution"] ?? DEFAULT_CAMERA_RESOLUTION)
|
|
605609
|
+
resolution: normalizeLiveCameraResolution(entry["resolution"] ?? DEFAULT_CAMERA_RESOLUTION),
|
|
605610
|
+
fps: normalizeLiveCameraFps(entry["fps"] ?? entry["framerate"] ?? DEFAULT_CAMERA_FPS)
|
|
605503
605611
|
};
|
|
605504
605612
|
} catch {
|
|
605505
|
-
out[device] = { enabled: entry["enabled"] !== false, resolution: DEFAULT_CAMERA_RESOLUTION };
|
|
605613
|
+
out[device] = { enabled: entry["enabled"] !== false, resolution: DEFAULT_CAMERA_RESOLUTION, fps: DEFAULT_CAMERA_FPS };
|
|
605506
605614
|
}
|
|
605507
605615
|
}
|
|
605508
605616
|
return out;
|
|
@@ -606641,7 +606749,7 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
|
|
|
606641
606749
|
const orientation = snapshot.config.cameraOrientation?.[snapshot.config.selectedCamera];
|
|
606642
606750
|
const stream = snapshot.config.cameraStreams?.[snapshot.config.selectedCamera];
|
|
606643
606751
|
lines.push(`Selected camera: ${snapshot.config.selectedCamera}`);
|
|
606644
|
-
lines.push(`Selected camera stream: ${stream?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(stream?.resolution)}`);
|
|
606752
|
+
lines.push(`Selected camera stream: ${stream?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(stream?.resolution)} ${formatLiveCameraFps(stream?.fps)}`);
|
|
606645
606753
|
lines.push(`Camera orientation correction: ${describeCameraOrientation(orientation)}`);
|
|
606646
606754
|
}
|
|
606647
606755
|
const cameraSnapshots = Object.values(snapshot.cameras ?? (snapshot.video ? { [snapshot.video.source]: snapshot.video } : {})).sort((a2, b) => {
|
|
@@ -607098,7 +607206,7 @@ function formatLiveStatus(snapshot) {
|
|
|
607098
607206
|
const lines = [
|
|
607099
607207
|
`Live streams: video=${cfg.videoEnabled ? "on" : "off"} infer=${cfg.inferEnabled ? "on" : "off"} clip=${cfg.clipEnabled ? "on" : "off"} audio=${cfg.audioEnabled ? "on" : "off"} asr=${cfg.asrEnabled ? "on" : "off"} sounds=${cfg.audioAnalysisEnabled ? "on" : "off"} output=${cfg.audioOutputEnabled ? "on" : "off"}`,
|
|
607100
607208
|
`Camera: ${cfg.selectedCamera || "none"}`,
|
|
607101
|
-
`Camera stream: ${cfg.selectedCamera ? `${cfg.cameraStreams?.[cfg.selectedCamera]?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(cfg.cameraStreams?.[cfg.selectedCamera]?.resolution)}` : "none"}`,
|
|
607209
|
+
`Camera stream: ${cfg.selectedCamera ? `${cfg.cameraStreams?.[cfg.selectedCamera]?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(cfg.cameraStreams?.[cfg.selectedCamera]?.resolution)} ${formatLiveCameraFps(cfg.cameraStreams?.[cfg.selectedCamera]?.fps)}` : "none"}`,
|
|
607102
607210
|
`Camera orientation: ${cfg.selectedCamera ? describeCameraOrientation(cfg.cameraOrientation?.[cfg.selectedCamera]) : "none"}`,
|
|
607103
607211
|
`Audio input: ${cfg.selectedAudioInput || "none"}`,
|
|
607104
607212
|
`Audio output: ${cfg.selectedAudioOutput || "none"}`,
|
|
@@ -607112,7 +607220,7 @@ function formatLiveStatus(snapshot) {
|
|
|
607112
607220
|
}
|
|
607113
607221
|
return lines.join("\n");
|
|
607114
607222
|
}
|
|
607115
|
-
var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, AUDIO_ACTIVITY_INTERVAL_MS, AUDIO_ACTIVITY_SAMPLE_SEC, DEFAULT_CAMERA_RESOLUTION, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, _liveDashboardMaximizedCamera, LiveSensorManager;
|
|
607223
|
+
var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, AUDIO_ACTIVITY_INTERVAL_MS, AUDIO_ACTIVITY_SAMPLE_SEC, DEFAULT_CAMERA_RESOLUTION, DEFAULT_CAMERA_FPS, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, _liveDashboardMaximizedCamera, LiveSensorManager;
|
|
607116
607224
|
var init_live_sensors = __esm({
|
|
607117
607225
|
"packages/cli/src/tui/live-sensors.ts"() {
|
|
607118
607226
|
"use strict";
|
|
@@ -607130,6 +607238,7 @@ var init_live_sensors = __esm({
|
|
|
607130
607238
|
AUDIO_ACTIVITY_INTERVAL_MS = 200;
|
|
607131
607239
|
AUDIO_ACTIVITY_SAMPLE_SEC = 0.2;
|
|
607132
607240
|
DEFAULT_CAMERA_RESOLUTION = "1920x1080";
|
|
607241
|
+
DEFAULT_CAMERA_FPS = 8;
|
|
607133
607242
|
DEFAULT_CONFIG7 = {
|
|
607134
607243
|
videoEnabled: false,
|
|
607135
607244
|
audioEnabled: false,
|
|
@@ -607339,7 +607448,8 @@ var init_live_sensors = __esm({
|
|
|
607339
607448
|
...this.config.cameraStreams ?? {},
|
|
607340
607449
|
[fallback]: {
|
|
607341
607450
|
enabled: true,
|
|
607342
|
-
resolution: this.config.cameraStreams?.[fallback]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
|
|
607451
|
+
resolution: this.config.cameraStreams?.[fallback]?.resolution ?? DEFAULT_CAMERA_RESOLUTION,
|
|
607452
|
+
fps: this.config.cameraStreams?.[fallback]?.fps ?? DEFAULT_CAMERA_FPS
|
|
607343
607453
|
}
|
|
607344
607454
|
}
|
|
607345
607455
|
};
|
|
@@ -607360,13 +607470,18 @@ var init_live_sensors = __esm({
|
|
|
607360
607470
|
const target = device || this.config.selectedCamera;
|
|
607361
607471
|
return target ? this.config.cameraStreams?.[target]?.resolution ?? DEFAULT_CAMERA_RESOLUTION : DEFAULT_CAMERA_RESOLUTION;
|
|
607362
607472
|
}
|
|
607473
|
+
getCameraStreamFps(device = this.config.selectedCamera) {
|
|
607474
|
+
const target = device || this.config.selectedCamera;
|
|
607475
|
+
return target ? normalizeLiveCameraFps(this.config.cameraStreams?.[target]?.fps ?? DEFAULT_CAMERA_FPS) : DEFAULT_CAMERA_FPS;
|
|
607476
|
+
}
|
|
607363
607477
|
setCameraStreamEnabled(device, enabled2) {
|
|
607364
607478
|
const target = device || this.config.selectedCamera;
|
|
607365
607479
|
if (!target) return null;
|
|
607366
607480
|
const current = this.config.cameraStreams?.[target];
|
|
607367
607481
|
const next = {
|
|
607368
607482
|
enabled: enabled2,
|
|
607369
|
-
resolution: current?.resolution ?? DEFAULT_CAMERA_RESOLUTION
|
|
607483
|
+
resolution: current?.resolution ?? DEFAULT_CAMERA_RESOLUTION,
|
|
607484
|
+
fps: current?.fps ?? DEFAULT_CAMERA_FPS
|
|
607370
607485
|
};
|
|
607371
607486
|
this.config = {
|
|
607372
607487
|
...this.config,
|
|
@@ -607388,7 +607503,30 @@ var init_live_sensors = __esm({
|
|
|
607388
607503
|
const current = this.config.cameraStreams?.[target];
|
|
607389
607504
|
const next = {
|
|
607390
607505
|
enabled: current?.enabled ?? target === this.config.selectedCamera,
|
|
607391
|
-
resolution: normalizeLiveCameraResolution(resolution)
|
|
607506
|
+
resolution: normalizeLiveCameraResolution(resolution),
|
|
607507
|
+
fps: current?.fps ?? DEFAULT_CAMERA_FPS
|
|
607508
|
+
};
|
|
607509
|
+
this.config = {
|
|
607510
|
+
...this.config,
|
|
607511
|
+
cameraStreams: {
|
|
607512
|
+
...this.config.cameraStreams ?? {},
|
|
607513
|
+
[target]: next
|
|
607514
|
+
}
|
|
607515
|
+
};
|
|
607516
|
+
this.videoGeneration++;
|
|
607517
|
+
this.lastStreamFrameMtime.delete(target);
|
|
607518
|
+
this.persist();
|
|
607519
|
+
this.ensureLoops();
|
|
607520
|
+
return next;
|
|
607521
|
+
}
|
|
607522
|
+
setCameraStreamFps(device, fps) {
|
|
607523
|
+
const target = device || this.config.selectedCamera;
|
|
607524
|
+
if (!target) return null;
|
|
607525
|
+
const current = this.config.cameraStreams?.[target];
|
|
607526
|
+
const next = {
|
|
607527
|
+
enabled: current?.enabled ?? target === this.config.selectedCamera,
|
|
607528
|
+
resolution: current?.resolution ?? DEFAULT_CAMERA_RESOLUTION,
|
|
607529
|
+
fps: normalizeLiveCameraFps(fps)
|
|
607392
607530
|
};
|
|
607393
607531
|
this.config = {
|
|
607394
607532
|
...this.config,
|
|
@@ -607642,7 +607780,8 @@ var init_live_sensors = __esm({
|
|
|
607642
607780
|
if (!device.id || /metadata\/non-capture/i.test(device.detail ?? "")) continue;
|
|
607643
607781
|
next[device.id] = {
|
|
607644
607782
|
enabled: current[device.id]?.enabled ?? device.id === selected,
|
|
607645
|
-
resolution: current[device.id]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
|
|
607783
|
+
resolution: current[device.id]?.resolution ?? DEFAULT_CAMERA_RESOLUTION,
|
|
607784
|
+
fps: current[device.id]?.fps ?? DEFAULT_CAMERA_FPS
|
|
607646
607785
|
};
|
|
607647
607786
|
}
|
|
607648
607787
|
return next;
|
|
@@ -607662,7 +607801,8 @@ var init_live_sensors = __esm({
|
|
|
607662
607801
|
...this.config.cameraStreams ?? {},
|
|
607663
607802
|
[selected]: {
|
|
607664
607803
|
enabled: true,
|
|
607665
|
-
resolution: this.config.cameraStreams?.[selected]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
|
|
607804
|
+
resolution: this.config.cameraStreams?.[selected]?.resolution ?? DEFAULT_CAMERA_RESOLUTION,
|
|
607805
|
+
fps: this.config.cameraStreams?.[selected]?.fps ?? DEFAULT_CAMERA_FPS
|
|
607666
607806
|
}
|
|
607667
607807
|
};
|
|
607668
607808
|
}
|
|
@@ -607882,7 +608022,8 @@ var init_live_sensors = __esm({
|
|
|
607882
608022
|
action: "capture",
|
|
607883
608023
|
device: source,
|
|
607884
608024
|
rotate_degrees: rotation,
|
|
607885
|
-
...captureSize ? { width: captureSize.width, height: captureSize.height } : {}
|
|
608025
|
+
...captureSize ? { width: captureSize.width, height: captureSize.height } : {},
|
|
608026
|
+
framerate: this.getCameraStreamFps(source)
|
|
607886
608027
|
});
|
|
607887
608028
|
if (!this.isVideoWorkCurrent(generation)) return { ok: false, message: "Video context is disabled." };
|
|
607888
608029
|
if (!result.success) {
|
|
@@ -608502,7 +608643,8 @@ ${analysis}` : ""
|
|
|
608502
608643
|
this.cameraStreamers.sync(
|
|
608503
608644
|
this.activeVideoSources(),
|
|
608504
608645
|
(source) => this.getCameraOrientation(source)?.rotation ?? 0,
|
|
608505
|
-
(source) => this.getCameraStreamResolution(source)
|
|
608646
|
+
(source) => this.getCameraStreamResolution(source),
|
|
608647
|
+
(source) => this.getCameraStreamFps(source)
|
|
608506
608648
|
);
|
|
608507
608649
|
}
|
|
608508
608650
|
previewTickIntervalMs() {
|
|
@@ -613305,12 +613447,16 @@ var init_command_registry = __esm({
|
|
|
613305
613447
|
["/livechat", "Alias for /live chat, used by the top live button"],
|
|
613306
613448
|
["/live camera <device>", "Select a camera and render an ASCII preview"],
|
|
613307
613449
|
["/live resolution [camera] 720p|1080p|1440p|4k|native", "Set per-camera live stream resolution (default 1080p)"],
|
|
613450
|
+
["/live fps [camera] 1|2|4|8|12|15|24|30", "Set per-camera live stream FPS (default 8)"],
|
|
613308
613451
|
["/live camera-on|camera-off [camera]", "Enable or disable an individual live camera stream"],
|
|
613309
613452
|
["/live rotate auto|cw|ccw|180|none [camera]", "Detect or set persistent camera orientation correction"],
|
|
613310
613453
|
["/live infer [now|on|off]", "Toggle or run camera object/location inference"],
|
|
613311
613454
|
["/live clip [on|off]", "Toggle CLIP visual-memory recognition on live frames"],
|
|
613312
613455
|
["/live audio|asr|sounds on|off", "Toggle live audio context streams"],
|
|
613313
613456
|
["/live stop", "Disable all live sensor streams"],
|
|
613457
|
+
["/camera", "Open compact camera preset menu shared with /live"],
|
|
613458
|
+
["/camera status", "Show selected camera and per-device presets"],
|
|
613459
|
+
["/camera select|preview|resolution|fps|rotate", "Manage camera source, preview, resolution, FPS, and orientation"],
|
|
613314
613460
|
["/paste", "Attach clipboard image content to the current or next prompt"],
|
|
613315
613461
|
["/image", "Open image-generation model/setup menu"],
|
|
613316
613462
|
[
|
|
@@ -653830,6 +653976,10 @@ sleep 1
|
|
|
653830
653976
|
await handleLiveCommand(ctx3, arg);
|
|
653831
653977
|
return "handled";
|
|
653832
653978
|
}
|
|
653979
|
+
case "camera": {
|
|
653980
|
+
await handleCameraCommand(ctx3, arg);
|
|
653981
|
+
return "handled";
|
|
653982
|
+
}
|
|
653833
653983
|
case "livechat": {
|
|
653834
653984
|
await handleLiveCommand(ctx3, "chat");
|
|
653835
653985
|
return "handled";
|
|
@@ -659588,7 +659738,7 @@ async function chooseLiveDevice(ctx3, title, devices, activeKey) {
|
|
|
659588
659738
|
return devices.find((device) => device.id === result.key) ?? null;
|
|
659589
659739
|
}
|
|
659590
659740
|
function liveCameraStreamSummary(manager, deviceId) {
|
|
659591
|
-
return `${manager.isCameraStreamEnabled(deviceId) ? liveEnabled(true) : liveEnabled(false)} · ${formatLiveCameraResolution(manager.getCameraStreamResolution(deviceId))} · ${formatCameraRotation(manager.getCameraRotation(deviceId))}`;
|
|
659741
|
+
return `${manager.isCameraStreamEnabled(deviceId) ? liveEnabled(true) : liveEnabled(false)} · ${formatLiveCameraResolution(manager.getCameraStreamResolution(deviceId))} · ${formatLiveCameraFps(manager.getCameraStreamFps(deviceId))} · ${formatCameraRotation(manager.getCameraRotation(deviceId))}`;
|
|
659592
659742
|
}
|
|
659593
659743
|
async function chooseLiveCameraResolution(ctx3, manager, deviceId) {
|
|
659594
659744
|
const current = manager.getCameraStreamResolution(deviceId);
|
|
@@ -659607,11 +659757,29 @@ async function chooseLiveCameraResolution(ctx3, manager, deviceId) {
|
|
|
659607
659757
|
if (!result.confirmed || !result.key) return null;
|
|
659608
659758
|
return normalizeLiveCameraResolution(result.key);
|
|
659609
659759
|
}
|
|
659760
|
+
async function chooseLiveCameraFps(ctx3, manager, deviceId) {
|
|
659761
|
+
const current = manager.getCameraStreamFps(deviceId);
|
|
659762
|
+
const choices = [1, 2, 4, 8, 12, 15, 24, 30];
|
|
659763
|
+
const result = await tuiSelect({
|
|
659764
|
+
items: choices.map((fps) => ({
|
|
659765
|
+
key: String(fps),
|
|
659766
|
+
label: formatLiveCameraFps(fps),
|
|
659767
|
+
detail: fps <= 4 ? "lowest hardware burden" : fps === 8 ? "default balanced live stream rate" : "smoother preview, higher camera/CPU burden"
|
|
659768
|
+
})),
|
|
659769
|
+
title: `Camera FPS — ${deviceId}`,
|
|
659770
|
+
activeKey: String(current),
|
|
659771
|
+
rl: ctx3.rl,
|
|
659772
|
+
availableRows: ctx3.availableContentRows?.()
|
|
659773
|
+
});
|
|
659774
|
+
if (!result.confirmed || !result.key) return null;
|
|
659775
|
+
return normalizeLiveCameraFps(result.key);
|
|
659776
|
+
}
|
|
659610
659777
|
async function showLiveCameraMenu(ctx3, manager, device) {
|
|
659611
659778
|
while (true) {
|
|
659612
659779
|
const selected = manager.getConfig().selectedCamera === device.id;
|
|
659613
659780
|
const enabled2 = manager.isCameraStreamEnabled(device.id);
|
|
659614
659781
|
const resolution = manager.getCameraStreamResolution(device.id);
|
|
659782
|
+
const fps = manager.getCameraStreamFps(device.id);
|
|
659615
659783
|
const items = [
|
|
659616
659784
|
{ key: "hdr:camera", label: selectColors.dim(`─── Camera ${device.id} ───`) },
|
|
659617
659785
|
{
|
|
@@ -659633,6 +659801,11 @@ async function showLiveCameraMenu(ctx3, manager, device) {
|
|
|
659633
659801
|
label: "Set Stream Resolution",
|
|
659634
659802
|
detail: formatLiveCameraResolution(resolution)
|
|
659635
659803
|
},
|
|
659804
|
+
{
|
|
659805
|
+
key: "fps",
|
|
659806
|
+
label: "Set Stream FPS",
|
|
659807
|
+
detail: formatLiveCameraFps(fps)
|
|
659808
|
+
},
|
|
659636
659809
|
{
|
|
659637
659810
|
key: "preview",
|
|
659638
659811
|
label: "Preview Camera",
|
|
@@ -659685,6 +659858,14 @@ async function showLiveCameraMenu(ctx3, manager, device) {
|
|
|
659685
659858
|
}
|
|
659686
659859
|
continue;
|
|
659687
659860
|
}
|
|
659861
|
+
case "fps": {
|
|
659862
|
+
const next = await chooseLiveCameraFps(ctx3, manager, device.id);
|
|
659863
|
+
if (next) {
|
|
659864
|
+
manager.setCameraStreamFps(device.id, next);
|
|
659865
|
+
renderInfo(`Camera ${device.id} stream FPS set to ${formatLiveCameraFps(next)}.`);
|
|
659866
|
+
}
|
|
659867
|
+
continue;
|
|
659868
|
+
}
|
|
659688
659869
|
case "preview":
|
|
659689
659870
|
renderLivePreview(await manager.previewCamera(device.id));
|
|
659690
659871
|
continue;
|
|
@@ -659808,6 +659989,28 @@ async function handleLiveCommand(ctx3, arg) {
|
|
|
659808
659989
|
}
|
|
659809
659990
|
return;
|
|
659810
659991
|
}
|
|
659992
|
+
if (sub2 === "fps" || sub2 === "framerate" || sub2 === "rate") {
|
|
659993
|
+
await ensureLiveInventory(manager);
|
|
659994
|
+
const tokens = parts.slice(1);
|
|
659995
|
+
const rawFps = tokens.pop();
|
|
659996
|
+
if (!rawFps) {
|
|
659997
|
+
renderWarning("Usage: /live fps [camera] 1|2|4|8|12|15|24|30");
|
|
659998
|
+
return;
|
|
659999
|
+
}
|
|
660000
|
+
const device = tokens.join(" ") || manager.getConfig().selectedCamera;
|
|
660001
|
+
if (!device) {
|
|
660002
|
+
renderWarning("No camera selected. Use /live camera <device> first.");
|
|
660003
|
+
return;
|
|
660004
|
+
}
|
|
660005
|
+
try {
|
|
660006
|
+
const fps = normalizeLiveCameraFps(rawFps);
|
|
660007
|
+
manager.setCameraStreamFps(device, fps);
|
|
660008
|
+
renderInfo(`Camera ${device} stream FPS set to ${formatLiveCameraFps(fps)}.`);
|
|
660009
|
+
} catch (err) {
|
|
660010
|
+
renderWarning(err instanceof Error ? err.message : String(err));
|
|
660011
|
+
}
|
|
660012
|
+
return;
|
|
660013
|
+
}
|
|
659811
660014
|
if (sub2 === "camera-on" || sub2 === "camera-off" || sub2 === "camera-enable" || sub2 === "camera-disable") {
|
|
659812
660015
|
await ensureLiveInventory(manager);
|
|
659813
660016
|
const device = value2 || manager.getConfig().selectedCamera;
|
|
@@ -659906,6 +660109,222 @@ async function handleLiveCommand(ctx3, arg) {
|
|
|
659906
660109
|
}
|
|
659907
660110
|
await showLiveMenu(ctx3, manager);
|
|
659908
660111
|
}
|
|
660112
|
+
function formatCameraStatus(manager) {
|
|
660113
|
+
const snapshot = manager.getSnapshot();
|
|
660114
|
+
const cfg = manager.getConfig();
|
|
660115
|
+
const lines = [
|
|
660116
|
+
`Selected camera: ${cfg.selectedCamera || "none"}`,
|
|
660117
|
+
`Video context: ${cfg.videoEnabled ? "enabled" : "disabled"}`,
|
|
660118
|
+
`Camera devices: ${snapshot.devices.video.length}`
|
|
660119
|
+
];
|
|
660120
|
+
for (const device of snapshot.devices.video) {
|
|
660121
|
+
lines.push(`- ${device.id}: ${liveCameraStreamSummary(manager, device.id)} — ${device.label}${device.detail ? ` — ${device.detail}` : ""}`);
|
|
660122
|
+
}
|
|
660123
|
+
return lines.join("\n");
|
|
660124
|
+
}
|
|
660125
|
+
async function showCameraMenu(ctx3, manager) {
|
|
660126
|
+
await ensureLiveInventory(manager);
|
|
660127
|
+
while (true) {
|
|
660128
|
+
const snapshot = manager.getSnapshot();
|
|
660129
|
+
const cfg = manager.getConfig();
|
|
660130
|
+
const devices = snapshot.devices.video;
|
|
660131
|
+
const items = [
|
|
660132
|
+
{ key: "hdr:camera", label: selectColors.dim("─── Camera Presets ───") },
|
|
660133
|
+
{
|
|
660134
|
+
key: "info:camera",
|
|
660135
|
+
label: selectColors.dim(` selected ${cfg.selectedCamera || "none"} · video ${liveEnabled(cfg.videoEnabled)} · ${devices.length} device(s)`)
|
|
660136
|
+
},
|
|
660137
|
+
{
|
|
660138
|
+
key: "select",
|
|
660139
|
+
label: "Select Primary Camera",
|
|
660140
|
+
detail: liveDeviceSummary(devices, cfg.selectedCamera)
|
|
660141
|
+
},
|
|
660142
|
+
{
|
|
660143
|
+
key: "preview",
|
|
660144
|
+
label: "Preview Selected Camera",
|
|
660145
|
+
detail: "uses selected resolution, fps, and orientation preset"
|
|
660146
|
+
},
|
|
660147
|
+
{
|
|
660148
|
+
key: "toggle-video",
|
|
660149
|
+
label: cfg.videoEnabled ? "Disable Video Context" : "Enable Video Context",
|
|
660150
|
+
detail: "does not delete camera presets"
|
|
660151
|
+
},
|
|
660152
|
+
...devices.map((device, index) => ({
|
|
660153
|
+
key: `camera-device:${index}`,
|
|
660154
|
+
label: `Camera: ${device.id}`,
|
|
660155
|
+
detail: `${liveCameraStreamSummary(manager, device.id)} — ${device.label}${device.detail ? ` — ${device.detail}` : ""}`
|
|
660156
|
+
})),
|
|
660157
|
+
{ key: "refresh", label: "Refresh Devices", detail: "rescan /dev/video* and audio/video inventory" },
|
|
660158
|
+
{ key: "status", label: "Show Camera Status", detail: "selected camera and per-device presets" }
|
|
660159
|
+
];
|
|
660160
|
+
const result = await tuiSelect({
|
|
660161
|
+
items,
|
|
660162
|
+
title: "Camera Presets",
|
|
660163
|
+
activeKey: cfg.selectedCamera ? "preview" : "select",
|
|
660164
|
+
rl: ctx3.rl,
|
|
660165
|
+
availableRows: ctx3.availableContentRows?.(),
|
|
660166
|
+
skipKeys: liveSkipKeys(items),
|
|
660167
|
+
customKeyHint: " r refresh",
|
|
660168
|
+
onCustomKey(_item, key, helpers) {
|
|
660169
|
+
if (key === "r" || key === "R") {
|
|
660170
|
+
void manager.refreshDevices().then(() => helpers.done()).catch(() => helpers.done());
|
|
660171
|
+
return true;
|
|
660172
|
+
}
|
|
660173
|
+
return false;
|
|
660174
|
+
}
|
|
660175
|
+
});
|
|
660176
|
+
if (!result.confirmed || !result.key) return;
|
|
660177
|
+
if (result.key.startsWith("camera-device:")) {
|
|
660178
|
+
const index = Number(result.key.slice("camera-device:".length));
|
|
660179
|
+
const device = devices[index];
|
|
660180
|
+
if (device) await showLiveCameraMenu(ctx3, manager, device);
|
|
660181
|
+
continue;
|
|
660182
|
+
}
|
|
660183
|
+
switch (result.key) {
|
|
660184
|
+
case "select": {
|
|
660185
|
+
const device = await chooseLiveDevice(ctx3, "Select Camera", devices, cfg.selectedCamera);
|
|
660186
|
+
if (device) {
|
|
660187
|
+
manager.configure({ selectedCamera: device.id, videoEnabled: true });
|
|
660188
|
+
manager.setCameraStreamEnabled(device.id, true);
|
|
660189
|
+
renderInfo(`Selected camera ${device.id}.`);
|
|
660190
|
+
}
|
|
660191
|
+
continue;
|
|
660192
|
+
}
|
|
660193
|
+
case "preview":
|
|
660194
|
+
renderLivePreview(await manager.previewCamera(cfg.selectedCamera));
|
|
660195
|
+
continue;
|
|
660196
|
+
case "toggle-video":
|
|
660197
|
+
manager.configure({ videoEnabled: !cfg.videoEnabled });
|
|
660198
|
+
continue;
|
|
660199
|
+
case "refresh":
|
|
660200
|
+
renderInfo(formatLiveInventory(await manager.refreshDevices()));
|
|
660201
|
+
continue;
|
|
660202
|
+
case "status":
|
|
660203
|
+
renderInfo(formatCameraStatus(manager));
|
|
660204
|
+
continue;
|
|
660205
|
+
default:
|
|
660206
|
+
return;
|
|
660207
|
+
}
|
|
660208
|
+
}
|
|
660209
|
+
}
|
|
660210
|
+
async function handleCameraCommand(ctx3, arg) {
|
|
660211
|
+
const manager = getLiveSensorManager(ctx3.repoRoot);
|
|
660212
|
+
attachLiveSinks(ctx3, manager);
|
|
660213
|
+
const parts = arg.trim().split(/\s+/).filter(Boolean);
|
|
660214
|
+
const sub2 = (parts[0] || "").toLowerCase();
|
|
660215
|
+
const value2 = parts.slice(1).join(" ");
|
|
660216
|
+
if (sub2 === "status") {
|
|
660217
|
+
await ensureLiveInventory(manager);
|
|
660218
|
+
renderInfo(formatCameraStatus(manager));
|
|
660219
|
+
return;
|
|
660220
|
+
}
|
|
660221
|
+
if (sub2 === "refresh" || sub2 === "devices" || sub2 === "list") {
|
|
660222
|
+
renderInfo(formatLiveInventory(await manager.refreshDevices()));
|
|
660223
|
+
return;
|
|
660224
|
+
}
|
|
660225
|
+
if (sub2 === "preview" || sub2 === "view" || sub2 === "capture") {
|
|
660226
|
+
await ensureLiveInventory(manager);
|
|
660227
|
+
renderLivePreview(await manager.previewCamera(value2 || manager.getConfig().selectedCamera));
|
|
660228
|
+
return;
|
|
660229
|
+
}
|
|
660230
|
+
if (sub2 === "select" || sub2 === "use") {
|
|
660231
|
+
await ensureLiveInventory(manager);
|
|
660232
|
+
const device = value2;
|
|
660233
|
+
if (!device) {
|
|
660234
|
+
const selected = await chooseLiveDevice(ctx3, "Select Camera", manager.getSnapshot().devices.video, manager.getConfig().selectedCamera);
|
|
660235
|
+
if (selected) {
|
|
660236
|
+
manager.configure({ selectedCamera: selected.id, videoEnabled: true });
|
|
660237
|
+
manager.setCameraStreamEnabled(selected.id, true);
|
|
660238
|
+
renderInfo(`Selected camera ${selected.id}.`);
|
|
660239
|
+
}
|
|
660240
|
+
return;
|
|
660241
|
+
}
|
|
660242
|
+
manager.configure({ selectedCamera: device, videoEnabled: true });
|
|
660243
|
+
manager.setCameraStreamEnabled(device, true);
|
|
660244
|
+
renderInfo(`Selected camera ${device}.`);
|
|
660245
|
+
return;
|
|
660246
|
+
}
|
|
660247
|
+
if (sub2 === "on" || sub2 === "enable" || sub2 === "off" || sub2 === "disable") {
|
|
660248
|
+
await ensureLiveInventory(manager);
|
|
660249
|
+
const device = value2 || manager.getConfig().selectedCamera;
|
|
660250
|
+
if (!device) {
|
|
660251
|
+
renderWarning("No camera selected. Use /camera select <device> first.");
|
|
660252
|
+
return;
|
|
660253
|
+
}
|
|
660254
|
+
const enabled2 = sub2 === "on" || sub2 === "enable";
|
|
660255
|
+
manager.setCameraStreamEnabled(device, enabled2);
|
|
660256
|
+
renderInfo(`${enabled2 ? "Enabled" : "Disabled"} camera stream ${device}.`);
|
|
660257
|
+
return;
|
|
660258
|
+
}
|
|
660259
|
+
if (sub2 === "resolution" || sub2 === "res" || sub2 === "size") {
|
|
660260
|
+
await ensureLiveInventory(manager);
|
|
660261
|
+
const tokens = parts.slice(1);
|
|
660262
|
+
const rawResolution = tokens.pop();
|
|
660263
|
+
if (!rawResolution) {
|
|
660264
|
+
renderWarning("Usage: /camera resolution [camera] 720p|1080p|1440p|4k|native");
|
|
660265
|
+
return;
|
|
660266
|
+
}
|
|
660267
|
+
const device = tokens.join(" ") || manager.getConfig().selectedCamera;
|
|
660268
|
+
if (!device) {
|
|
660269
|
+
renderWarning("No camera selected. Use /camera select <device> first.");
|
|
660270
|
+
return;
|
|
660271
|
+
}
|
|
660272
|
+
try {
|
|
660273
|
+
const resolution = normalizeLiveCameraResolution(rawResolution);
|
|
660274
|
+
manager.setCameraStreamResolution(device, resolution);
|
|
660275
|
+
renderInfo(`Camera ${device} stream resolution set to ${formatLiveCameraResolution(resolution)}.`);
|
|
660276
|
+
} catch (err) {
|
|
660277
|
+
renderWarning(err instanceof Error ? err.message : String(err));
|
|
660278
|
+
}
|
|
660279
|
+
return;
|
|
660280
|
+
}
|
|
660281
|
+
if (sub2 === "fps" || sub2 === "framerate" || sub2 === "rate") {
|
|
660282
|
+
await ensureLiveInventory(manager);
|
|
660283
|
+
const tokens = parts.slice(1);
|
|
660284
|
+
const rawFps = tokens.pop();
|
|
660285
|
+
if (!rawFps) {
|
|
660286
|
+
renderWarning("Usage: /camera fps [camera] 1|2|4|8|12|15|24|30");
|
|
660287
|
+
return;
|
|
660288
|
+
}
|
|
660289
|
+
const device = tokens.join(" ") || manager.getConfig().selectedCamera;
|
|
660290
|
+
if (!device) {
|
|
660291
|
+
renderWarning("No camera selected. Use /camera select <device> first.");
|
|
660292
|
+
return;
|
|
660293
|
+
}
|
|
660294
|
+
try {
|
|
660295
|
+
const fps = normalizeLiveCameraFps(rawFps);
|
|
660296
|
+
manager.setCameraStreamFps(device, fps);
|
|
660297
|
+
renderInfo(`Camera ${device} stream FPS set to ${formatLiveCameraFps(fps)}.`);
|
|
660298
|
+
} catch (err) {
|
|
660299
|
+
renderWarning(err instanceof Error ? err.message : String(err));
|
|
660300
|
+
}
|
|
660301
|
+
return;
|
|
660302
|
+
}
|
|
660303
|
+
if (sub2 === "rotate" || sub2 === "rotation" || sub2 === "orient" || sub2 === "orientation") {
|
|
660304
|
+
await ensureLiveInventory(manager);
|
|
660305
|
+
const mode = (parts[1] || "cycle").toLowerCase();
|
|
660306
|
+
const deviceArg = parts.slice(2).join(" ") || manager.getConfig().selectedCamera;
|
|
660307
|
+
if (mode === "auto" || mode === "detect") {
|
|
660308
|
+
renderInfo("Detecting camera orientation...");
|
|
660309
|
+
renderInfo(await manager.autoOrientCamera(deviceArg));
|
|
660310
|
+
return;
|
|
660311
|
+
}
|
|
660312
|
+
if (mode === "cycle") {
|
|
660313
|
+
const orientation = manager.cycleCameraRotation(deviceArg);
|
|
660314
|
+
renderInfo(orientation ? `Camera rotation set to ${formatCameraRotation(orientation.rotation)} for ${deviceArg || manager.getConfig().selectedCamera || "selected camera"}.` : "No camera selected. Use /camera select <device> first.");
|
|
660315
|
+
return;
|
|
660316
|
+
}
|
|
660317
|
+
try {
|
|
660318
|
+
const rotation = normalizeLiveCameraRotation(mode);
|
|
660319
|
+
const orientation = manager.setCameraRotation(deviceArg, rotation, "manual", `/camera rotate ${mode}`);
|
|
660320
|
+
renderInfo(orientation ? `Camera rotation set to ${formatCameraRotation(orientation.rotation)} for ${deviceArg || manager.getConfig().selectedCamera || "selected camera"}.` : "No camera selected. Use /camera select <device> first.");
|
|
660321
|
+
} catch (err) {
|
|
660322
|
+
renderWarning(err instanceof Error ? err.message : String(err));
|
|
660323
|
+
}
|
|
660324
|
+
return;
|
|
660325
|
+
}
|
|
660326
|
+
await showCameraMenu(ctx3, manager);
|
|
660327
|
+
}
|
|
659909
660328
|
async function showLiveMenu(ctx3, manager) {
|
|
659910
660329
|
await ensureLiveInventory(manager);
|
|
659911
660330
|
while (true) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.435",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.435",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED