Skip to content

refactor: single camera registry#20

Merged
RobXYZ merged 4 commits into
RobXYZ:mainfrom
jusii:pr/camera-registry
Jun 15, 2026
Merged

refactor: single camera registry#20
RobXYZ merged 4 commits into
RobXYZ:mainfrom
jusii:pr/camera-registry

Conversation

@jusii

@jusii jusii commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

As discussed in #18 — the camera set (filename letter, channel key, label) now lives in one place, viofosync_lib/cameras.py, and everything derives from it: the scan glob, the queue's filename regexes, channel order/labels, the archive/export pair slots, the per-camera export job types and the route validation patterns. The frontend mirrors it with a single CAMERAS table in app.js (it can't import Python — a test pins the two against drift).

Pure refactor — the derived tables are test-pinned to the exact literals they replaced, and the full suite passes unchanged. One small deliberate exception: a corrupt/unknown export job type in a legacy DB row now fails that job with an error instead of silently rendering as a front+rear PiP.

Adding a future lens is now one Camera line plus its UI strings (the export-bar layout question you raised is untouched — whatever you decide about PiP buttons, the registry makes it easier).

Validated on my A329 archive (telephoto + interior data): identical scan results, exports and timeline behavior.

jusii added 4 commits June 12, 2026 20:49
Camera knowledge (filename letter, channel key, label) was
scattered as literals: regexes in queue.py, the scan glob in
_archive.py, three channel tables in naming.py, slot-dispatch
dicts in the archive pairer and _pair_clips, per-type maps in the
exporter and the route patterns. Adding a lens meant touching all
of them.

Now viofosync_lib/cameras.py declares the cameras once and
everything derives: the glob and regex character classes from
CAMERA_LETTERS, channel maps/order/labels and channel_of() from
CAMERAS, the per-camera export job types (join_<channel>,
pip/pip_<channel>) with their letter/partner/main tables in
naming.py, and the route validation patterns from those. The
registry lives in viofosync_lib so both the lib (glob) and the
web app can import it without layering violations.

One deliberate behavior change: the exporter's pip dispatch used
defaulting .get() lookups, so a corrupt/unknown job type in a
legacy row would silently render as a front+rear PiP; the derived
tables raise KeyError instead, which the job runner already
catches and records as a failed job. Unreachable through
enqueue(), which validates types up front.
app.js had the camera set spread across MODAL_CAMERAS,
CAMERA_VIEW_LABELS, the thumb-render arms, selection hydration,
per-camera action-button wiring and the queue badge ternary. One
CAMERAS const (a mirror of viofosync_lib/cameras.py — comment
points there) now feeds all of them; the per-camera button trios
are registered in a loop keyed by channel-suffixed element ids.

EXPORT_TYPE_LABELS stays an explicit table: the PiP short labels
(Fr/Rf/Tf/If) are display quirks, not registry facts.
The derived export-type/label/channel tables must reproduce the
exact literals they replaced; these tests fail first if a
registry edit silently changes behavior. Also pins the
load-bearing positions (front first, rear second) and the
one-uppercase-letter invariant the SQL substr expressions rely
on.
From the adversarial review pass (codex + multi-lens):

- pair_slot_of() in cameras.py expresses the pairers' historical
  rear fallback once instead of inline in archive.py and
  _pair_clips (channel_of keeps its "other" fallback — the two
  diverge on purpose)
- renderKindBadge guards the label lookup with Object.hasOwn so a
  non-letter camera value renders "?" again instead of resolving
  prototype keys
- new test pins the app.js CAMERAS mirror against the Python
  registry (regex-extracts the JS table) so the two cannot drift
  silently
- CAMERA_LETTERS import hoisted to queue.py's top-level block;
  stale letter-set literals removed from two docstrings
- viofosync_lib/__init__ docstring documents cameras.py as the
  package's one deliberately public submodule
- naming.py docstring describes its camera-facade role
- dropped a test duplicating channel_of coverage that
  test_channel_of.py already pins
@RobXYZ RobXYZ merged commit 749d505 into RobXYZ:main Jun 15, 2026
1 check passed
@RobXYZ

RobXYZ commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Thanks again, really appreacited!

@jusii jusii deleted the pr/camera-registry branch June 18, 2026 12:41
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.

2 participants