Skip to content

v2.5 - #27

Merged
RobXYZ merged 26 commits into
mainfrom
dev
Jul 10, 2026
Merged

v2.5#27
RobXYZ merged 26 commits into
mainfrom
dev

Conversation

@RobXYZ

@RobXYZ RobXYZ commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Added

GPS Triage

viofosync can now fetch a clip's GPS track before downloading the recording itself — a skeleton trace pulled in seconds over Wi-Fi, rather than minutes of transferring the full MP4. With triage on, every queued clip is scouted for its route first, so the archive's journey maps, stops, and place names appear ahead of the footage arriving, and the download queue can be organised around where you actually drove. Off by default — enable GPS triage in Settings.

Sync Filtering

GPS-driven controls over what actually syncs — more sync policies to come:

  • Read-only-only sync — restrict syncing to locked (event) clips, so only footage the camera has protected is pulled.
  • Location skip — define named locations (Home by default) with a dwell radius; with GPS triage on, clips that dwell at a location flagged exclude recordings are auto-skipped, so parking-mode footage recorded on your own driveway never downloads. Location names also label journey and stop endpoints on the archive maps.

Clip Locking & Delete-from-Camera

You can now manually mark a clip read-only to retain it indefinitely — locked clips are protected from retention pruning and manual delete.

Journeys & Archive UX

  • A per-journey completion pie shows at a glance how much of each detected trip has finished downloading.
  • Journey grouping is padded past the GPS stop radius so a trip takes in its pull-away and pull-in clips, with the trace, start, and end markers all unified to that same padded window.
  • Unified clip actions dropdown (queue / export / delete) replaces the scattered per-clip buttons.
  • Archive navigation now preserves tab state, restores map views, and adds FLIP animations, so the view no longer resets as clips index in.

Changed

  • Single-channel captures get compact filenames — no redundant camera suffix when only one lens is present — and a downloaded clip's sidecar GPS is used as a fallback source for its track. Thanks to @nittanygeek (Support compact single-channel Viofo filenames #24).
  • Redundant Extract GPS button was removed now that triage handles extraction.

Fixed

  • The dashcam lists and serves the clip it is still recording and reports a stale size for it. An active-recording guard now holds every lens of the newest capture group out of triage and the download drain until the camera's cmd=3014 record flag reports stopped, freeing superseded captures as new ones arrive and deferring any clip that keeps growing mid-download. (Incorrect file sizes; failure to complete download #26)
  • The sync worker now reports its state on start, so the status badge no longer shows a false "paused" before the first cycle.
  • RangeReader now raises TruncatedRead on a short range response instead of silently accepting a truncated GPS read.

RobXYZ and others added 26 commits July 2, 2026 23:19
Add a user 'locked' (retain-indefinitely) flag on clip_index and
download_queue, protect locked/RO clips from retention and manual
delete, carry the lock through the scanner, and surface Mark-read-only /
Delete actions plus a read-only badge in the archive and downloads UI.
… on the cmd=3014 record flag

The camera lists and serves the clip it is still recording and reports a
stale size for it. Hold every lens of the newest capture group out of GPS
triage and the download drain until the camera's cmd=3014 record flag
reports stopped (control.record_state → 1/0/None; hold unless an explicit
0). Supersession frees superseded captures and a download-overage abort
in download_file defers a clip that keeps growing. Adds capture_key_sql
and the download_queue.remote_complete flag.

Fixes #26
Clear the ruff violations that landed with the GPS-triage, locking, and
journey-grouping work: unused imports, un-sorted import blocks,
module-level imports below the first def, semicolon-joined statements,
and one unused local. Test behaviour is unchanged (108 passing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e handshake

A client vanishing between the WS accept and the hub's initial
snapshot send left Hub.connect() swallowing the failure while the
/api/progress route carried on into receive_text() — starlette had
already marked the socket DISCONNECTED, so every fast tab reload
logged "Exception in ASGI application: RuntimeError: WebSocket is
not connected".

Hub.connect() now returns False on a dead handshake so the route
exits early, and the receive loop treats RuntimeError as a normal
disconnect to cover the broadcast-eviction race flipping the state
mid-session. Regression tests drive a real starlette WebSocket over
a fake ASGI transport for both windows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… their tracks

Geofence-auto-skipped clips keep their triage GPS skeletons on disk
but were invisible in the archive. An opt-in show_geofenced query
param on GET /api/archive/day/{date} and .../route now:

- returns geofence-skipped rows as remote tiles (remote_day_clips
  gains include_geofenced; user-skipped rows are never returned — a
  manual skip means "don't show me this")
- weaves their skeletons into journey detection via a new
  day_tracks.geofence_skipped_gpx_paths() helper, kept separate from
  day_gpx_paths so no existing caller's defaults can drift (the
  geofence evaluator keeps its own broader queue_states)
- emits per-clip overlay geometry (geofenced_tracks, with per-point
  times so the client can scope each track to the journey that owns
  its window)

The route cache needs no new logic: its signature covers the file
set, so on/off variants are distinct entries. Completion pies are
untouched by the flag; the empty-window value changes from 1.0 to
None so a journey recovered purely from skipped clips shows no pie
rather than a misleading 100%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A fourth archive filter checkbox, "GPS-excluded", persisted to
localStorage like the maps toggle (it's a mode, not a per-visit
narrowing). When on, day fetches carry show_geofenced=true:
geofence-skipped clips render as muted remote tiles with the
existing house glyph plus a per-tile Un-skip button (routes through
the existing unskip+retry action, so geofence_released_at is set and
the clip won't be re-skipped), and each journey map draws the
recovered skeleton stretches dashed and muted, clipped to that
journey's padded window via the tracks' per-point times.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@RobXYZ
RobXYZ merged commit 995a965 into main Jul 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant