storage: per-camera target + date subfolders; move active-storage widget
- Camera.storage_id: each camera chooses its storage ("" = active/default).
supervisor resolves per-camera (storage_by_id → active fallback); cameras
API (body/payload) + /toggle accept storage_id and repoint the recorder.
- Recordings now go to <root>/<cam>/<YYYY-MM-DD>/<file>.mp4. This ffmpeg build
lacks -strftime_mkdir, so recorder_task pre-creates today+tomorrow dirs at
start and the indexer re-ensures them each tick (survives midnight).
- indexer: scan date subdirs + legacy flat files; sort by basename so the
in-progress segment is detected correctly when both layouts coexist.
- frontend: per-camera "Хранилище" dropdown in the camera table (inline) and
in the add/edit + bulk forms. Move the active-storage summary widget from
the Система tab into the Хранилища tab.
VERSION 0.0.129.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ class Camera:
|
||||
main_path: str
|
||||
sub_path: str | None = None
|
||||
record: bool = True # REC: писать на диск. enabled — камера вообще включена (live+запись)
|
||||
storage_id: str = "" # в какое хранилище писать ("" = активное/по умолчанию)
|
||||
|
||||
def rtsp_url(self, path: str) -> str:
|
||||
return f"rtsp://{self.user}:{self.password}@{self.ip}:554{path}"
|
||||
@@ -141,6 +142,7 @@ def _camera_from_raw(c: dict) -> Camera:
|
||||
password=c["password"],
|
||||
main_path=c["main_path"],
|
||||
sub_path=c.get("sub_path"),
|
||||
storage_id=c.get("storage_id", "") or "",
|
||||
)
|
||||
|
||||
|
||||
@@ -198,6 +200,7 @@ def camera_to_yaml(c: Camera) -> dict:
|
||||
"password": c.password,
|
||||
"main_path": c.main_path,
|
||||
"sub_path": c.sub_path,
|
||||
"storage_id": c.storage_id,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user