Add local dashcam video library

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-09 19:04:47 -04:00
co-authored by Copilot
parent c57457b934
commit 3a981f5c6d
14 changed files with 659 additions and 29 deletions
+31 -1
View File
@@ -868,7 +868,7 @@ Phase 15 shared list component:
original 87 files/29,615,111,758 bytes unmounted. The refined UI was then re-tested against a
real existing video: it reported one skip, cleared the checkbox, and re-enabled all controls.
### Phase 17: Local imported-video browser + player — 🚧 PLANNED
### Phase 17: Local imported-video browser + player — ✅ DONE
Same file-browser treatment for videos already imported to the Pi's own disk
(`dash/videos/`, populated by `import_dashcam()`), built on the Phase 15 shared list component:
- List endpoint (reuses `find_video_files()` against `app_dash.DEFAULT_DESTINATION`) showing
@@ -895,6 +895,36 @@ Same file-browser treatment for videos already imported to the Pi's own disk
Settings page - e.g. "delete local copies older than N days once uploaded", off by default)
so the Pi's limited storage doesn't need to be babysat manually as the dashcam backlog grows.
**Implemented and real-hardware verified 2026-08-09**:
- Added local-video list, playback, thumbnail, and local-only delete APIs. Listing reports path,
size, modified time, and exact upload status without rehashing: one SQLite join matches the
existing `(relative path, size, mtime) -> SHA256` cache against confirmed uploads.
- Added a second `/dash` browser using the Phase 15 table component, with lazy thumbnails, sortable
file/size/time/upload columns, Uploaded/Pending badges, inline HTML5 video playback, confirmed
"Delete local" actions, totals, and retention status. Remote copies are never deleted.
- Playback uses Flask conditional file serving; a real `Range: bytes=0-1023` request returned 206,
the exact `Content-Range`, and 1,024 bytes. Browser-tested a real H.264 1080p MOV at mobile width:
the player reached readyState 4 with its duration loaded and no media error.
- Added cached ffmpeg JPEG thumbnails plus `deploy/install_video_tools.sh`; installed ffmpeg 5.1.9
on the Pi. Real clips exposed and fixed the edge case where ffmpeg exits 0 without output at a
late seek, so generation now retries frame zero and verifies a non-empty file. A normal 366MB
clip generated in ~4.1s and its cached request returned in ~81ms. Generation uses a cooperative
gevent semaphore/poll loop so cold thumbnails do not freeze the web server.
- Added off-by-default `local_video_retention_days` support. The upload loop checks it after sync;
only files older than N days whose exact current content is confirmed uploaded are eligible.
The Phase 21 Settings page will expose the control; `0`/unset remains disabled. Temporary
filesystem tests confirmed disabled retention deletes nothing and enabled retention preserves
pending files.
- Replaced a long-held upload/delete lock with per-path in-use/deleting state and reference counts:
delete now returns HTTP 409 while that exact file is uploading or generating a thumbnail instead
of blocking gevent and freezing every request.
- Deployed uncommitted code before committing and tested against the real 87-file/28GB Pi library:
all 87 reported uploaded, total bytes matched 29,615,111,758, and retention reported off. Copied
a tiny real clip to `YARIS_OBD_LOCAL_TEST.MOV`, verified it appeared Pending, played it in the
browser, and deleted it through the confirmed UI action; the player closed and the library
returned to exactly 87 uploaded files. Background uploads were paused for the disposable test,
restored afterward, and the service remained active.
### Phase 18: Trip history & replay — 🚧 PLANNED
**New phase.** Right now the `tracking` table (Phase 7) is just a raw stream of GPS/speed points
with no concept of a discrete "trip" - there's no way to look back and see "trip #47, left home