- Переименование камер per-user, синхронизировано между Просмотром,
Воспроизведением и Моими видами через user_channel_names (по main-id)
- Hour/half-hour штрихи на всех таймлайнах (через ::after overlay)
- Двойной клик на pane в Воспроизведении → fullscreen, повторный → возврат
- Унифицирован hitbox кнопок ✎/✕ к 24×24 во всех разделах
- Фикс утечки reader-нитей при недоступных DVR: hard inactivity timeout
30 сек, без него за сутки накапливалось 180+ зависших нитей
- psutil в Docker — был пустой dashboard в админке
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- login_required валидирует существование юзера в БД: при устаревшей
session (user_id ссылается на удалённую запись после пересоздания БД)
чистим session и редиректим на /login вместо 500 на user["is_admin"]
- entrypoint.sh чистит /tmp/.X1-lock перед Xvfb — иначе после креша
контейнера повторный старт падает с "Server is already active"
- CHANGELOG: запись v2.4.0 (Novicam integration) + v2.4.1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Security / шифрование:
- stream_key (128-byte KDF-derived key для encrypted H.265+) теперь
шифруется Fernet как и пароль DVR. Добавлены _enc_stream_key /
_dec_stream_key, расшифровка в _dvr_row, автомиграция plaintext→Fernet
при старте для существующих записей
- dvrs_add / dvrs_edit шифруют stream_key на INSERT/UPDATE
Resource cleanup:
- release(buf): kill() теперь вне buf.lock + wait(timeout=2) чтобы
не оставлять зомби-процессов (wine/ffmpeg) после disconnect
- view_playback: при смене ключа старый buffer также wait(timeout=2)
Docker:
- Dockerfile: установка wine + wine32 (i386) + xvfb для PlayCtrl.dll
- Предварительная инициализация WINEPREFIX=/app/.wine во время build
(избегаем задержек первого wineboot в runtime)
- entrypoint.sh запускает Xvfb на :1, затем gunicorn
- COPY dvr_admin/wine_playm4/ в образ (директория gitignore'д —
нужно положить вручную перед docker build, см. DEPLOY.md)
- DEPLOY.md: добавлена секция «Требования для сборки» с пояснением
про wine_playm4/ и варианты без него
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Первая волна: live preview / main view / playback archive для Hikvision
DVR с user-заданным Encryption Key (Live View Parameters). Работает на
нативной libPlayCtrl.so без wine в runtime.
### Добавлено
- Live 16-канальный грид (2 fps), main view (12 fps), playback archive
через `/SDK/play` / `/SDK/playback` HTTP protocol + libPlayCtrl.so
- Pull-модель PlayM4_GetJPEG вместо SetDecCallBack (callback'и крашили
под нагрузкой из-за GIL race в 16 native decoder threads)
- Session reconnect loop (DVR рвёт /SDK/play ~30 сек) + heartbeat
/ISAPI/Security/sessionHeartbeat + auto-recovery на 401
- UI sync часов к видео-PTS через PlayM4_GetSystemTime + /pos endpoint,
_pbWall re-peg каждые 2 сек. Оба template'а (fullscreen + modal)
- Pure Python KDF `_hik_stream_kdf_128(user_key)` — реверс NetStream.dll
через Ghidra headless. K1=6a68a361bf6eb567, K2=cd7afe68ca6fde75,
cipher D(K1)-swap-E(K2)-swap-D(K1) на 16-байт блоки. Финальная формула
`user_key_ascii + derived16 × 7` (константа для любого ключа)
- Spy DLL под wine + Ghidra reverse engineering workflow
### Исправлено
- UI часы в архиве тикают на всех скоростях (убрано `if(_pbRate!==1)`
в _startSeekTimer + добавлено обновление m-status в модальном template)
- Сервер больше не падает в 16-канальном гриде encrypted (убраны
per-frame ffmpeg forks, pull-модель JPEG)
### TODO (остаются в testing до фикса)
- Playback speed ×2/×4/×8 — протокол захвачен, код применён
(PlayM4_Fast + dynamic GETJPEG_INTERVAL), ожидает теста
- Clip download encrypted — NET_DVR_SetPlayBackSecretKey returns FALSE,
план B: post-factum decrypt через pure Python cipher
### Docker
- gunicorn --workers 1 --threads 16 (single worker обязательно для
libPlayCtrl thread safety)
- _DVR_LD_SET=1 env чтобы skip self-exec в контейнере
Переведено скачивание клипов на Hikvision SDK (PlayBackByTime_V40 +
data callback) — точное время по часам DVR без seek-смещения.
Исправлена загрузка SDK-библиотек через self-restart с LD_LIBRARY_PATH.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Archive player: loading spinner on stream start/seek/timeline click
- Archive player: live clock updates every second during playback
- Timeline: removed segment overlays, hourly labels (0–24)
- Clip download: split time inputs into separate HH/MM/SS fields
- Clip download: cancel button aborts fetch and kills ffmpeg on server
- Security: CSRF protection, HttpOnly/SameSite cookies, XSS escaping,
parameter validation, access control on ping endpoint
- Dashboard: user-specific DVR cards, live clock and version widgets
- Preview channels resume after closing fullscreen player
- Docker: moved SDK libs into dvr_admin/, cleaned up dvr_admin_docker/
- Flask-приложение управления DVR Hikvision
- Предпросмотр каналов, архив, скачивание клипов
- Управление пользователями с правами доступа
- Docker-контейнер с Gunicorn