The footer no longer shows the app version (sidebar version stays). A new
per-browser preference liveAutostart controls live view startup: a toggle in
Settings → Плеер. Default off — live opens paused and waits for Play; on —
cameras start immediately on entering live view. Live.init seeds this.playing
from the pref.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Track whether fullscreen was entered by the double-click itself (_fsBySolo).
Mode 1 (from the grid): a double-click fullscreens the camera and a second
double-click now exits fullscreen back to live view. Mode 2 (already in
fullscreen via F): double-click toggles solo/grid without leaving fullscreen;
Esc or F exits. Exiting fullscreen by any means resets the flag and clears solo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The grid/archive control bar is hidden while its frame is fullscreen, so the
video fills the screen cleanly. A global F-key handler toggles fullscreen of
the active frame (live-main or arch-content) — entered and exited with F, and
exited with Esc as well. Uses e.code (KeyF) so it works on non-Latin layouts
and ignores typing in inputs and Ctrl/Cmd/Alt combos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The archive content frame gets a 32px footer (reusing the live grid-bar look)
with a fullscreen button that expands the player + timeline. The sidebar date
section is now a bottom-anchored card (panel-2, bordered, rounded) holding the
date input above the inline calendar; the camera list fills the space above it
and its scrollbar is hidden (still scrollable). Calendar colours tweaked to sit
on the card.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The player-frame toolbar (camera <select> + date input) is removed. Archive
main is now a row: a 220px sidebar split in half by height — the top half is
a scrollable clickable camera list, the bottom half holds the date input plus
a new inline month calendar (prev/next month, today + selected highlight,
Monday-first). Picking a camera or a day loads that day's recordings. The
player and DVR timeline move into an .arch-content column on the right.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-add the top header as a 50px bar injected by ensureHeader() on every
layout page (skipped on login), with the brand centered. The layout height
now subtracts both header and footer. Rebrand the project CoRE.Vision →
CoRE.Vizion+ everywhere: header + footer brand, all page <title>s, the login
card, and the FastAPI OpenAPI title (applies on next backend restart).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All grid/play/fullscreen submenu items are removed from every sidebar
(index, archive, settings, layout) — those controls now live in the live
grid footer. The sidebar becomes a narrow 72px rail and Live/Archive/Settings
render as 64x64 icon tiles (icon + small caption, active = inset red ring).
The layout.html gear (only link to /layout) is dropped with its submenu, so
the layout editor is now reachable by URL only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The grid control footer is regrouped: ⏮ play/stop ⏭ now sit together in the
centre (left section empty). On the right, before fullscreen, a new ▦ split
button opens an upward popup menu with the layouts 4/9/16/25/36/49/64 that
calls setDim; the menu respects maxDim (16+ mode), highlights the active
layout, and closes on outside click.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The live-view <main> now hosts its own 32px footer bar beneath the grid:
prev page on the left, play/stop in the centre, next page + fullscreen on the
right — all icon buttons. Pagination is new: cameras are split into pages of
dim² cells, prev/next walk the pages (page 0 still honours a saved manual
layout), and the arrows disable at the bounds. Fullscreen now targets <main>
so the control bar stays visible in fullscreen (the global stats footer is
outside <main> and hides as before). The sidebar play/fullscreen items now
target <main> too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The camera table actions column is back as the 9th column but stays empty in
the normal view — restart (⟳) and delete (✕) buttons render only on existing
cameras while bulk-editing. Restart in bulk mode no longer reloads the table
(keeps pending edits); delete reloads as before.
Row height is now truly uniform: cams-fixed cells use line-height:1 with
vertically-centred controls, the Вкл/Запись toggles shrink to 30×16, and
selects/inputs/action buttons cap at 20px so filled rows match empty slots.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The camera table actions column (log/restart/delete buttons) is removed:
the table drops to 8 columns across thead, filled rows, empty slots and the
bulk-edit rows. The now-orphaned log subrow and openLogs tracking are gone.
Camera rows get a hard fixed height of 22px via a new table.cams.cams-fixed
rule (zero vertical padding, 22px line-height) so rows never inflate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Header bar dropped from all pages; brand, system stats (#sys-stats) and clock
(#clock) now live in the 22px footer next to the version. .layout fills the
full height minus the footer. ensureFooter runs before startClock/refreshStats
so the moved elements exist when populated.
VERSION 0.0.136.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Footer is a third layout block; .layout height now subtracts --footer-h (22px)
so it never overlaps the full-height video grid. Injected via JS only on pages
with the main layout (skips login); shows CoRE.Vision brand + version.
VERSION 0.0.135.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
"Изменить" now renders all 64 slots as editable rows — filled ones for editing,
empty ones with blank fields (user prefilled "admin", channel 1) for adding.
Saving PUTs changed cameras and POSTs filled empty slots (auto id camN, lowest
free). Removed the per-row "+ Добавить" buttons; empty slots in normal view just
show "пусто". Bulk edit can now be entered with zero cameras.
VERSION 0.0.134.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adding a camera stays available via the per-slot "+ Добавить" row. JS handlers
are already guarded with if (el), so no logic changes are needed.
VERSION 0.0.133.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cameras (esp. an NVR at one IP with many channels) are configured by a channel
number now: channel N → main /Streaming/Channels/{N*100+1}, sub {N*100+2}
(101/102 = ch1, 1101/1102 = ch11, 3201/3202 = ch32). The add/edit form and the
bulk-edit row use a 1-32 dropdown; the camera list shows "канал N". Frontend
derives main_path/sub_path from the channel, so the backend is unchanged.
VERSION 0.0.132.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
"Изменить" previously replaced each camera row with a vertical .cam-edit-grid
form inside one colspan cell — effectively a different table. Now bulk edit
keeps the same columns and turns the cells into compact inline inputs:
Камера→name, IP→ip, Потоки→main/sub, Вкл/Запись toggles, Хранилище select,
and the Статус column becomes Логин/Пароль (header swaps via data-bulk-label).
Live per-row onchange is suppressed while bulk is active (changes collected
until Сохранить). Inputs are compact (22px) so row height stays dense.
VERSION 0.0.131.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-row "Хранилище" <select> inherited the base select padding (6px 8px,
~32px tall) and inflated every camera row. Scope a compact rule to .stor-sel
(22px height, matching the toggles) so row height stays dense. Edit/bulk-form
selects are unaffected.
VERSION 0.0.130.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Camera.storage_id: each camera chooses its storage ("" = active/default).
supervisor resolves per-camera (storage_by_id → active fallback); cameras
API (body/payload) + /toggle accept storage_id and repoint the recorder.
- Recordings now go to <root>/<cam>/<YYYY-MM-DD>/<file>.mp4. This ffmpeg build
lacks -strftime_mkdir, so recorder_task pre-creates today+tomorrow dirs at
start and the indexer re-ensures them each tick (survives midnight).
- indexer: scan date subdirs + legacy flat files; sort by basename so the
in-progress segment is detected correctly when both layouts coexist.
- frontend: per-camera "Хранилище" dropdown in the camera table (inline) and
in the add/edit + bulk forms. Move the active-storage summary widget from
the Система tab into the Хранилища tab.
VERSION 0.0.129.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the single fixed /records path with a list of storages and an
active selection (where new recordings go). Quota is now per-storage.
- config: StorageItem(id,name,type,path,quota_gb,nas-meta) + Storage keeps
global retention_days/segment_seconds; active + items. Migration from the
old single {path,quota_gb} schema → one local item.
- recorder: write to the active storage; restart_all() repoints on switch;
NAS-not-mounted guard (never write into the container overlay).
- indexer: scan ALL storage roots so recordings survive an active switch.
- retention: enforce quota PER storage via db.total_size_under /
oldest_recordings_under (path-prefix LIKE).
- api/storages: GET/POST/PUT/DELETE + activate + policy. NAS uses host-mount
(backend stores SMB params, generates the mount/fstab command, reports
ismount status). Retire old POST /api/storage.
- frontend: new "Хранилища" settings tab — table with inline per-row quota,
add form (local folder / NAS SMB), global policy (segment + retention).
- compose: add shared ./storages:/storages root for extra local folders and
host-mounted NAS shares.
VERSION 0.0.127.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a separate `record` field so a camera can be registered but fully
off, or on but not recording:
- enabled (Вкл): camera on/off. Disabled = no go2rtc stream (no live),
no recording; entry is just stored. build_streams/sync_all/reconcile
skip disabled cameras; live grid shows "камера выключена".
- record (REC): write segments to disk. Recorder runs only when
enabled AND record.
Unified POST /api/cameras/{id}/toggle {enabled?, record?} (replaces the
/record endpoint); go2rtc is touched only when `enabled` changes, so
flipping REC doesn't blip live. Camera table gets Вкл + Запись toggle
columns; add/edit forms get both switches.
load_config migrates the old schema (no `record` key): old `enabled`
meant "record" with live always on -> enabled=True, record=old enabled.
VERSION -> 0.0.126.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`enabled` already gated recording only (go2rtc/live work regardless), but
it was a buried "Вкл" checkbox. Make it an explicit REC control:
- New "Запись" column with an inline REC switch in each camera row.
- Relabel the add/edit form toggle "Вкл" -> "REC" + tooltip.
- New POST /api/cameras/{id}/record {enabled} that flips recording through
the supervisor only (no go2rtc re-sync, so live view doesn't blip).
Off = view-only (live via go2rtc); on = record segments to disk.
VERSION -> 0.0.124.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The params row was a ragged flex-wrap and "Готовый профиль" was floated
with margin-left:auto, so controls didn't line up and the preset menu
dangled at an odd height. Split the row into a left grid (auto-fit
columns, controls bottom-aligned, full-width) and a separate right-side
"Готовый профиль" zone. Reorder fields logically: codec, H.264 profile,
preset, rate control, bitrate, QP, keyframe interval. Drop the now-dead
SOFT/MEDIUM/HARD button CSS.
VERSION -> 0.0.123.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SOFT/MEDIUM/HARD selector lost its color coding when it became a
dropdown. Re-apply colors (SOFT red, MEDIUM yellow, HARD white) to the
options and to the select's shown value, and right-align the "Готовый
профиль" label (margin-left:auto) so it clearly sits on the right.
VERSION -> 0.0.122.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Double-clicking a grid cell now maximizes that camera ("solo") via a CSS
class on the grid instead of putting the tile into the browser Fullscreen
API. In fullscreen the soloed camera fills the screen; double-clicking
again returns to the grid (staying fullscreen). From windowed mode the
gesture also enters fullscreen so the camera fills the screen. ESC exits
fullscreen natively; on exit the solo state is cleared.
VERSION -> 0.0.121.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Style QP <input type=number> like the <select>s (it rendered with the
default white background -> stood out); add a disabled (greyed) style.
- QP vs bitrate are now mutually DISABLED instead of hidden: QP mode
greys the bitrate field, VBR/CBR greys the QP field. Hiding never
worked because .tr-row label{display:flex} overrode [hidden].
- Replace SOFT/MEDIUM/HARD preset buttons with a "Готовый профиль"
dropdown, placed last (rightmost) in the params row.
VERSION -> 0.0.120.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Player/transcoding settings gain encoder controls:
- Rate-control mode VBR / CBR / QP (constant quantizer). x264: VBR uses
-b:v/-maxrate/-bufsize, CBR adds -x264-params nal-hrd=cbr (min=max=b:v),
QP uses -qp N (no bitrate). VP9 maps QP -> -crf N -b:v 0, CBR -> min=max=b:v.
- Preset list expanded to ultrafast/superfast/veryfast/faster/fast/medium
(was only ultrafast/superfast); for VP9 the preset maps to cpu-used.
- New QP field in the UI, shown when rate control = QP, otherwise the
bitrate field is shown.
Both /play.mp4 (archive) and /live.mp4 accept rc + qp query params.
All three modes verified producing valid output on the live restream.
VERSION -> 0.0.119.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per request, move the account widget (current user line + logout button)
to the top of the "Пользователи" tab and remove the standalone Account
tab. Note: the Users tab is superadmin-only, so logout is now reachable
only by superadmin (it is the only logout in the app) -- confirmed
acceptable by the user, who operates as superadmin.
VERSION -> 0.0.118.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "Система" tab was a catch-all (Recording, Player & transcoding,
Storage, System info, Account). Split out two dedicated tabs:
- "Плеер": per-browser playback/transcode profiles. Kept at operator+
(the transcode option spawns server-side ffmpeg, i.e. CPU load).
- "Учётная запись": current user + logout. Ungated, so any signed-in
user (incl. viewers) can log out -- previously it was buried inside
the operator-only "Система" tab.
.tabs gets flex-wrap so the now-7 tabs wrap instead of overflowing.
VERSION -> 0.0.117.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The built-in WASM player (frontend/static/vendor/hevcjs/hevc-core.js)
rendered washed-out, green/red-shifted video. Two causes, both fixed:
- VideoFrame path (Chrome): the I420 VideoFrame was created without a
colorSpace, so the browser defaulted to BT.601 limited -> hue shift,
and guessed the range -> washout. Set explicit BT.709, fullRange:false.
- WebGL fallback shader: used BT.709 FULL-range coefficients on
limited-range camera output -> washout/desaturation. Switched to
BT.709 limited-range conversion ((Y-16)*255/219, chroma centered 128).
VERSION -> 0.0.116.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>