cameras: split camera enable (Вкл) from REC (record-to-disk)

Add a separate `record` field so a camera can be registered but fully
off, or on but not recording:
- enabled (Вкл): camera on/off. Disabled = no go2rtc stream (no live),
  no recording; entry is just stored. build_streams/sync_all/reconcile
  skip disabled cameras; live grid shows "камера выключена".
- record (REC): write segments to disk. Recorder runs only when
  enabled AND record.

Unified POST /api/cameras/{id}/toggle {enabled?, record?} (replaces the
/record endpoint); go2rtc is touched only when `enabled` changes, so
flipping REC doesn't blip live. Camera table gets Вкл + Запись toggle
columns; add/edit forms get both switches.

load_config migrates the old schema (no `record` key): old `enabled`
meant "record" with live always on -> enabled=True, record=old enabled.

VERSION -> 0.0.126.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 18:35:26 +05:00
parent 7060f26e86
commit 24155a8492
7 changed files with 97 additions and 44 deletions
+3 -3
View File
@@ -26,11 +26,11 @@ class Supervisor:
task = RecorderTask(cam, self.config.storage, on_status=self.on_status,
input_url=self._input_url(cam))
self.tasks[cam.id] = task
if cam.enabled:
if cam.enabled and cam.record:
task.start()
log.info("recorder started: %s", cam.id)
else:
log.info("recorder skipped (disabled): %s", cam.id)
log.info("recorder skipped (enabled=%s record=%s): %s", cam.enabled, cam.record, cam.id)
async def stop_all(self) -> None:
for task in self.tasks.values():
@@ -60,7 +60,7 @@ class Supervisor:
task = RecorderTask(cam, self.config.storage, on_status=self.on_status,
input_url=self._input_url(cam))
self.tasks[cam.id] = task
if cam.enabled:
if cam.enabled and cam.record:
task.start()
log.info("recorder added: %s", cam.id)