iobroker.agent-dvr 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +6 -0
- package/README.md +6 -3
- package/admin/assets/index-B13Ujb6j.js +685 -0
- package/admin/assets/index-Bez3QfoS.js +685 -0
- package/admin/assets/index-CNOz09VA.js +685 -0
- package/admin/assets/index-D7I0OIPq.js +685 -0
- package/admin/assets/index-DSBe1npE.js +685 -0
- package/admin/assets/index-Dqw9GB72.js +685 -0
- package/admin/assets/index-t1B1rnou.js +685 -0
- package/admin/i18n/de.json +123 -118
- package/admin/i18n/en.json +123 -118
- package/admin/i18n/es.json +123 -118
- package/admin/i18n/fr.json +123 -118
- package/admin/i18n/it.json +123 -118
- package/admin/i18n/nl.json +123 -118
- package/admin/i18n/pl.json +123 -118
- package/admin/i18n/pt.json +123 -118
- package/admin/i18n/ru.json +123 -118
- package/admin/i18n/uk.json +123 -118
- package/admin/i18n/zh-cn.json +123 -118
- package/admin/index_m.html +1 -1
- package/build/main.js +3 -3
- package/build/main.js.map +2 -2
- package/io-package.json +33 -28
- package/lib/web.js +64 -2
- package/package.json +1 -1
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "agent-dvr",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.4.1": {
|
|
7
|
+
"en": "fix: overview tile links to ioBroker host; go2rtc URL shown only when enabled",
|
|
8
|
+
"de": "fix: Übersichtskachel zeigt ioBroker-Host-IP; go2rtc-URL nur bei aktivierter Option sichtbar",
|
|
9
|
+
"ru": "fix: плитка обзора ссылается на хост ioBroker; URL go2rtc отображается только при включении",
|
|
10
|
+
"pt": "fix: tile de visão geral aponta para o host ioBroker; URL go2rtc exibida apenas quando habilitado",
|
|
11
|
+
"nl": "fix: overzichtstegel verwijst naar ioBroker-host; go2rtc-URL alleen zichtbaar als ingeschakeld",
|
|
12
|
+
"fr": "fix: la tuile d aperçu pointe vers l hôte ioBroker; URL go2rtc visible uniquement si activé",
|
|
13
|
+
"it": "fix: il riquadro panoramica punta all host ioBroker; URL go2rtc visibile solo se abilitato",
|
|
14
|
+
"es": "fix: el tile de vista general apunta al host ioBroker; URL go2rtc visible solo cuando está activado",
|
|
15
|
+
"pl": "fix: kafelek przeglądu wskazuje na host ioBroker; URL go2rtc widoczny tylko po włączeniu",
|
|
16
|
+
"uk": "fix: плитка огляду вказує на хост ioBroker; URL go2rtc відображається лише при увімкненні",
|
|
17
|
+
"zh-cn": "fix: 概览磁贴指向 ioBroker 主机;go2rtc URL 仅在启用时显示"
|
|
18
|
+
},
|
|
19
|
+
"0.4.0": {
|
|
20
|
+
"en": "Optional MJPEG and snapshot stream proxy through ioBroker (browser needs only one connection)",
|
|
21
|
+
"de": "Optionaler MJPEG- und Snapshot-Stream-Proxy über ioBroker (Browser benötigt nur eine Verbindung)",
|
|
22
|
+
"ru": "Опциональный прокси потоков MJPEG и снимков через ioBroker",
|
|
23
|
+
"pt": "Proxy opcional de streams MJPEG e snapshots pelo ioBroker",
|
|
24
|
+
"nl": "Optionele MJPEG- en snapshot-proxy via ioBroker",
|
|
25
|
+
"fr": "Proxy optionnel pour les flux MJPEG et snapshots via ioBroker",
|
|
26
|
+
"it": "Proxy opzionale per stream MJPEG e snapshot tramite ioBroker",
|
|
27
|
+
"es": "Proxy opcional de flujos MJPEG e instantáneas a través de ioBroker",
|
|
28
|
+
"pl": "Opcjonalny proxy strumieni MJPEG i migawek przez ioBroker",
|
|
29
|
+
"zh-cn": "可选的 MJPEG 和快照流代理(通过 ioBroker)",
|
|
30
|
+
"uk": "Опціональний проксі потоків MJPEG і знімків через ioBroker"
|
|
31
|
+
},
|
|
6
32
|
"0.3.0": {
|
|
7
33
|
"en": "New control buttons (scheduleOn/Off, detectorOn/Off, sensitivityMin/Max/Gain), audio URL states for microphones, native browser fullscreen in dashboard, collapsible tag filter, auto-hide header",
|
|
8
34
|
"de": "Neue Steuertasten (scheduleOn/Off, detectorOn/Off, Empfindlichkeit), Audio-URL-Zustände für Mikrofone, nativer Browser-Vollbild im Dashboard, ausklappbarer Tag-Filter, Auto-Hide-Header",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "wyczyn: dodanie pełnego i18n do pulpitu nawigacyjnego na żywo — wszystkie ciągi interfejsu użytkownika przetłumaczone na 11 języków\nnaprawiono: dodano brakujące atrybuty rozmiaru sm/md/lg/xl do tabeli go2rtcMapping w jsonConfig.json (E5507)\nnaprawiono: przetłumaczono brakujące klucze administratora i18n na 9 języków (E5606)",
|
|
68
94
|
"uk": "подвиг: додано повний i18n до панелі керування Live — усі рядки інтерфейсу перекладено 11 мовами\nвиправлення: додано відсутні атрибути розміру sm/md/lg/xl до таблиці go2rtcMapping у jsonConfig.json (E5507)\nвиправлення: переклад відсутніх ключів адміністратора i18n на 9 мов (E5606)",
|
|
69
95
|
"zh-cn": "新增功能:为实时仪表盘添加完整的国际化 (i18n) 功能——所有用户界面字符串均翻译成 11 种语言\n修复:在 jsonConfig.json 中向 go2rtcMapping 表添加缺失的 sm/md/lg/xl 尺寸属性 (E5507)\n修复:将缺失的管理员 i18n 密钥翻译成 9 种语言 (E5606)"
|
|
70
|
-
},
|
|
71
|
-
"0.0.6": {
|
|
72
|
-
"en": "add Live Dashboard and go2rtc WebRTC documentation to README",
|
|
73
|
-
"de": "Live-Dashboard- und go2rtc-WebRTC-Dokumentation zur README hinzugefügt",
|
|
74
|
-
"ru": "добавлена документация Live Dashboard и go2rtc WebRTC в README",
|
|
75
|
-
"pt": "documentação do Live Dashboard e go2rtc WebRTC adicionada ao README",
|
|
76
|
-
"nl": "Live Dashboard en go2rtc WebRTC documentatie toegevoegd aan README",
|
|
77
|
-
"fr": "documentation Live Dashboard et go2rtc WebRTC ajoutée au README",
|
|
78
|
-
"it": "documentazione Live Dashboard e go2rtc WebRTC aggiunta al README",
|
|
79
|
-
"es": "documentación de Live Dashboard y go2rtc WebRTC añadida al README",
|
|
80
|
-
"pl": "dodano dokumentację Live Dashboard i go2rtc WebRTC do README",
|
|
81
|
-
"uk": "додано документацію Live Dashboard і go2rtc WebRTC до README",
|
|
82
|
-
"zh-cn": "README 中新增 Live Dashboard 和 go2rtc WebRTC 文档"
|
|
83
|
-
},
|
|
84
|
-
"0.0.5": {
|
|
85
|
-
"en": "go2rtc WebRTC integration (admin table mapping, ioBroker WS proxy); auto-delete stale cameras; fix recording prev/next order",
|
|
86
|
-
"de": "go2rtc WebRTC-Integration (Admin-Tabellen-Mapping, ioBroker WS-Proxy); gelöschte Kameras werden automatisch entfernt; Vor/Zurück-Reihenfolge bei Aufnahmen korrigiert",
|
|
87
|
-
"ru": "интеграция go2rtc WebRTC (таблица в admin, WS-прокси через ioBroker); автоудаление устаревших камер; исправлен порядок кнопок Пред/След для записей",
|
|
88
|
-
"pt": "integração go2rtc WebRTC (tabela no admin, proxy WS via ioBroker); remoção automática de câmeras obsoletas; ordem anterior/próximo nas gravações corrigida",
|
|
89
|
-
"nl": "go2rtc WebRTC-integratie (admintabel, ioBroker WS-proxy); automatisch verwijderen van verouderde camera's; volgorde vorige/volgende opnames gecorrigeerd",
|
|
90
|
-
"fr": "intégration go2rtc WebRTC (table admin, proxy WS ioBroker); suppression automatique des caméras obsolètes; ordre précédent/suivant des enregistrements corrigé",
|
|
91
|
-
"it": "integrazione go2rtc WebRTC (tabella admin, proxy WS ioBroker); eliminazione automatica telecamere obsolete; ordine precedente/successivo registrazioni corretto",
|
|
92
|
-
"es": "integración go2rtc WebRTC (tabla en admin, proxy WS ioBroker); eliminación automática de cámaras obsoletas; orden anterior/siguiente en grabaciones corregido",
|
|
93
|
-
"pl": "integracja go2rtc WebRTC (tabela w admin, proxy WS ioBroker); automatyczne usuwanie nieaktywnych kamer; poprawiona kolejność poprzedni/następny nagrań",
|
|
94
|
-
"uk": "інтеграція go2rtc WebRTC (таблиця в admin, WS-проксі через ioBroker); автовидалення застарілих камер; виправлено порядок кнопок Попередній/Наступний для записів",
|
|
95
|
-
"zh-cn": "go2rtc WebRTC 集成(管理表格映射,ioBroker WS 代理);自动删除过时摄像头;修正录像上一个/下一个顺序"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -142,6 +142,10 @@
|
|
|
142
142
|
"tier": 3,
|
|
143
143
|
"mode": "daemon",
|
|
144
144
|
"type": "alarm",
|
|
145
|
+
"intro": true,
|
|
146
|
+
"localLinks": {
|
|
147
|
+
"_default": "%web_protocol%://%ip%:%web_port%/agent-dvr/"
|
|
148
|
+
},
|
|
145
149
|
"messagebox": true,
|
|
146
150
|
"compact": true,
|
|
147
151
|
"connectionType": "local",
|
|
@@ -171,7 +175,7 @@
|
|
|
171
175
|
"pass"
|
|
172
176
|
],
|
|
173
177
|
"native": {
|
|
174
|
-
"
|
|
178
|
+
"serverIp": "192.168.1.100",
|
|
175
179
|
"port": 8090,
|
|
176
180
|
"user": "",
|
|
177
181
|
"pass": "",
|
|
@@ -218,6 +222,7 @@
|
|
|
218
222
|
"widgetColorAccent": "#8ab4f8",
|
|
219
223
|
"widgetColorModalBg": "#1c1c1e",
|
|
220
224
|
"widgetBorderRadius": 8,
|
|
225
|
+
"go2rtcEnabled": false,
|
|
221
226
|
"go2rtcUrl": "",
|
|
222
227
|
"cameraStreams": {},
|
|
223
228
|
"dashColorBg": "#080b0f",
|
package/lib/web.js
CHANGED
|
@@ -28,10 +28,15 @@ class AgentDvrWeb {
|
|
|
28
28
|
const ns = instanceSettings ? instanceSettings._id.replace('system.adapter.', '') : 'agent-dvr.0';
|
|
29
29
|
const native = (instanceSettings && instanceSettings.native) ? instanceSettings.native : {};
|
|
30
30
|
|
|
31
|
+
// Cache auth header for proxy endpoints
|
|
32
|
+
this._authHeader = (native.user || native.pass)
|
|
33
|
+
? 'Basic ' + Buffer.from((native.user || '') + ':' + (native.pass || '')).toString('base64')
|
|
34
|
+
: null;
|
|
35
|
+
|
|
31
36
|
// ── REST API ─────────────────────────────────────────────────────────
|
|
32
37
|
// Must be registered before the static file handler (Express matches in order)
|
|
33
38
|
app.get('/' + ROUTE + '/api/cameras', (req, res) => {
|
|
34
|
-
const base = (native.
|
|
39
|
+
const base = (native.serverIp && native.port) ? 'http://' + native.serverIp + ':' + native.port : '';
|
|
35
40
|
|
|
36
41
|
Promise.all([
|
|
37
42
|
adapter.getForeignStatesAsync(ns + '.cam_*.name'),
|
|
@@ -108,6 +113,16 @@ class AgentDvrWeb {
|
|
|
108
113
|
});
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
// Replace stream URLs with proxy URLs when enableStreamProxy is on
|
|
117
|
+
if (native.enableStreamProxy) {
|
|
118
|
+
Object.values(cameras).forEach(cam => {
|
|
119
|
+
if (cam.oid) {
|
|
120
|
+
cam.mjpegUrl = '/' + ROUTE + '/api/mjpeg?oid=' + cam.oid;
|
|
121
|
+
cam.snapshotUrl = '/' + ROUTE + '/api/snap?oid=' + cam.oid;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
// Build aspect from data.width / data.height states written by flattenWrite.
|
|
112
127
|
// Reading from ioBroker states is reliable regardless of whether the web
|
|
113
128
|
// extension runs in the same process as the main adapter.
|
|
@@ -159,9 +174,56 @@ class AgentDvrWeb {
|
|
|
159
174
|
}));
|
|
160
175
|
});
|
|
161
176
|
|
|
177
|
+
// ── MJPEG stream proxy (optional: enableStreamProxy) ─────────────────
|
|
178
|
+
app.get('/' + ROUTE + '/api/mjpeg', (req, res) => {
|
|
179
|
+
const base = (native.serverIp && native.port) ? 'http://' + native.serverIp + ':' + native.port : '';
|
|
180
|
+
if (!base) { res.status(503).end('AgentDVR not configured'); return; }
|
|
181
|
+
const oid = String(req.query.oid || '');
|
|
182
|
+
if (!oid || !/^\d+$/.test(oid)) { res.status(400).end('invalid oid'); return; }
|
|
183
|
+
const url = base + '/video.mjpg?oid=' + oid;
|
|
184
|
+
let target;
|
|
185
|
+
try { target = new URL(url); } catch (_) { res.status(500).end(); return; }
|
|
186
|
+
const mod = target.protocol === 'https:' ? https : http;
|
|
187
|
+
const headers = {};
|
|
188
|
+
if (this._authHeader) headers['Authorization'] = this._authHeader;
|
|
189
|
+
const upReq = mod.get({ hostname: target.hostname, port: target.port, path: target.pathname + target.search, headers }, upstream => {
|
|
190
|
+
res.setHeader('Content-Type', upstream.headers['content-type'] || 'multipart/x-mixed-replace');
|
|
191
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
192
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
193
|
+
upstream.pipe(res);
|
|
194
|
+
upstream.on('error', () => { if (!res.headersSent) res.status(502).end(); else res.end(); });
|
|
195
|
+
});
|
|
196
|
+
upReq.setTimeout(0); // no timeout for infinite MJPEG stream
|
|
197
|
+
upReq.on('error', () => { if (!res.headersSent) res.status(502).end(); else res.end(); });
|
|
198
|
+
req.on('close', () => { try { upReq.destroy(); } catch (_) {} });
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// ── Snapshot proxy (optional: enableStreamProxy) ──────────────────────
|
|
202
|
+
app.get('/' + ROUTE + '/api/snap', (req, res) => {
|
|
203
|
+
const base = (native.serverIp && native.port) ? 'http://' + native.serverIp + ':' + native.port : '';
|
|
204
|
+
if (!base) { res.status(503).end('AgentDVR not configured'); return; }
|
|
205
|
+
const oid = String(req.query.oid || '');
|
|
206
|
+
if (!oid || !/^\d+$/.test(oid)) { res.status(400).end('invalid oid'); return; }
|
|
207
|
+
const url = base + '/grab.jpg?oid=' + oid;
|
|
208
|
+
let target;
|
|
209
|
+
try { target = new URL(url); } catch (_) { res.status(500).end(); return; }
|
|
210
|
+
const mod = target.protocol === 'https:' ? https : http;
|
|
211
|
+
const headers = {};
|
|
212
|
+
if (this._authHeader) headers['Authorization'] = this._authHeader;
|
|
213
|
+
const upReq = mod.get({ hostname: target.hostname, port: target.port, path: target.pathname + target.search, headers }, upstream => {
|
|
214
|
+
res.setHeader('Content-Type', upstream.headers['content-type'] || 'image/jpeg');
|
|
215
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
216
|
+
upstream.pipe(res);
|
|
217
|
+
upstream.on('error', () => { if (!res.headersSent) res.status(502).end(); else res.end(); });
|
|
218
|
+
});
|
|
219
|
+
upReq.setTimeout(8000, () => upReq.destroy());
|
|
220
|
+
upReq.on('error', () => { if (!res.headersSent) res.status(502).end(); else res.end(); });
|
|
221
|
+
req.on('close', () => { try { upReq.destroy(); } catch (_) {} });
|
|
222
|
+
});
|
|
223
|
+
|
|
162
224
|
// ── FLV stream proxy (avoids browser CORS block for flv.js XHR) ────────
|
|
163
225
|
app.get('/' + ROUTE + '/api/stream', (req, res) => {
|
|
164
|
-
const base = (native.
|
|
226
|
+
const base = (native.serverIp && native.port) ? 'http://' + native.serverIp + ':' + native.port : '';
|
|
165
227
|
if (!base) { res.status(503).end('AgentDVR not configured'); return; }
|
|
166
228
|
const oid = String(req.query.oid || '');
|
|
167
229
|
if (!oid || !/^\d+$/.test(oid)) { res.status(400).end('invalid oid'); return; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.agent-dvr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Connects ioBroker to AgentDVR: auto-discovers cameras, mirrors all device values as data points, delivers real-time triggers on new recordings, and generates a responsive HTML gallery with optional search and tag filtering.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ipod86",
|