Skip to content

Releases: OpenIPC/viewer

v0.3.8-rc2

v0.3.8-rc2 Pre-release
Pre-release

Choose a tag to compare

@keyldev keyldev released this 22 Jul 11:06
b8f3601

Builds on the React SPA web console and closes most of the gap with the desktop head. Everything here is server-side + SPA only — no change to the video pipeline, the desktop UI, or the mobile heads.

Live grid

  • Stills mode — periodic snapshots instead of live streams, refresh interval
    2–60 s. A 25-cell wall costs one HTTP GET per camera per interval instead of an
    ffmpeg session each; the camera encodes the JPEG itself when it runs Majestic.
  • Digital zoom in a tile: mouse wheel, drag to pan, buttons for touch. The
    transform lives on the tile's slot, never on the pooled <video>, so zoom
    can't follow a camera into another cell.
  • Kiosk mode — chrome-free full-viewport wall with optional page cycling.
    Uses the Fullscreen API when granted and falls back to a fixed overlay when it
    isn't (embedded/iframed pages refuse it outright).
  • Wall preferences live in the browser, not the install: the same layout is
    watched from a control-room screen and from someone's laptop.

Archive

  • Recording start/stop from the browser, written into the same folder and table
    the desktop head uses (-c copy, segmented, q on stdin so the MP4 trailer is
    written).
  • Calendar + date filtering, paging, and clip export (fast -c copy or precise
    re-encode), streamed as a download without leaving a copy on the server.
  • Playback is a ranged file response, so seeking is the browser's own.

Snapshot library

  • Stills taken from the browser can be kept: same folder layout, same
    .thumbs/<id>.jpg naming and the same table as the desktop's
    SnapshotService, so a still taken from a phone shows up in the desktop
    gallery and vice versa.
  • Thumbnails are produced with ffmpeg — already a dependency of this head —
    rather than pulling the Video layer's Skia thumbnailer into the server.
  • Pixel dimensions are read from the JPEG frame header; no imaging library
    needed to record what the desktop records.
  • Gallery page with lightbox, download and delete, under the Archive tab.

Camera settings (Majestic)

  • Read the live config.json, edit fields, post raw JSON, set day/night, read
    /metrics. Schema-driven like the desktop editor (IMajesticConfigSchema), so
    it renders whatever knobs the firmware actually exposes instead of a fixed form
    that drifts between builds.
  • ISP fields get their own panel: Majestic re-reads those live, so tuning the
    picture does not restart the encoder. Fields that do restart it are flagged.
  • Edits travel as (path, value) and are applied against a freshly read copy of
    the camera's config, so a stale tab can't revert someone else's change.

Two-way audio

  • Listen: audio rides in the existing live stream (transcoded to AAC, ~1% of
    the video bitrate) rather than a second session, so nobody's picture restarts
    when they unmute.
  • Push-to-talk: the browser sends 16-bit PCM over a WebSocket; G.711
    encoding and RTP packetizing happen server-side in the same Core code the
    desktop talks with. One talker per camera — a speaker is exclusive.
  • Held, not toggled, and the camera is released when the route changes.

Permissions

  • New Talk flag, separate from Ptz/Manage: it is the one action that
    reaches people standing in front of the camera.
  • ViewArchive now gates the archive and the snapshot library; Export gates
    clip export. Both flags previously existed without gating anything.
  • Camera settings are Manage-only including readsconfig.json carries
    the camera's own logins and, on many builds, the Wi-Fi PSK.

Fixes

  • The live WebSocket was write-only, so a viewer's close frame went unnoticed and
    the shared ffmpeg process outlived its last viewer. Verified: 8 streams → 0
    after the last tile releases.
  • A camera that never answered a Majestic call was reported as success (204): our
    own call deadline surfaced as the same cancellation as an abandoned request.
    Now 504.
  • Player: a viewer joining an already-running stream got a buffer starting at
    t=90s with currentTime=0 and sat paused forever. A watchdog now jumps to the
    live edge.
  • ViewArchive was missing from the users page, which quietly made the archive
    ungrantable to anyone created from the web console.
  • Recording a camera that delivered nothing left a 0-byte file and an archive row.

What's Changed

  • Web console: archive, snapshots, camera settings and two-way audio by @keyldev in #60
  • web: OpenIPC logo in the console by @keyldev in #61

Full Changelog: v0.3.8-rc1...v0.3.8-rc2

v0.3.8-rc1

v0.3.8-rc1 Pre-release
Pre-release

Choose a tag to compare

@keyldev keyldev released this 21 Jul 15:59
b7bfb36

Web console: React SPA, PTZ, discovery, and user permissions
Grows the --server-only web console from the Phase 20 foundation into a
self-contained browser client for OpenIPC cameras. The Razor UI it shipped
with is removed — the SPA reached parity and then passed it.

What's new
React SPA replaces the server-rendered UI. Client-routed, so navigating
never reloads the page — and, crucially, never restarts video. Live tiles are
keyed by camera id and survive a grid resize (1 → 9 → 1 keeps the shared
cameras playing), a layout switch, a page flip, and now a route change: the

PTZ from the browser. Pan/tilt/zoom with presets, for cameras that report
PTZ and have a probed ONVIF profile. Movement is stateless on the server: each
move carries an ONVIF self-stop timeout that the client refreshes while a
button is held, so a closed tab cannot leave a camera panning.

Network discovery. ONVIF WS-Discovery, mDNS and an opt-in subnet sweep,
using the same aggregator as the desktop app. A scan is a background job polled
by id, so it survives navigation and a second viewer joins the running scan
instead of starting a rival. Adding is probe → review → add: ONVIF is the only
source of the real RTSP URI and it can be wrong behind NAT, so nothing is
written until the user has seen it.

Users and permissions. Accounts with permission flags
(ViewLive / ViewArchive / Ptz / Export / Manage) and an optional
per-user camera subset. The roster is a JSON file next to the database holding
PBKDF2 hashes only; the built-in admin keeps working as the way back in if the
last Manage account is lost. Authorization is enforced per endpoint — the UI
hides what you may not do, but hiding is not the boundary. A camera outside
your subset answers 404 rather than 403, so ids can't be probed for existence.

Also: saved grid layouts with paging (page = gridSize², like the desktop
head), a single-camera page, mobile layout at the 700px breakpoint, in-app
modals instead of prompt/confirm, and Inter bundled as a self-hosted woff2
(full variable file, not the latin subset, which drops Cyrillic).

Fixes found along the way
Live video never actually played past the first seconds. fMP4 carries the
ffmpeg session's timestamps, so a viewer joining a running stream got a buffer
starting minutes ahead of currentTime, outside every buffered range —
autoplay never fired and the tile sat frozen. A watchdog now seeks to the live
edge and resumes. Pre-existing, not caused by the pooling above (verified
against an element that is never reparented).
Unmatched /api paths returned index.html with 200 text/html via the
SPA fallback; they now 404 with JSON.
Adding a non-ONVIF camera sat through the full ONVIF timeout for nothing.
Breaking
The Razor UI under /app is gone; / serves the SPA. Its form-post endpoints
(/app/config/export|import, /app/sessions/revoke-all) moved to /api/v1
and answer JSON instead of redirects.
OpenIPC.Viewer.Web is a plain SDK project again (no .razor left to
compile); the SPA is embedded in the assembly, so dotnet publish still
produces one self-contained binary. Node is a build-time-only dependency and
CI installs it.
Verification
Exercised live against a real 82-camera database via --server-only:

grid pagination (10 pages, correct windowing, ends disabled), cross-route
persistence (same DOM nodes, currentTime advanced through the absence,
server stream count unchanged), retention expiry (streams 8 → 0, no leak);
layout editing on a middle page preserves the pages before and after
byte-for-byte (checked on a throwaway layout, then deleted);
permissions: a view-only user with two cameras sees exactly those two and gets
403 on camera CRUD, users, discovery, export, PTZ, layouts and revoke-all; an
operator gets 404 (not 403) for PTZ and live on a camera outside their subset;
discovery scan/cancel/409-while-running, probe fallback for a non-ONVIF host,
and add creating a camera with ONVIF metadata persisted;
config export/import and session revoke through the UI.
Builds with 0 warnings (TreatWarningsAsErrors is on repo-wide); eslint and
tsc are clean.

Not verified: PTZ against a physical PTZ camera, and discovery against
cameras on a real LAN — the dev machine has neither. Both paths are exercised
only through their error/fallback branches and a stubbed scan payload.

What's Changed

Full Changelog: v0.3.7...v0.3.8-rc1

v0.3.7

Choose a tag to compare

@github-actions github-actions released this 12 Jul 15:36
c8a891d

What's Changed

  • fix(android): repair corrupt release APK + zero-byte motion recordings by @keyldev in #58

Full Changelog: v0.3.6...v0.3.7

v0.3.6

Choose a tag to compare

@github-actions github-actions released this 05 Jul 18:59
aef7dab

What's Changed

  • chore: simplify issue forms by @keyldev in #56
  • feat: opt-in single-instance mode (desktop) by @keyldev in #57

Full Changelog: v0.3.5...v0.3.6

v0.3.5

Choose a tag to compare

@github-actions github-actions released this 02 Jul 19:45
c9cc96d

What's Changed

  • feat(discovery): multi-add flow + OpenIPC web fingerprint by @keyldev in #53
  • feat(analytics): detections continue on the single-camera page by @keyldev in #54
  • docs: refresh README by @keyldev in #55

Full Changelog: v0.3.4...v0.3.5

v0.3.4

Choose a tag to compare

@github-actions github-actions released this 02 Jul 18:27
fc2afea

What's Changed

  • fix(editor): XM Sofia-hash template + wider dialog by @keyldev in #52

Full Changelog: v0.3.3...v0.3.4

v0.3.3

Choose a tag to compare

@github-actions github-actions released this 02 Jul 17:51
27e77bc

What's Changed

  • feat(mobile): SSH soft keyboard, risky-tools gate, animated splash on mobile by @keyldev in #49
  • feat(desktop): tray icon + close-to-tray setting by @keyldev in #50
  • feat(editor): multi-vendor RTSP URI templates by @keyldev in #51

Full Changelog: v0.3.2...v0.3.3

v0.3.2

Choose a tag to compare

@github-actions github-actions released this 01 Jul 20:02
479b475

What's Changed

  • fix(android): allow cleartext HTTP (Majestic panel + snapshots dead on-device) by @keyldev in #48

Full Changelog: v0.3.1...v0.3.2

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 01 Jul 18:53
9b8c2e2

What's Changed

  • fix(android): disable AOT (malformed libaot-*.so broke APK install) by @keyldev in #47

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 01 Jul 17:26
32130cf

What's Changed

  • feat: animated camera-eye splash loader by @keyldev in #37
  • feat: wire CameraStatusRegistry into grid, library, Health Center by @keyldev in #38
  • feat: Discovery v2 foundation — model + source abstraction + aggregator by @keyldev in #39
  • feat: firmware-lite backend — reboot / time / logs over SSH (Slice A) by @keyldev in #40
  • feat: majestic control center by @keyldev in #42
  • feat: grid pager, fullscreen kiosk, network config sync by @keyldev in #43
  • fix: ONVIF add fallback, mobile dialog polish, Majestic editor, SSH host-key trust by @keyldev in #44
  • feat(onvif): trim-safe SOAP client (HttpClient + XDocument), replace by @keyldev in #45
  • feat(stills): grid-wide snapshot mode by @keyldev in #46

Full Changelog: v0.2.2...v0.3.0