Redesign cang as snapshot-first NVR: events UI, snapshot DB, tiered retention #102
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Cang currently treats video clips as the primary artefact, with snapshots as secondary metadata attached to clips. This design is unsatisfying because:
The camera already does reliable motion detection and marks snapshot files with [M] (motion) vs [F] (first-frame/background). This gives us a clean event signal without any video analysis.
Proposed changes:
snapshotsDB table, not just those matching clipsFindings from test data
The incoming directory for one camera was examined. Key observations:
<serial>/<YYYY-MM-DD>/<channel>/jpg/<HH>/<MM>/<SS>[FLAG][0@0][0].jpgPlan of attack
New module:
src/cang/events.py— pure functiongroup_into_events(snapshots, gap_seconds=60)that clusters consecutive [M] rows into events when the gap between them is < threshold.Key file changes (TDD, each with a commit):
adapters/base.py+adapters/dahua.py— addIncomingSnapshotdataclass andscan_snapshots()that walks the full jpg/ treedb.py— migration v3:snapshotstable with unique index on path; new queries:insert_snapshot,list_snapshots_for_day,list_days_with_snapshot_stats,delete_expired_snapshots, renamedelete_expired→delete_expired_clipsconfig.py+pipeline.py— addretention_days/background_retention_days/video_retention_daystoServerConfig; simplify_delete_sourceto only delete .davweb/lifespan.py— add_scan_snapshots_for_cameraand_run_cleanupwired into startup and periodic scansevents.py— gap-based event grouperroutes/clips.py(events grid on day view, clips in<details>),routes/snapshots.py(DB-backed, time-window filtering), updated templatesFull implementation plan:
docs/superpowers/plans/2026-07-09-snapshot-first-nvr.md