iobroker.agent-dvr 0.0.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/LICENSE +21 -0
- package/README.md +159 -0
- package/admin/agent-dvr.png +0 -0
- package/admin/i18n/de.json +40 -0
- package/admin/i18n/en.json +40 -0
- package/admin/i18n/es.json +40 -0
- package/admin/i18n/fr.json +40 -0
- package/admin/i18n/it.json +40 -0
- package/admin/i18n/nl.json +40 -0
- package/admin/i18n/pl.json +40 -0
- package/admin/i18n/pt.json +40 -0
- package/admin/i18n/ru.json +40 -0
- package/admin/i18n/uk.json +40 -0
- package/admin/i18n/zh-cn.json +40 -0
- package/admin/jsonConfig.json +205 -0
- package/build/lib/widget-i18n.js +118 -0
- package/build/lib/widget-i18n.js.map +7 -0
- package/build/main.js +991 -0
- package/build/main.js.map +7 -0
- package/io-package.json +131 -0
- package/package.json +73 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/main.ts"],
|
|
4
|
+
"sourcesContent": ["import * as utils from '@iobroker/adapter-core';\nimport * as http from 'node:http';\nimport { getWidgetLabels, type WidgetLabels } from './lib/widget-i18n';\n\n// =====================================================================\n// Agent DVR -> ioBroker Adapter\n// API reference: https://ispysoftware.github.io/Agent_API/ (v7.5)\n// =====================================================================\n\n// ---- Types ----\n\ninterface ApiResult {\n\tok: boolean;\n\tdata?: string;\n\terror?: string;\n}\n\ninterface AgentDvrEvent {\n\tfn?: string;\n\ttg?: string;\n\tc?: number;\n\td?: number | string;\n\tsb?: number;\n\t[key: string]: unknown;\n}\n\ninterface Device {\n\toid: number | string;\n\tot: number;\n\tname: string;\n\traw: Record<string, unknown>;\n}\n\ntype RegistryKind = 'cam' | 'sys' | 'ptz' | 'ptzHold' | 'push';\n\ninterface RegistryEntry {\n\tkind: RegistryKind;\n\tpath?: string | null;\n\tparams?: string[];\n\toid?: number | string;\n\tot?: number;\n\tdir?: number;\n\tfid?: string;\n}\n\n// ---- Commands ----\n\nconst CAM_COMMANDS = [\n\t{ id: 'record', path: '/command/record', params: ['oid', 'ot'], name: 'Start recording' },\n\t{ id: 'recordStop', path: '/command/recordStop', params: ['oid', 'ot'], name: 'Stop recording' },\n\t{ id: 'recordRestart', path: '/command/recordRestart', params: ['oid', 'ot'], name: 'Restart recording' },\n\t{ id: 'triggerRecord', path: '/command/triggerRecord', params: ['oid', 'ot'], name: 'Trigger recording (timeout)' },\n\t{ id: 'snapshot', path: '/command/snapshot', params: ['oid'], name: 'Take snapshot' },\n\t{ id: 'detect', path: '/command/detect', params: ['oid', 'ot'], name: 'Trigger motion detection' },\n\t{ id: 'alertOn', path: '/command/alertOn', params: ['oid', 'ot'], name: 'Arm alerts' },\n\t{ id: 'alertOff', path: '/command/alertOff', params: ['oid', 'ot'], name: 'Disarm alerts' },\n\t{ id: 'switchOn', path: '/command/switchOn', params: ['oid', 'ot'], name: 'Switch device on' },\n\t{ id: 'switchOff', path: '/command/switchOff', params: ['oid', 'ot'], name: 'Switch device off' },\n\t{ id: 'objectDetectOn', path: '/command/objectdetecton', params: ['oid', 'ot'], name: 'Enable object detection' },\n\t{\n\t\tid: 'objectDetectOff',\n\t\tpath: '/command/objectdetectoff',\n\t\tparams: ['oid', 'ot'],\n\t\tname: 'Disable object detection',\n\t},\n\t{ id: 'recOnAlert', path: '/command/recordOnAlertOn', params: ['oid', 'ot'], name: 'Record on alert: on' },\n\t{ id: 'recOnDetect', path: '/command/recordOnDetectOn', params: ['oid', 'ot'], name: 'Record on detect: on' },\n\t{ id: 'purge', path: '/command/purge', params: ['oid', 'ot'], name: 'Purge folder (caution!)' },\n] as const;\n\nconst SYS_COMMANDS = [\n\t{ id: 'arm', path: '/command/arm', name: 'Arm system' },\n\t{ id: 'disarm', path: '/command/disarm', name: 'Disarm system' },\n\t{ id: 'allOn', path: '/command/allOn', name: 'All devices on' },\n\t{ id: 'allOff', path: '/command/allOff', name: 'All devices off' },\n\t{ id: 'reloadConfig', path: '/command/reloadConfig', name: 'Reload config' },\n\t{ id: 'reloadObjects', path: '/command/reloadObjects', name: 'Reload objects' },\n\t{ id: 'runStorageMgmt', path: '/command/runStorageMgmt', name: 'Run storage management' },\n\t{ id: 'blockExternal', path: '/command/blockExternal', name: 'Block external access' },\n\t{ id: 'unblockExternal', path: '/command/unblockExternal', name: 'Unblock external access' },\n\t{ id: 'restart', path: '/command/restart', name: 'Restart Agent DVR' },\n\t{ id: 'refresh', path: null, name: 'Refresh data now' },\n] as const;\n\nconst PTZ_DIRS = [\n\t{ id: 'left', dir: 1, hold: true },\n\t{ id: 'upLeft', dir: 2, hold: true },\n\t{ id: 'up', dir: 3, hold: true },\n\t{ id: 'upRight', dir: 4, hold: true },\n\t{ id: 'right', dir: 5, hold: true },\n\t{ id: 'downRight', dir: 6, hold: true },\n\t{ id: 'down', dir: 7, hold: true },\n\t{ id: 'downLeft', dir: 8, hold: true },\n\t{ id: 'zoomIn', dir: 9, hold: true },\n\t{ id: 'zoomOut', dir: 10, hold: true },\n\t{ id: 'stop', dir: 11, hold: false },\n\t{ id: 'center', dir: 0, hold: false },\n] as const;\n\nconst SKIP_KEYS = ['icons', 'image', 'thumbnail', 'base64'];\n\n// ---- Module-level helpers ----\n\nfunction sanitize(s: unknown): string {\n\treturn (\n\t\tString(s)\n\t\t\t.replace(/[\\s.[\\]*?\"'`,;:/\\\\]+/g, '_')\n\t\t\t.replace(/[^A-Za-z0-9_-]/g, '_')\n\t\t\t.replace(/_+/g, '_')\n\t\t\t.replace(/^_+|_+$/g, '') || 'x'\n\t);\n}\n\nfunction asJson(data: unknown): Record<string, unknown> | null {\n\tif (data == null) {\n\t\treturn null;\n\t}\n\tif (typeof data === 'object') {\n\t\treturn data as Record<string, unknown>;\n\t}\n\tif (typeof data === 'string') {\n\t\ttry {\n\t\t\treturn JSON.parse(data) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction toStr(v: unknown): string {\n\tif (v == null) {\n\t\treturn '';\n\t}\n\tif (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n\t\treturn String(v);\n\t}\n\treturn Object.prototype.toString.call(v);\n}\n\nfunction escHtml(s: unknown): string {\n\treturn toStr(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction parseSizeGb(s: unknown): number | null {\n\tif (s == null) {\n\t\treturn null;\n\t}\n\tconst m = toStr(s)\n\t\t.trim()\n\t\t.match(/([\\d.,]+)\\s*([KMGT]?B)?/i);\n\tif (!m) {\n\t\treturn null;\n\t}\n\tlet v = parseFloat(m[1].replace(',', '.'));\n\tif (isNaN(v)) {\n\t\treturn null;\n\t}\n\tconst u = (m[2] || 'GB').toUpperCase();\n\tif (u === 'TB') {\n\t\tv *= 1024;\n\t} else if (u === 'MB') {\n\t\tv /= 1024;\n\t} else if (u === 'KB') {\n\t\tv /= 1048576;\n\t} else if (u === 'B') {\n\t\tv /= 1073741824;\n\t}\n\treturn Math.round(v * 100) / 100;\n}\n\nfunction findWH(obj: unknown, depth: number): [number, number] | null {\n\tif (!obj || typeof obj !== 'object' || depth > 5) {\n\t\treturn null;\n\t}\n\tconst o = obj as Record<string, unknown>;\n\tfor (const [kw, kh] of [\n\t\t['width', 'height'],\n\t\t['w', 'h'],\n\t\t['sourceWidth', 'sourceHeight'],\n\t\t['videoWidth', 'videoHeight'],\n\t\t['imageWidth', 'imageHeight'],\n\t]) {\n\t\tconst w = o[kw],\n\t\t\th = o[kh];\n\t\tif (typeof w === 'number' && typeof h === 'number' && w >= 100 && h >= 100 && w <= 12000 && h <= 12000) {\n\t\t\tconst r = w / h;\n\t\t\tif (r >= 0.3 && r <= 4) {\n\t\t\t\treturn [w, h];\n\t\t\t}\n\t\t}\n\t}\n\tfor (const k of Object.keys(o)) {\n\t\tconst g = findWH(o[k], depth + 1);\n\t\tif (g) {\n\t\t\treturn g;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction detectOt(elem: Record<string, unknown>): number {\n\tconst v = elem.typeID ?? elem.ot ?? elem.objectTypeID ?? elem.type;\n\treturn v === 1 || v === 2 ? v : 2;\n}\n\nfunction findDevices(json: Record<string, unknown>): Device[] {\n\tconst list = Array.isArray(json.objectList) ? json.objectList : [];\n\tconst out: Device[] = [];\n\tfor (const e of list) {\n\t\tif (!e || typeof e !== 'object') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst el = e as Record<string, unknown>;\n\t\tconst rawId = el.id ?? el.oid;\n\t\tif (rawId === undefined || rawId === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst id = rawId as number | string;\n\t\tconst name = typeof el.name === 'string' ? el.name : `obj_${id}`;\n\t\tout.push({ oid: id, ot: detectOt(el), name, raw: el });\n\t}\n\treturn out;\n}\n\n// ---- HTML/CSS gallery helpers ----\n\nfunction galleryCss(minCol: number, maxW: number): string {\n\treturn (\n\t\t`.advgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(${minCol}px,1fr));gap:12px;max-width:100%}` +\n\t\t`.advgrid .advlb{display:none}` +\n\t\t`.advcell{display:flex;flex-direction:column;cursor:pointer;text-decoration:none;color:inherit;font-family:inherit}` +\n\t\t`.advimg{position:relative;display:block;border-radius:8px;overflow:hidden;background:rgba(127,127,127,.15)}` +\n\t\t`.advimg img{width:100%;height:auto;display:block}` +\n\t\t`.advimgfix img{height:100%;object-fit:cover}` +\n\t\t`.advtag{position:absolute;background:rgba(0,0,0,.55);color:#fff;font-size:.6rem;padding:2px 4px;border-radius:3px;line-height:1;max-width:85%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}` +\n\t\t`.advplay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s;background:rgba(0,0,0,.2)}` +\n\t\t`.advplay::before{content:\"\";border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent #fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.6))}` +\n\t\t`.advcell:hover .advplay{opacity:1}` +\n\t\t`.advcap{font-size:.72rem;margin-top:4px;line-height:1.25;opacity:.85}` +\n\t\t`.advmodal{display:none;position:fixed;inset:0;z-index:99999;align-items:center;justify-content:center}` +\n\t\t`.advgrid .advlb:checked + .advthumb + .advmodal{display:flex}` +\n\t\t`.advbackdrop{position:absolute;inset:0;background:transparent;cursor:pointer}` +\n\t\t`.advbox{position:relative;z-index:1;display:flex;flex-direction:column;gap:8px;max-width:min(92vw,${maxW}px);background:#1c1c1e;padding:12px;border-radius:14px;box-shadow:0 16px 48px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08)}` +\n\t\t`.advvideo{width:100%;max-height:80vh;border-radius:8px;background:#000;display:block}` +\n\t\t`.advclose{position:absolute;top:18px;right:18px;width:32px;height:32px;border-radius:50%;background:rgba(0,0,0,.65);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;z-index:2;border:2px solid rgba(255,255,255,.35)}` +\n\t\t`.advinfo{color:#fff;font-size:.8rem;text-align:center}` +\n\t\t`.advinfo a{color:#8ab4f8}` +\n\t\t`.advempty{padding:24px;text-align:center;opacity:.7;font-family:inherit}`\n\t);\n}\n\nfunction galleryCssJs(minCol: number): string {\n\treturn (\n\t\t`.advroot{font-family:inherit;color:inherit}` +\n\t\t`.advbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:10px}` +\n\t\t`.advsearchjs{flex:1 1 160px;min-width:120px;padding:6px 10px;border-radius:8px;border:1px solid rgba(127,127,127,.4);background:rgba(127,127,127,.08);color:inherit;font:inherit}` +\n\t\t`.advtagsjs{display:flex;flex-wrap:wrap;gap:6px}` +\n\t\t`.advtagbtn{padding:4px 10px;border-radius:999px;border:1px solid rgba(127,127,127,.4);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.8rem}` +\n\t\t`.advtagbtn.on{background:#2d6cdf;color:#fff;border-color:#2d6cdf}` +\n\t\t`.advgridjs{display:grid;grid-template-columns:repeat(auto-fill,minmax(${minCol}px,1fr));gap:12px}` +\n\t\t`.advcelljs{display:flex;flex-direction:column;cursor:pointer}` +\n\t\t`.advimgjs{position:relative;display:block;border-radius:8px;overflow:hidden;background:rgba(127,127,127,.15)}` +\n\t\t`.advimgjs img{width:100%;height:auto;display:block}` +\n\t\t`.advimgjs.advimgfix img{height:100%;object-fit:cover}` +\n\t\t`.advtagjs{position:absolute;background:rgba(0,0,0,.55);color:#fff;font-size:.6rem;padding:2px 4px;border-radius:3px;line-height:1;max-width:85%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}` +\n\t\t`.advplayjs{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s;background:rgba(0,0,0,.2)}` +\n\t\t`.advplayjs::before{content:\"\";border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent #fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.6))}` +\n\t\t`.advcelljs:hover .advplayjs{opacity:1}` +\n\t\t`.advcapjs{font-size:.72rem;margin-top:4px;line-height:1.25;opacity:.85}` +\n\t\t`.advemptyjs{padding:24px;text-align:center;opacity:.7}`\n\t);\n}\n\n// Client-side browser code for the JS widget variant.\n// Stored as a string: TypeScript never type-checks browser code running in DOM context.\nconst ADV_CLIENT_CODE = `\n(function(){\nfunction esc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"');}\nvar MODAL_CSS='.advmodaljs{display:none;position:fixed;inset:0;z-index:99999;align-items:center;justify-content:center}.advbackdropjs{position:absolute;inset:0;background:transparent;cursor:pointer}.advboxjs{position:relative;z-index:1;display:flex;flex-direction:column;gap:8px;max-width:min(92vw,900px);background:#1c1c1e;padding:12px;border-radius:14px;box-shadow:0 16px 48px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08)}.advvideojs{width:100%;max-height:80vh;border-radius:8px;background:#000;display:block}.advclosejs{position:absolute;top:18px;right:18px;width:32px;height:32px;border-radius:50%;background:rgba(0,0,0,.65);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;z-index:2;border:2px solid rgba(255,255,255,.35)}.advinfojs{color:#fff;font-size:.8rem;text-align:center}';\nvar modalEl=null,modalVideo=null,modalInfo=null,modalBox=null;\nfunction getModal(){\n if(modalEl&&document.body.contains(modalEl))return modalEl;\n if(!document.getElementById('advmodalcss')){var st=document.createElement('style');st.id='advmodalcss';st.textContent=MODAL_CSS;document.head.appendChild(st);}\n modalEl=document.createElement('div');modalEl.className='advmodaljs';\n var bd=document.createElement('div');bd.className='advbackdropjs';\n modalBox=document.createElement('div');modalBox.className='advboxjs';\n var cl=document.createElement('span');cl.className='advclosejs';cl.textContent='\u2715';\n modalVideo=document.createElement('video');modalVideo.className='advvideojs';\n modalVideo.setAttribute('controls','');modalVideo.setAttribute('preload','none');modalVideo.setAttribute('playsinline','');\n modalInfo=document.createElement('div');modalInfo.className='advinfojs';\n modalBox.appendChild(cl);modalBox.appendChild(modalVideo);modalBox.appendChild(modalInfo);\n modalEl.appendChild(bd);modalEl.appendChild(modalBox);\n document.body.appendChild(modalEl);\n bd.addEventListener('click',closeModal);cl.addEventListener('click',closeModal);\n return modalEl;\n}\nfunction openSrc(src,label,maxW){\n var m=getModal();\n if(maxW)modalBox.style.maxWidth='min(92vw,'+maxW+'px)';\n modalVideo.setAttribute('src',src);modalInfo.textContent=label;m.style.display='flex';\n}\nfunction closeModal(){\n if(!modalEl)return;\n try{modalVideo.pause();}catch(e){}\n modalVideo.removeAttribute('src');try{modalVideo.load();}catch(e){}\n modalEl.style.display='none';\n}\ndocument.addEventListener('keydown',function(e){if(e.key==='Escape'||e.keyCode===27)closeModal();});\nfunction initRoot(root){\n var dataEl=root.querySelector('script.advdata');\n if(!dataEl)return;\n var D;try{D=JSON.parse(dataEl.textContent);}catch(e){return;}\n var cfg=D.cfg||{},items=D.items||[],live=D.live||null;\n var grid=root.querySelector('.advgridjs'),search=root.querySelector('.advsearchjs'),tagsBox=root.querySelector('.advtagsjs');\n var state={q:'',tag:''};\n var tagset={};\n items.forEach(function(it){String(it.tag||'').split(/[,\\\\s]+/).forEach(function(t){if(t)tagset[t]=1;});});\n var tags=Object.keys(tagset);\n if(cfg.show_tags&&tags.length){\n var mk=function(label,val){\n var b=document.createElement('button');b.className='advtagbtn';b.textContent=label;b.setAttribute('data-tag',val);\n b.addEventListener('click',function(){state.tag=state.tag===val?'':val;updateTagBtns();render();});\n tagsBox.appendChild(b);\n };\n mk(cfg.labels&&cfg.labels.all||'All','');tags.forEach(function(t){mk(t,t);});\n }\n function updateTagBtns(){var bs=tagsBox.querySelectorAll('.advtagbtn');for(var i=0;i<bs.length;i++)bs[i].classList.toggle('on',bs[i].getAttribute('data-tag')===state.tag);}\n updateTagBtns();\n if(search)search.addEventListener('input',function(){state.q=this.value.toLowerCase();render();});\n function badge(it){if(!(cfg.show_tags&&it.tag))return '';var pos=String(cfg.tag_position||'bottom-left').split('-');return '<span class=\"advtagjs\" style=\"'+pos[0]+':5px;'+pos[1]+':5px\">'+esc(it.tag)+'</span>';}\n function render(){\n var html='';\n if(live){var ar=cfg.live_aspect||'',arStyle=ar?' style=\"aspect-ratio:'+ar.replace('/',' / ')+'\"':'',arCls=ar?' advimgfix':'';\n html+='<div class=\"advcelljs\" data-live=\"1\"><span class=\"advimgjs'+arCls+'\"'+arStyle+'><img loading=\"lazy\" src=\"'+esc(live.thumb)+'\"><span class=\"advtagjs\" style=\"top:5px;left:5px\">● '+(cfg.labels&&cfg.labels.live||'LIVE')+'</span><span class=\"advplayjs\"></span></span><span class=\"advcapjs\">'+esc(live.name)+'</span></div>';}\n items.forEach(function(it,i){\n if(state.tag&&String(it.tag||'').toLowerCase().indexOf(state.tag.toLowerCase())<0)return;\n if(state.q){var hay=((it.date||'')+' '+(it.time||'')+' '+(it.tag||'')).toLowerCase();if(hay.indexOf(state.q)<0)return;}\n html+='<div class=\"advcelljs\" data-i=\"'+i+'\"><span class=\"advimgjs\"><img loading=\"lazy\" src=\"'+esc(it.thumb)+'\">'+badge(it)+'<span class=\"advplayjs\"></span></span><span class=\"advcapjs\">'+esc(it.date)+' '+esc(it.time)+'<br>'+esc(it.dur)+'s · '+esc(it.size)+' MB</span></div>';\n });\n grid.innerHTML=html||'<div class=\"advemptyjs\">'+(cfg.labels&&cfg.labels.noRecordings||'No recordings')+'</div>';\n var cells=grid.querySelectorAll('.advcelljs');\n for(var k=0;k<cells.length;k++)(function(cell){\n cell.addEventListener('click',function(){\n if(cell.getAttribute('data-live')==='1'){openSrc(live.video,(live.name||'')+' \u00B7 Live',cfg.max_modal_width);return;}\n var it=items[parseInt(cell.getAttribute('data-i'),10)],maxW=Number(cfg.max_modal_width)||900;\n if(cfg.player_url){var u=cfg.player_url.replace(/{video}/g,encodeURIComponent(it.video)).replace(/{videoRaw}/g,it.video).replace(/{fn}/g,encodeURIComponent(it.fn||'')).replace(/{date}/g,encodeURIComponent(it.date)).replace(/{time}/g,encodeURIComponent(it.time)).replace(/{duration}/g,encodeURIComponent(it.dur)).replace(/{size}/g,encodeURIComponent(it.size)).replace(/{tags}/g,encodeURIComponent(it.tag));window.open(u,'_blank');}\n else{openSrc(it.video,esc(it.date)+' '+esc(it.time)+(it.dur!=null?' \u00B7 '+it.dur+'s':'')+(it.size!=null?' \u00B7 '+it.size+' MB':'')+(it.tag?' \u00B7 '+it.tag:''),maxW);}\n });\n })(cells[k]);\n }\n render();\n}\nfunction scan(){var roots=document.querySelectorAll('.advroot');for(var i=0;i<roots.length;i++)if(!roots[i].__adv){roots[i].__adv=1;initRoot(roots[i]);}}\nwindow.ADVscan=scan;scan();\n})();\n`.trim();\n\n// ---- Adapter class ----\n\nclass AgentDvr extends utils.Adapter {\n\tprivate pollTimer: ioBroker.Interval | undefined = undefined;\n\tprivate refreshTimer: ioBroker.Timeout | undefined = undefined;\n\tprivate authHeader: string | null = null;\n\tprivate baseUrl = '';\n\tprivate wt: WidgetLabels = getWidgetLabels('en');\n\n\tprivate readonly ensuredFolders = new Set<string>();\n\tprivate readonly registry = new Map<string, RegistryEntry>();\n\tprivate readonly ptzActive = new Map<string | number, string>();\n\tprivate readonly widgetSig: Record<string, string> = {};\n\tprivate readonly lastEventFn: Record<string | number, string> = {};\n\tprivate readonly camAspect: Record<string | number, string> = {};\n\tprivate readonly devById = new Map<string | number, Device>();\n\tprivate readonly eventBusy: Record<string | number, boolean> = {};\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({ ...options, name: 'agent-dvr' });\n\t\tthis.on('ready', this.onReady.bind(this));\n\t\tthis.on('stateChange', this.onStateChange.bind(this));\n\t\tthis.on('unload', this.onUnload.bind(this));\n\t}\n\n\t// ---- lifecycle ----\n\n\tprivate async onReady(): Promise<void> {\n\t\tvoid this.setState('info.connection', false, true);\n\n\t\tconst sysConfig = await this.getForeignObjectAsync('system.config');\n\t\tconst rawLang = (sysConfig?.common as unknown as { language?: string } | undefined)?.language;\n\t\tthis.wt = getWidgetLabels(rawLang ?? 'en');\n\n\t\tconst pollSeconds = Math.max(5, Math.min(3600, this.config.pollSeconds || 30));\n\t\tthis.baseUrl = `http://${this.config.ip}:${this.config.port || 8090}`;\n\n\t\tif (this.config.user || this.config.pass) {\n\t\t\tthis.authHeader = `Basic ${Buffer.from(`${this.config.user}:${this.config.pass}`).toString('base64')}`;\n\t\t}\n\n\t\tawait this.buildSystem();\n\t\ttry {\n\t\t\tawait this.poll();\n\t\t} catch (e) {\n\t\t\tthis.log.warn(`First poll error: ${(e as Error).message}`);\n\t\t}\n\n\t\tthis.pollTimer = this.setInterval(\n\t\t\t() => this.poll().catch(e => this.log.warn(`Poll error: ${(e as Error).message}`)),\n\t\t\tpollSeconds * 1000,\n\t\t);\n\n\t\tthis.subscribeStates('*');\n\t\tthis.log.info(`Agent DVR adapter ready. Polling ${this.baseUrl} every ${pollSeconds}s.`);\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tif (this.pollTimer !== undefined) {\n\t\t\t\tthis.clearInterval(this.pollTimer);\n\t\t\t\tthis.pollTimer = undefined;\n\t\t\t}\n\t\t\tif (this.refreshTimer !== undefined) {\n\t\t\t\tthis.clearTimeout(this.refreshTimer);\n\t\t\t\tthis.refreshTimer = undefined;\n\t\t\t}\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\tcallback();\n\t}\n\n\tprivate onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n\t\tif (!state || state.ack !== false) {\n\t\t\treturn;\n\t\t}\n\t\tconst relId = this.getRelId(id);\n\t\tconst entry = this.registry.get(relId);\n\t\tif (entry) {\n\t\t\tthis.runCommand(relId, entry, state.val as boolean).catch(e =>\n\t\t\t\tthis.log.warn(`Command error: ${(e as Error).message}`),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ---- helpers ----\n\n\tprivate getRelId(fullId: string): string {\n\t\treturn fullId.startsWith(`${this.namespace}.`) ? fullId.slice(this.namespace.length + 1) : fullId;\n\t}\n\n\tprivate apiGet(path: string): Promise<ApiResult> {\n\t\treturn new Promise(resolve => {\n\t\t\tconst timeout = Math.max(1000, Math.min(30000, this.config.httpTimeoutMs || 8000));\n\t\t\tconst opts: http.RequestOptions = {\n\t\t\t\thostname: this.config.ip,\n\t\t\t\tport: this.config.port || 8090,\n\t\t\t\tpath,\n\t\t\t\tmethod: 'GET',\n\t\t\t\ttimeout,\n\t\t\t};\n\t\t\tif (this.authHeader) {\n\t\t\t\topts.headers = { Authorization: this.authHeader };\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst req = http.request(opts, res => {\n\t\t\t\t\tlet data = '';\n\t\t\t\t\tres.on('data', (c: Buffer) => {\n\t\t\t\t\t\tdata += c.toString();\n\t\t\t\t\t});\n\t\t\t\t\tres.on('end', () => {\n\t\t\t\t\t\tif (res.statusCode && res.statusCode >= 400) {\n\t\t\t\t\t\t\tresolve({ ok: false, error: `HTTP ${res.statusCode}` });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve({ ok: true, data });\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tres.on('error', (e: Error) => resolve({ ok: false, error: e.message }));\n\t\t\t\t});\n\t\t\t\treq.on('error', (e: Error) => resolve({ ok: false, error: e.message }));\n\t\t\t\treq.on('timeout', () => {\n\t\t\t\t\treq.destroy();\n\t\t\t\t\tresolve({ ok: false, error: 'timeout' });\n\t\t\t\t});\n\t\t\t\treq.end();\n\t\t\t} catch (e) {\n\t\t\t\tresolve({ ok: false, error: String((e as Error).message || e) });\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async ensureFolder(id: string, name: string, type: 'device' | 'channel' = 'channel'): Promise<void> {\n\t\tif (this.ensuredFolders.has(id)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.setObjectNotExistsAsync(id, { type, common: { name }, native: {} });\n\t\tthis.ensuredFolders.add(id);\n\t}\n\n\tprivate async ensurePath(fullId: string): Promise<void> {\n\t\tconst parts = fullId.split('.');\n\t\tlet acc = parts[0];\n\t\tfor (let i = 1; i < parts.length - 1; i++) {\n\t\t\tacc += `.${parts[i]}`;\n\t\t\tif (!this.ensuredFolders.has(acc)) {\n\t\t\t\tawait this.setObjectNotExistsAsync(acc, { type: 'channel', common: { name: parts[i] }, native: {} });\n\t\t\t\tthis.ensuredFolders.add(acc);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate guessRole(id: string, val: unknown): ioBroker.CommonType {\n\t\tif (typeof val === 'string' && /^https?:\\/\\//i.test(val)) {\n\t\t\treturn 'string';\n\t\t}\n\t\treturn 'string';\n\t}\n\n\tprivate async writeLeaf(id: string, val: unknown): Promise<void> {\n\t\tconst t = typeof val;\n\t\tlet common: ioBroker.StateCommon;\n\t\tif (t === 'boolean') {\n\t\t\tcommon = { name: id.split('.').pop() || id, type: 'boolean', role: 'indicator', read: true, write: false };\n\t\t} else if (t === 'number') {\n\t\t\tcommon = { name: id.split('.').pop() || id, type: 'number', role: 'value', read: true, write: false };\n\t\t} else {\n\t\t\tconst role = typeof val === 'string' && /^https?:\\/\\//i.test(val) ? 'text.url' : 'text';\n\t\t\tcommon = { name: id.split('.').pop() || id, type: 'string', role, read: true, write: false };\n\t\t}\n\t\tif (!this.ensuredFolders.has(id)) {\n\t\t\tawait this.ensurePath(id);\n\t\t\tawait this.setObjectNotExistsAsync(id, { type: 'state', common, native: {} });\n\t\t\tthis.ensuredFolders.add(id);\n\t\t}\n\t\tawait this.setStateAsync(id, { val: (val === undefined ? null : val) as ioBroker.StateValue, ack: true });\n\t}\n\n\tprivate async flattenWrite(obj: unknown, prefix: string, depth: number): Promise<void> {\n\t\tconst maxDepth = Math.max(1, Math.min(10, this.config.maxDepth || 6));\n\t\tconst maxArray = Math.max(1, Math.min(500, this.config.maxArray || 30));\n\t\tif (depth > maxDepth) {\n\t\t\treturn;\n\t\t}\n\t\tif (obj === null || obj === undefined) {\n\t\t\tawait this.writeLeaf(prefix, obj);\n\t\t\treturn;\n\t\t}\n\t\tif (typeof obj === 'object') {\n\t\t\tif (Array.isArray(obj)) {\n\t\t\t\tif (obj.length > maxArray) {\n\t\t\t\t\tawait this.writeLeaf(`${prefix}.count`, obj.length);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < obj.length; i++) {\n\t\t\t\t\tawait this.flattenWrite(obj[i], `${prefix}.${i}`, depth + 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const k of Object.keys(obj)) {\n\t\t\t\t\tif (SKIP_KEYS.includes(k)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tawait this.flattenWrite((obj as Record<string, unknown>)[k], `${prefix}.${sanitize(k)}`, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tawait this.writeLeaf(prefix, obj);\n\t\t}\n\t}\n\n\tprivate async ensureControl(\n\t\tid: string,\n\t\tname: string,\n\t\tentry: RegistryEntry,\n\t\trole: 'button' | 'switch',\n\t): Promise<void> {\n\t\tif (!this.ensuredFolders.has(id)) {\n\t\t\tawait this.ensurePath(id);\n\t\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\t\ttype: 'state',\n\t\t\t\tcommon: { name, type: 'boolean', role, read: role === 'switch', write: true, def: false },\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.setStateAsync(id, { val: false, ack: true });\n\t\t\tthis.ensuredFolders.add(id);\n\t\t}\n\t\tthis.registry.set(id, entry);\n\t}\n\n\tprivate ensureButton(id: string, name: string, entry: RegistryEntry): Promise<void> {\n\t\treturn this.ensureControl(id, name, entry, 'button');\n\t}\n\n\tprivate async ensureFlag(id: string, name: string): Promise<void> {\n\t\tif (this.ensuredFolders.has(id)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.ensurePath(id);\n\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\ttype: 'state',\n\t\t\tcommon: { name, type: 'boolean', role: 'indicator', read: true, write: false, def: false },\n\t\t\tnative: {},\n\t\t});\n\t\tthis.ensuredFolders.add(id);\n\t\tawait this.setStateAsync(id, { val: false, ack: true });\n\t}\n\n\tprivate async pulse(id: string): Promise<void> {\n\t\tawait this.setStateAsync(id, { val: true, ack: true });\n\t\tthis.setTimeout(() => this.setStateAsync(id, { val: false, ack: true }).catch(() => {}), 1500);\n\t}\n\n\t// ---- system structure ----\n\n\tprivate async buildSystem(): Promise<void> {\n\t\tawait this.ensureFolder('system', 'System', 'channel');\n\t\tawait this.writeLeaf('system.online', false);\n\t\tawait this.writeLeaf('system.lastUpdate', '');\n\t\tawait this.writeLeaf('system.lastPoll', 0);\n\t\tawait this.writeLeaf('system.cameraCount', 0);\n\n\t\tif (this.config.enableSystemControls) {\n\t\t\tawait this.ensureFolder('system.control', 'Control', 'channel');\n\t\t\tfor (const c of SYS_COMMANDS) {\n\t\t\t\tawait this.ensureButton(`system.control.${c.id}`, c.name, { kind: 'sys', path: c.path });\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- camera aspect detection ----\n\n\tprivate async detectAspect(d: Device): Promise<void> {\n\t\tif (this.camAspect[d.oid] !== undefined) {\n\t\t\treturn;\n\t\t}\n\t\tlet wh = findWH(d.raw, 0);\n\t\tif (!wh) {\n\t\t\tconst res = await this.apiGet(`/command/getObject?oid=${d.oid}&ot=2`);\n\t\t\tconst j = asJson(res.data);\n\t\t\tif (j) {\n\t\t\t\twh = findWH(j, 0);\n\t\t\t}\n\t\t}\n\t\tthis.camAspect[d.oid] = wh ? `${wh[0]}/${wh[1]}` : '';\n\t\tif (wh) {\n\t\t\tthis.log.debug(`cam ${d.oid} resolution ${wh[0]}x${wh[1]} -> AR ${this.camAspect[d.oid]}`);\n\t\t}\n\t}\n\n\t// ---- device folder name ----\n\n\tprivate deviceFolder(d: Device): string {\n\t\treturn `${d.ot === 1 ? 'mic' : 'cam'}_${sanitize(d.oid)}_${sanitize(d.name)}`;\n\t}\n\n\t// ---- build device data points ----\n\n\tprivate async buildDevice(d: Device): Promise<void> {\n\t\tconst fid = this.deviceFolder(d);\n\t\tthis.devById.set(d.oid, d);\n\n\t\tawait this.ensureFolder(fid, d.name, 'device');\n\t\tif (d.ot === 2) {\n\t\t\tawait this.detectAspect(d);\n\t\t}\n\t\tawait this.flattenWrite(d.raw, fid, 0);\n\n\t\tawait this.ensureFolder(`${fid}.control`, 'Control', 'channel');\n\t\tfor (const c of CAM_COMMANDS) {\n\t\t\tif (c.id === 'snapshot' && d.ot !== 2) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.ensureButton(`${fid}.control.${c.id}`, c.name, {\n\t\t\t\tkind: 'cam',\n\t\t\t\tpath: c.path,\n\t\t\t\tparams: [...c.params],\n\t\t\t\toid: d.oid,\n\t\t\t\tot: d.ot,\n\t\t\t});\n\t\t}\n\n\t\tif (this.config.enablePtz && d.ot === 2) {\n\t\t\tawait this.ensureFolder(`${fid}.control.ptz`, 'PTZ', 'channel');\n\t\t\tfor (const p of PTZ_DIRS) {\n\t\t\t\tconst cid = `${fid}.control.ptz.${p.id}`;\n\t\t\t\tif (p.hold) {\n\t\t\t\t\tawait this.ensureControl(\n\t\t\t\t\t\tcid,\n\t\t\t\t\t\t`PTZ ${p.id} (hold)`,\n\t\t\t\t\t\t{ kind: 'ptzHold', oid: d.oid, dir: p.dir },\n\t\t\t\t\t\t'switch',\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tawait this.ensureButton(cid, `PTZ ${p.id}`, { kind: 'ptz', oid: d.oid, dir: p.dir });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.config.enableUrls && d.ot === 2) {\n\t\t\tawait this.ensureFolder(`${fid}.urls`, 'URLs', 'channel');\n\t\t\tawait this.writeLeaf(`${fid}.urls.snapshot`, `${this.baseUrl}/grab.jpg?oid=${d.oid}`);\n\t\t\tawait this.writeLeaf(`${fid}.urls.photo`, `${this.baseUrl}/photo.jpg?oid=${d.oid}`);\n\t\t\tawait this.writeLeaf(`${fid}.urls.mjpeg`, `${this.baseUrl}/video.mjpg?oids=${d.oid}`);\n\t\t\tawait this.writeLeaf(`${fid}.urls.mp4`, `${this.baseUrl}/video.mp4?oids=${d.oid}`);\n\t\t}\n\n\t\tawait this.updateCameraEvents(d, fid);\n\t}\n\n\t// ---- event formatting ----\n\n\tprivate fmtEvent(\n\t\tev: Record<string, unknown>,\n\t\toid: number | string,\n\t): {\n\t\tfn: string;\n\t\tsizeMB: number;\n\t\tdur: string;\n\t\ttag: string;\n\t\tdate: string;\n\t\ttime: string;\n\t\tthumb: string;\n\t\tvideo: string;\n\t} {\n\t\tconst e = ev as AgentDvrEvent;\n\t\tconst fn = e.fn ?? '';\n\t\tconst dot = fn.lastIndexOf('.');\n\t\tconst jpg = `${dot > 0 ? fn.slice(0, dot) : fn}_large.jpg`;\n\t\tconst sizeMB = e.sb ? Math.round((Number(e.sb) / 1048576) * 100) / 100 : 0;\n\t\tconst dur = e.d != null ? String(e.d) : '';\n\t\tconst tag = e.tg ?? '';\n\t\tconst ms = (parseFloat(String(e.c ?? 0)) - 621355968000000000) / 10000;\n\t\tconst dt = new Date(ms);\n\t\tconst two = (n: number): string => String(n).padStart(2, '0');\n\t\tconst date = `${two(dt.getDate())}.${two(dt.getMonth() + 1)}.`;\n\t\tconst time = `${two(dt.getHours())}:${two(dt.getMinutes())}`;\n\t\tconst thumb = `${this.baseUrl}/fileThumb.jpg?oid=${oid}&fn=${encodeURIComponent(jpg)}`;\n\t\tconst video = `${this.baseUrl}/streamFile.cgi?oid=${oid}&ot=2&fn=${encodeURIComponent(fn)}`;\n\t\treturn { fn, sizeMB, dur, tag, date, time, thumb, video };\n\t}\n\n\t// ---- gallery HTML builders ----\n\n\tprivate buildGalleryHtml(d: Device, events: Record<string, unknown>[]): string {\n\t\treturn (this.config.widgetMode || 'nojs') === 'js'\n\t\t\t? this.buildGalleryHtmlJs(d, events)\n\t\t\t: this.buildGalleryHtmlNojs(d, events);\n\t}\n\n\tprivate buildGalleryHtmlNojs(d: Device, events: Record<string, unknown>[]): string {\n\t\tconst oid = d.oid;\n\t\tconst minCol = this.config.widgetMinCol || 150;\n\t\tconst maxW = this.config.widgetMaxModalWidth || 900;\n\t\tconst showTags = this.config.widgetShowTags;\n\t\tconst pos = (this.config.widgetTagPosition || 'bottom-left').split('-');\n\t\tconst tagStyle = `${pos[0]}:5px;${pos[1]}:5px`;\n\t\tconst playerUrl = (this.config.widgetPlayerUrl || '').trim();\n\t\tconst PAUSE_ATTR = ` onchange=\"if(!this.checked){var m=this.nextElementSibling.nextElementSibling,v=m&&m.querySelector('video');if(v){v.pause();}}\"`;\n\n\t\tconst items = events\n\t\t\t.map((ev, i) => {\n\t\t\t\tconst p = this.fmtEvent(ev, oid);\n\t\t\t\tconst id = `adv${sanitize(oid)}_${i}`;\n\t\t\t\tconst badge =\n\t\t\t\t\tshowTags && p.tag ? `<span class=\"advtag\" style=\"${tagStyle}\">${escHtml(p.tag)}</span>` : '';\n\t\t\t\tconst inner =\n\t\t\t\t\t`<span class=\"advimg\"><img src=\"${p.thumb}\" loading=\"lazy\" alt=\"\">${badge}<span class=\"advplay\"></span></span>` +\n\t\t\t\t\t`<span class=\"advcap\">${escHtml(p.date)} ${escHtml(p.time)}<br>${escHtml(p.dur)}s · ${escHtml(p.sizeMB)} MB</span>`;\n\t\t\t\tif (playerUrl) {\n\t\t\t\t\tconst href = playerUrl\n\t\t\t\t\t\t.replace(/{video}/g, encodeURIComponent(p.video))\n\t\t\t\t\t\t.replace(/{videoRaw}/g, p.video)\n\t\t\t\t\t\t.replace(/{fn}/g, encodeURIComponent(p.fn))\n\t\t\t\t\t\t.replace(/{date}/g, encodeURIComponent(p.date))\n\t\t\t\t\t\t.replace(/{time}/g, encodeURIComponent(p.time))\n\t\t\t\t\t\t.replace(/{duration}/g, encodeURIComponent(p.dur))\n\t\t\t\t\t\t.replace(/{size}/g, encodeURIComponent(String(p.sizeMB)))\n\t\t\t\t\t\t.replace(/{tags}/g, encodeURIComponent(p.tag));\n\t\t\t\t\treturn `<a class=\"advcell\" href=\"${escHtml(href)}\" target=\"_blank\" rel=\"noopener\">${inner}</a>`;\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t`<input class=\"advlb\" type=\"checkbox\" id=\"${id}\"${PAUSE_ATTR}>` +\n\t\t\t\t\t`<label class=\"advcell advthumb\" for=\"${id}\">${inner}</label>` +\n\t\t\t\t\t`<div class=\"advmodal\"><label class=\"advbackdrop\" for=\"${id}\"></label>` +\n\t\t\t\t\t`<div class=\"advbox\"><label class=\"advclose\" for=\"${id}\">✕</label>` +\n\t\t\t\t\t`<video class=\"advvideo\" controls preload=\"none\" playsinline src=\"${p.video}\"></video>` +\n\t\t\t\t\t`<div class=\"advinfo\">${escHtml(p.date)} ${escHtml(p.time)} · ${escHtml(p.dur)}s · ${escHtml(p.sizeMB)} MB${\n\t\t\t\t\t\tp.tag ? ` · ${escHtml(p.tag)}` : ''\n\t\t\t\t\t} · <a href=\"${p.video}\" download target=\"_blank\">${this.wt.download}</a></div></div></div>`\n\t\t\t\t);\n\t\t\t})\n\t\t\t.join('');\n\n\t\tconst grid = items\n\t\t\t? `<div class=\"advgrid\">${items}</div>`\n\t\t\t: `<div class=\"advempty\">${this.wt.noRecordings}</div>`;\n\t\treturn `<style>${galleryCss(minCol, maxW)}</style>${grid}`;\n\t}\n\n\tprivate buildGalleryHtmlJs(d: Device, events: Record<string, unknown>[]): string {\n\t\tconst oid = d.oid;\n\t\tconst minCol = this.config.widgetMinCol || 150;\n\t\tconst maxW = this.config.widgetMaxModalWidth || 900;\n\t\tconst items = events.map(ev => {\n\t\t\tconst p = this.fmtEvent(ev, oid);\n\t\t\treturn {\n\t\t\t\tfn: p.fn,\n\t\t\t\tdate: p.date,\n\t\t\t\ttime: p.time,\n\t\t\t\tdur: p.dur,\n\t\t\t\tsize: p.sizeMB,\n\t\t\t\ttag: p.tag,\n\t\t\t\tthumb: p.thumb,\n\t\t\t\tvideo: p.video,\n\t\t\t};\n\t\t});\n\t\tconst cfg = {\n\t\t\tmin_col: minCol,\n\t\t\tshow_tags: !!this.config.widgetShowTags,\n\t\t\tmax_modal_width: maxW,\n\t\t\tlive_aspect: this.camAspect[oid] || this.config.widgetLiveAspect || '',\n\t\t\tplayer_url: (this.config.widgetPlayerUrl || '').trim(),\n\t\t\ttag_position: this.config.widgetTagPosition || 'bottom-left',\n\t\t\tlabels: { noRecordings: this.wt.noRecordings, all: this.wt.all, live: this.wt.live },\n\t\t};\n\t\tconst data = JSON.stringify({ items, live: null, cfg }).replace(/</g, '\\\\u003c');\n\t\tconst boot = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';\n\t\treturn (\n\t\t\t`<style>${galleryCssJs(minCol)}</style>` +\n\t\t\t`<div class=\"advroot\"><script type=\"application/json\" class=\"advdata\">${data}</script>` +\n\t\t\t`<div class=\"advbar\"><input class=\"advsearchjs\" type=\"text\" placeholder=\"${escHtml(this.wt.search)}\"><div class=\"advtagsjs\"></div></div>` +\n\t\t\t`<div class=\"advgridjs\"></div></div>` +\n\t\t\t`<script type=\"text/plain\" class=\"advcode\">${ADV_CLIENT_CODE}</script>` +\n\t\t\t`<img alt=\"\" src=\"${boot}\" style=\"display:none\" onload=\"(function(){if(window.ADVscan){window.ADVscan();return;}var c=document.querySelector('script.advcode');if(!c)return;var s=document.createElement('script');s.textContent=c.textContent;document.body.appendChild(s);})()\">`\n\t\t);\n\t}\n\n\tprivate buildOverviewHtml(cams: Device[]): string {\n\t\tconst ts = Date.now();\n\t\tconst minCol = this.config.widgetMinCol || 150;\n\t\tconst maxW = this.config.widgetMaxModalWidth || 900;\n\t\tconst PAUSE_ATTR = ` onchange=\"if(!this.checked){var m=this.nextElementSibling.nextElementSibling,v=m&&m.querySelector('video');if(v){v.pause();}}\"`;\n\t\tconst tiles = cams\n\t\t\t.map(d => {\n\t\t\t\tconst oid = d.oid;\n\t\t\t\tconst id = `advlive${sanitize(oid)}`;\n\t\t\t\tconst grab = `${this.baseUrl}/grab.jpg?oid=${oid}&ot=2&maintainAR=1&ts=${ts}`;\n\t\t\t\tconst webm = `${this.baseUrl}/video.webm?oid=${oid}&ot=2`;\n\t\t\t\tconst name = escHtml(d.name || `Camera ${oid}`);\n\t\t\t\tconst arRaw = this.camAspect[oid] || this.config.widgetLiveAspect || '';\n\t\t\t\tconst ar = arRaw ? String(arRaw).replace('/', ' / ') : '';\n\t\t\t\tconst fix = ar ? ' advimgfix' : '';\n\t\t\t\tconst arStyle = ar ? ` style=\"aspect-ratio:${ar}\"` : '';\n\t\t\t\tconst inner =\n\t\t\t\t\t`<span class=\"advimg${fix}\"${arStyle}><img src=\"${grab}\" loading=\"lazy\" alt=\"\">` +\n\t\t\t\t\t`<span class=\"advtag\" style=\"top:5px;left:5px\">● ${escHtml(this.wt.live)}</span><span class=\"advplay\"></span></span>` +\n\t\t\t\t\t`<span class=\"advcap\">${name}</span>`;\n\t\t\t\treturn (\n\t\t\t\t\t`<input class=\"advlb\" type=\"checkbox\" id=\"${id}\"${PAUSE_ATTR}>` +\n\t\t\t\t\t`<label class=\"advcell advthumb\" for=\"${id}\">${inner}</label>` +\n\t\t\t\t\t`<div class=\"advmodal\"><label class=\"advbackdrop\" for=\"${id}\"></label>` +\n\t\t\t\t\t`<div class=\"advbox\"><label class=\"advclose\" for=\"${id}\">✕</label>` +\n\t\t\t\t\t`<video class=\"advvideo\" controls preload=\"none\" playsinline src=\"${webm}\"></video>` +\n\t\t\t\t\t`<div class=\"advinfo\">${name} · Live</div></div></div>`\n\t\t\t\t);\n\t\t\t})\n\t\t\t.join('');\n\t\tconst grid = tiles ? `<div class=\"advgrid\">${tiles}</div>` : `<div class=\"advempty\">No cameras</div>`;\n\t\treturn `<style>${galleryCss(minCol, maxW)}</style>${grid}`;\n\t}\n\n\t// ---- event data points ----\n\n\tprivate async writeEventDps(d: Device, fid: string, events: Record<string, unknown>[]): Promise<void> {\n\t\tconst oid = d.oid;\n\t\tawait this.ensureFolder(`${fid}.events`, 'Events', 'channel');\n\t\tawait this.ensureFolder(`${fid}.events.last`, 'Last event', 'channel');\n\n\t\tconst two = (n: number): string => String(n).padStart(2, '0');\n\t\tconst now = new Date();\n\t\tconst td = `${two(now.getDate())}.${two(now.getMonth() + 1)}.`;\n\t\tconst todayCount = events.filter(ev => this.fmtEvent(ev, oid).date === td).length;\n\n\t\tawait this.writeLeaf(`${fid}.events.count`, events.length);\n\t\tawait this.writeLeaf(`${fid}.events.today`, todayCount);\n\n\t\tif (events.length) {\n\t\t\tconst p = this.fmtEvent(events[0], oid);\n\t\t\tconst tsMs = (parseFloat(String((events[0] as AgentDvrEvent).c ?? 0)) - 621355968000000000) / 10000;\n\t\t\tawait this.writeLeaf(`${fid}.events.last.time`, `${p.date} ${p.time}`);\n\t\t\tawait this.writeLeaf(`${fid}.events.last.timestamp`, Math.round(tsMs));\n\t\t\tawait this.writeLeaf(`${fid}.events.last.tag`, p.tag);\n\t\t\tawait this.writeLeaf(`${fid}.events.last.duration`, p.dur ? parseFloat(p.dur) : 0);\n\t\t\tawait this.writeLeaf(`${fid}.events.last.size_mb`, p.sizeMB);\n\t\t\tawait this.writeLeaf(`${fid}.events.last.thumb`, p.thumb);\n\t\t\tawait this.writeLeaf(`${fid}.events.last.video`, p.video);\n\t\t}\n\n\t\tawait this.ensureFlag(`${fid}.events.new`, 'New event');\n\n\t\tif (this.config.enablePush) {\n\t\t\tconst pid = `${fid}.events.pushTrigger`;\n\t\t\tif (!this.ensuredFolders.has(pid)) {\n\t\t\t\tawait this.ensurePath(pid);\n\t\t\t\tawait this.setObjectNotExistsAsync(pid, {\n\t\t\t\t\ttype: 'state',\n\t\t\t\t\tcommon: {\n\t\t\t\t\t\tname: 'Push trigger (AgentDVR action)',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\trole: 'text',\n\t\t\t\t\t\tread: true,\n\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\tdef: '',\n\t\t\t\t\t},\n\t\t\t\t\tnative: {},\n\t\t\t\t});\n\t\t\t\tawait this.setStateAsync(pid, { val: '', ack: true });\n\t\t\t\tthis.ensuredFolders.add(pid);\n\t\t\t}\n\t\t\tthis.registry.set(pid, { kind: 'push', oid, fid });\n\t\t}\n\n\t\tconst ignore = (this.config.eventTagsIgnore || 'detected')\n\t\t\t.split(',')\n\t\t\t.map(s => s.trim().toLowerCase())\n\t\t\t.filter(Boolean);\n\t\tconst tokensOf = (s: string): string[] =>\n\t\t\ts\n\t\t\t\t.toLowerCase()\n\t\t\t\t.split(/[,\\s]+/)\n\t\t\t\t.filter(Boolean);\n\n\t\tfor (const kw of (this.config.eventTags || '')\n\t\t\t.split(',')\n\t\t\t.map(s => s.trim())\n\t\t\t.filter(Boolean)) {\n\t\t\tawait this.ensureFlag(`${fid}.events.detected_${sanitize(kw)}`, `Detected: ${kw}`);\n\t\t}\n\n\t\tif (this.config.eventTagsDynamic) {\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const ev of events) {\n\t\t\t\ttokensOf((ev as AgentDvrEvent).tg ?? '').forEach(t => seen.add(t));\n\t\t\t}\n\t\t\tfor (const t of seen) {\n\t\t\t\tif (ignore.includes(t)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait this.ensureFlag(`${fid}.events.detected_${sanitize(t)}`, `Detected: ${t}`);\n\t\t\t}\n\t\t}\n\n\t\tlet newCount = 0;\n\t\tif (events.length) {\n\t\t\tconst prev = this.lastEventFn[oid];\n\t\t\tif (prev !== undefined) {\n\t\t\t\tconst i = events.findIndex(e => (e as AgentDvrEvent).fn === prev);\n\t\t\t\tnewCount = i === -1 ? events.length : i;\n\t\t\t}\n\t\t\tthis.lastEventFn[oid] = (events[0] as AgentDvrEvent).fn ?? '';\n\t\t}\n\n\t\tif (newCount > 0) {\n\t\t\tawait this.pulse(`${fid}.events.new`);\n\t\t\tconst tags = new Set<string>();\n\t\t\tfor (let i = 0; i < newCount && i < events.length; i++) {\n\t\t\t\ttokensOf((events[i] as AgentDvrEvent).tg ?? '').forEach(t => tags.add(t));\n\t\t\t}\n\t\t\tfor (const t of tags) {\n\t\t\t\tif (ignore.includes(t)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst tid = `${fid}.events.detected_${sanitize(t)}`;\n\t\t\t\tawait this.ensureFlag(tid, `Detected: ${t}`);\n\t\t\t\tawait this.pulse(tid);\n\t\t\t}\n\t\t\tthis.log.debug(`${newCount} new event(s) cam ${oid} [${[...tags].join(',')}]`);\n\t\t}\n\t}\n\n\t// ---- camera events + widget ----\n\n\tprivate async updateCameraEvents(d: Device, fid: string): Promise<void> {\n\t\tif (d.ot !== 2) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this.config.enableWidget && !this.config.enableEventDps) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.eventBusy[d.oid]) {\n\t\t\treturn;\n\t\t}\n\t\tthis.eventBusy[d.oid] = true;\n\t\ttry {\n\t\t\tconst evRes = await this.apiGet(`/q/getEvents?oid=${d.oid}&ot=2`);\n\t\t\tconst evJson = asJson(evRes.data);\n\t\t\tif (!evJson) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst events = (\n\t\t\t\tArray.isArray(evJson.events) ? evJson.events : Array.isArray(evJson) ? evJson : []\n\t\t\t) as Record<string, unknown>[];\n\n\t\t\tif (this.config.enableEventDps) {\n\t\t\t\tawait this.writeEventDps(d, fid, events);\n\t\t\t}\n\n\t\t\tif (this.config.enableWidget) {\n\t\t\t\tconst wId = `${fid}.widget`;\n\t\t\t\tif (!this.ensuredFolders.has(wId)) {\n\t\t\t\t\tawait this.ensurePath(wId);\n\t\t\t\t\tawait this.setObjectNotExistsAsync(wId, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'HTML gallery widget',\n\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\trole: 'html',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\t\tdef: '',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tthis.ensuredFolders.add(wId);\n\t\t\t\t}\n\t\t\t\tconst ev = events.slice(0, Math.max(1, this.config.widgetAnzahl || 50));\n\t\t\t\tconst f = (ev[0] ?? {}) as AgentDvrEvent;\n\t\t\t\tconst l = (ev[ev.length - 1] ?? {}) as AgentDvrEvent;\n\t\t\t\tconst sig = `${ev.length}|${f.fn ?? ''}|${l.fn ?? ''}`;\n\t\t\t\tif (this.widgetSig[wId] !== sig) {\n\t\t\t\t\tawait this.setStateAsync(wId, { val: this.buildGalleryHtml(d, ev), ack: true });\n\t\t\t\t\tthis.widgetSig[wId] = sig;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.eventBusy[d.oid] = false;\n\t\t}\n\t}\n\n\tprivate pushRefresh(oid: number | string): void {\n\t\tconst d = this.devById.get(oid);\n\t\tif (!d) {\n\t\t\tthis.log.warn(`Push: camera ${oid} unknown (available after first poll)`);\n\t\t\treturn;\n\t\t}\n\t\tconst fid = this.deviceFolder(d);\n\t\tfor (const ms of [0, 1500, 3500, 6000]) {\n\t\t\tthis.setTimeout(\n\t\t\t\t() =>\n\t\t\t\t\tthis.updateCameraEvents(d, fid).catch(e =>\n\t\t\t\t\t\tthis.log.warn(`Push refresh error: ${(e as Error).message}`),\n\t\t\t\t\t),\n\t\t\t\tms,\n\t\t\t);\n\t\t}\n\t}\n\n\t// ---- main poll ----\n\n\tprivate async poll(): Promise<void> {\n\t\tconst res = await this.apiGet('/command/getObjects');\n\t\tconst json = asJson(res.data);\n\n\t\tif (!res.ok || !json) {\n\t\t\tawait this.setStateAsync('info.connection', false, true);\n\t\t\tawait this.setStateAsync('system.online', { val: false, ack: true });\n\t\t\tthis.log.warn(`AgentDVR unreachable: ${res.error || 'invalid response'}`);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.setStateAsync('info.connection', true, true);\n\t\tawait this.setStateAsync('system.online', { val: true, ack: true });\n\n\t\tif (json.settings) {\n\t\t\tawait this.flattenWrite(json.settings, 'system.settings', 0);\n\t\t}\n\n\t\tif (this.config.storeRawJson) {\n\t\t\tconst clean: Record<string, unknown> = { ...json };\n\t\t\tdelete clean.icons;\n\t\t\tawait this.writeLeaf('system.raw_getObjects', JSON.stringify(clean).slice(0, 60000));\n\t\t}\n\n\t\tconst devices = findDevices(json);\n\t\tawait this.setStateAsync('system.cameraCount', { val: devices.filter(d => d.ot === 2).length, ack: true });\n\n\t\tfor (const d of devices) {\n\t\t\tawait this.buildDevice(d);\n\t\t}\n\n\t\tconst stats = asJson((await this.apiGet('/command/getSystemStats')).data);\n\t\tif (stats) {\n\t\t\tawait this.flattenWrite(stats, 'system.stats', 0);\n\t\t\tconst gb = parseSizeGb(stats.disk_free);\n\t\t\tif (gb !== null) {\n\t\t\t\tawait this.writeLeaf('system.disk_free_gb', gb);\n\t\t\t}\n\t\t}\n\n\t\tconst status = asJson((await this.apiGet('/command/getStatus')).data);\n\t\tif (status) {\n\t\t\tawait this.flattenWrite(status, 'system.status', 0);\n\t\t}\n\n\t\tif (this.config.enableOverview) {\n\t\t\tconst cams = devices.filter(d => d.ot === 2);\n\t\t\tconst ovId = 'overview';\n\t\t\tif (!this.ensuredFolders.has(ovId)) {\n\t\t\t\tawait this.setObjectNotExistsAsync(ovId, {\n\t\t\t\t\ttype: 'state',\n\t\t\t\t\tcommon: {\n\t\t\t\t\t\tname: 'Overview (all cameras)',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\trole: 'html',\n\t\t\t\t\t\tread: true,\n\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\tdef: '',\n\t\t\t\t\t},\n\t\t\t\t\tnative: {},\n\t\t\t\t});\n\t\t\t\tthis.ensuredFolders.add(ovId);\n\t\t\t}\n\t\t\tawait this.setStateAsync(ovId, { val: this.buildOverviewHtml(cams), ack: true });\n\t\t}\n\n\t\tawait this.setStateAsync('system.lastUpdate', { val: new Date().toISOString(), ack: true });\n\t\tawait this.setStateAsync('system.lastPoll', { val: Date.now(), ack: true });\n\t}\n\n\tprivate scheduleRefresh(): void {\n\t\tif (this.refreshTimer !== undefined) {\n\t\t\tthis.clearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = undefined;\n\t\t}\n\t\tthis.refreshTimer = this.setTimeout(\n\t\t\t() => this.poll().catch(e => this.log.warn(`Refresh error: ${(e as Error).message}`)),\n\t\t\t1500,\n\t\t);\n\t}\n\n\t// ---- command execution ----\n\n\tprivate ptzUrl(oid: number | string, dir: number): string {\n\t\treturn `/ptz.cgi?oid=${encodeURIComponent(String(oid))}&dir=${dir}`;\n\t}\n\n\tprivate buildCommandUrl(entry: RegistryEntry): string {\n\t\tif (entry.kind === 'ptz') {\n\t\t\treturn this.ptzUrl(entry.oid!, entry.dir!);\n\t\t}\n\t\tif (entry.kind === 'sys') {\n\t\t\treturn entry.path as string;\n\t\t}\n\t\tconst qs: string[] = [];\n\t\tfor (const p of entry.params || []) {\n\t\t\tif (p === 'oid') {\n\t\t\t\tqs.push(`oid=${encodeURIComponent(String(entry.oid))}`);\n\t\t\t} else if (p === 'ot') {\n\t\t\t\tqs.push(`ot=${encodeURIComponent(String(entry.ot))}`);\n\t\t\t}\n\t\t}\n\t\treturn (entry.path || '') + (qs.length ? `?${qs.join('&')}` : '');\n\t}\n\n\tprivate async clearPtzSiblings(stateId: string): Promise<void> {\n\t\tconst prefix = stateId.slice(0, stateId.lastIndexOf('.') + 1);\n\t\tfor (const p of PTZ_DIRS) {\n\t\t\tif (!p.hold) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst sid = prefix + p.id;\n\t\t\tif (sid !== stateId) {\n\t\t\t\tawait this.setStateAsync(sid, { val: false, ack: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async runCommand(relId: string, entry: RegistryEntry, val: boolean): Promise<void> {\n\t\tif (entry.kind === 'push') {\n\t\t\tthis.log.info(`Push trigger cam ${entry.oid}`);\n\t\t\tawait this.setStateAsync(relId, { val: '', ack: true });\n\t\t\tthis.pushRefresh(entry.oid!);\n\t\t\treturn;\n\t\t}\n\n\t\tif (entry.kind === 'ptzHold') {\n\t\t\tconst oid = entry.oid!;\n\t\t\tconst startMove = async (): Promise<void> => {\n\t\t\t\tawait this.clearPtzSiblings(relId);\n\t\t\t\tawait this.apiGet(this.ptzUrl(oid, entry.dir!));\n\t\t\t\tthis.ptzActive.set(oid, relId);\n\t\t\t\tawait this.setStateAsync(relId, { val: true, ack: true });\n\t\t\t};\n\t\t\tconst stopMove = async (): Promise<void> => {\n\t\t\t\tawait this.apiGet(this.ptzUrl(oid, 11));\n\t\t\t\tif (this.ptzActive.get(oid) === relId) {\n\t\t\t\t\tthis.ptzActive.delete(oid);\n\t\t\t\t}\n\t\t\t\tawait this.setStateAsync(relId, { val: false, ack: true });\n\t\t\t};\n\t\t\tif (val) {\n\t\t\t\tif (this.ptzActive.get(oid) === relId) {\n\t\t\t\t\tawait stopMove();\n\t\t\t\t} else {\n\t\t\t\t\tawait startMove();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait stopMove();\n\t\t\t}\n\t\t\tthis.scheduleRefresh();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!val) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (entry.kind === 'sys' && entry.path === null) {\n\t\t\tawait this.poll().catch(e => this.log.warn(`Manual refresh error: ${(e as Error).message}`));\n\t\t\tawait this.setStateAsync(relId, { val: false, ack: true });\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = this.buildCommandUrl(entry);\n\t\tconst cmdRes = await this.apiGet(url);\n\t\tif (cmdRes.ok) {\n\t\t\tthis.log.debug(`OK: ${url}`);\n\t\t} else {\n\t\t\tthis.log.warn(`Command failed (${url}): ${cmdRes.error}`);\n\t\t}\n\n\t\tawait this.setStateAsync(relId, { val: false, ack: true });\n\t\tthis.scheduleRefresh();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new AgentDvr(options);\n} else {\n\t(() => new AgentDvr())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/io-package.json
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common": {
|
|
3
|
+
"name": "agent-dvr",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"news": {
|
|
6
|
+
"0.0.1": {
|
|
7
|
+
"en": "initial release",
|
|
8
|
+
"de": "Erstveröffentlichung",
|
|
9
|
+
"ru": "Начальная версия",
|
|
10
|
+
"pt": "lançamento inicial",
|
|
11
|
+
"nl": "Eerste uitgave",
|
|
12
|
+
"fr": "Première version",
|
|
13
|
+
"it": "Versione iniziale",
|
|
14
|
+
"es": "Versión inicial",
|
|
15
|
+
"pl": "Pierwsze wydanie",
|
|
16
|
+
"uk": "Початкова версія",
|
|
17
|
+
"zh-cn": "首次出版"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"titleLang": {
|
|
21
|
+
"en": "Agent DVR",
|
|
22
|
+
"de": "Agent DVR",
|
|
23
|
+
"ru": "Агент DVR",
|
|
24
|
+
"pt": "Agente DVR",
|
|
25
|
+
"nl": "Agent DVR",
|
|
26
|
+
"fr": "Agent DVR",
|
|
27
|
+
"it": "DVR dell'agente",
|
|
28
|
+
"es": "DVR del agente",
|
|
29
|
+
"pl": "Agent DVR",
|
|
30
|
+
"uk": "Агентський відеореєстратор",
|
|
31
|
+
"zh-cn": "代理 DVR"
|
|
32
|
+
},
|
|
33
|
+
"desc": {
|
|
34
|
+
"en": "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.",
|
|
35
|
+
"de": "Verbindet ioBroker mit AgentDVR: erkennt Kameras automatisch, spiegelt alle Gerätewerte als Datenpunkte wider, liefert Echtzeit-Trigger bei neuen Aufnahmen und generiert eine responsive HTML-Galerie mit optionaler Such- und Tag-Filterung.",
|
|
36
|
+
"ru": "Подключает ioBroker к AgentDVR: автоматически обнаруживает камеры, отображает все значения устройств в виде точек данных, обеспечивает срабатывание триггеров в реальном времени при появлении новых записей и генерирует адаптивную HTML-галерею с возможностью поиска и фильтрации по тегам.",
|
|
37
|
+
"pt": "Conecta o ioBroker ao AgentDVR: descobre câmeras automaticamente, espelha todos os valores dos dispositivos como pontos de dados, envia alertas em tempo real para novas gravações e gera uma galeria HTML responsiva com opções de pesquisa e filtragem por tags.",
|
|
38
|
+
"nl": "Verbindt ioBroker met AgentDVR: detecteert automatisch camera's, spiegelt alle apparaatwaarden als datapunten, levert realtime triggers voor nieuwe opnames en genereert een responsieve HTML-galerij met optionele zoek- en tagfiltering.",
|
|
39
|
+
"fr": "Connecte ioBroker à AgentDVR : détecte automatiquement les caméras, reproduit toutes les valeurs des appareils sous forme de points de données, envoie des déclencheurs en temps réel sur les nouveaux enregistrements et génère une galerie HTML réactive avec recherche et filtrage par étiquette optionnels.",
|
|
40
|
+
"it": "Collega ioBroker ad AgentDVR: rileva automaticamente le telecamere, replica tutti i valori dei dispositivi come punti dati, fornisce notifiche in tempo reale per le nuove registrazioni e genera una galleria HTML reattiva con funzionalità opzionali di ricerca e filtro per tag.",
|
|
41
|
+
"es": "Conecta ioBroker con AgentDVR: detecta automáticamente las cámaras, refleja todos los valores de los dispositivos como puntos de datos, proporciona notificaciones en tiempo real ante nuevas grabaciones y genera una galería HTML adaptable con opciones de búsqueda y filtrado por etiquetas.",
|
|
42
|
+
"pl": "Łączy ioBroker z AgentDVR: automatycznie wykrywa kamery, odzwierciedla wszystkie wartości urządzeń jako punkty danych, uruchamia wyzwalacze w czasie rzeczywistym dla nowych nagrań i generuje responsywną galerię HTML z opcjonalnym wyszukiwaniem i filtrowaniem tagów.",
|
|
43
|
+
"uk": "Підключає ioBroker до AgentDVR: автоматично виявляє камери, відображає всі значення пристроїв як точки даних, забезпечує тригери в режимі реального часу для нових записів та створює адаптивну HTML-галерею з додатковим пошуком та фільтрацією тегів.",
|
|
44
|
+
"zh-cn": "将 ioBroker 连接到 AgentDVR:自动发现摄像头,将所有设备值镜像为数据点,在新录像时提供实时触发,并生成具有可选搜索和标签过滤功能的响应式 HTML 图库。"
|
|
45
|
+
},
|
|
46
|
+
"authors": ["ipod86 <david@graef.email>"],
|
|
47
|
+
"keywords": ["ioBroker", "Agentdvr", "ispy", "ptz"],
|
|
48
|
+
"licenseInformation": {
|
|
49
|
+
"type": "free",
|
|
50
|
+
"license": "MIT"
|
|
51
|
+
},
|
|
52
|
+
"platform": "Javascript/Node.js",
|
|
53
|
+
"icon": "agent-dvr.png",
|
|
54
|
+
"enabled": true,
|
|
55
|
+
"extIcon": "https://raw.githubusercontent.com/ipod86/ioBroker.agent-dvr/main/admin/agent-dvr.png",
|
|
56
|
+
"readme": "https://github.com/ipod86/ioBroker.agent-dvr/blob/main/README.md",
|
|
57
|
+
"loglevel": "info",
|
|
58
|
+
"tier": 3,
|
|
59
|
+
"mode": "daemon",
|
|
60
|
+
"type": "alarm",
|
|
61
|
+
"compact": true,
|
|
62
|
+
"connectionType": "local",
|
|
63
|
+
"dataSource": "poll",
|
|
64
|
+
"adminUI": {
|
|
65
|
+
"config": "json"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": [
|
|
68
|
+
{
|
|
69
|
+
"js-controller": ">=6.0.11"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"globalDependencies": [
|
|
73
|
+
{
|
|
74
|
+
"admin": ">=7.0.23"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"native": {
|
|
79
|
+
"ip": "192.168.1.100",
|
|
80
|
+
"port": 8090,
|
|
81
|
+
"user": "",
|
|
82
|
+
"pass": "",
|
|
83
|
+
"pollSeconds": 30,
|
|
84
|
+
"httpTimeoutMs": 8000,
|
|
85
|
+
"enableSystemControls": true,
|
|
86
|
+
"enablePtz": true,
|
|
87
|
+
"enableUrls": true,
|
|
88
|
+
"enableEventDps": true,
|
|
89
|
+
"enablePush": true,
|
|
90
|
+
"enableOverview": true,
|
|
91
|
+
"storeRawJson": false,
|
|
92
|
+
"enableWidget": true,
|
|
93
|
+
"widgetMode": "nojs",
|
|
94
|
+
"widgetAnzahl": 50,
|
|
95
|
+
"widgetMinCol": 150,
|
|
96
|
+
"widgetShowTags": true,
|
|
97
|
+
"widgetLiveAspect": "",
|
|
98
|
+
"widgetTagPosition": "bottom-left",
|
|
99
|
+
"widgetMaxModalWidth": 900,
|
|
100
|
+
"widgetPlayerUrl": "",
|
|
101
|
+
"maxDepth": 6,
|
|
102
|
+
"maxArray": 30,
|
|
103
|
+
"eventTagsDynamic": true,
|
|
104
|
+
"eventTagsIgnore": "detected",
|
|
105
|
+
"eventTags": ""
|
|
106
|
+
},
|
|
107
|
+
"objects": [],
|
|
108
|
+
"instanceObjects": [
|
|
109
|
+
{
|
|
110
|
+
"_id": "info",
|
|
111
|
+
"type": "channel",
|
|
112
|
+
"common": {
|
|
113
|
+
"name": "Information"
|
|
114
|
+
},
|
|
115
|
+
"native": {}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"_id": "info.connection",
|
|
119
|
+
"type": "state",
|
|
120
|
+
"common": {
|
|
121
|
+
"role": "indicator.connected",
|
|
122
|
+
"name": "Device or service connected",
|
|
123
|
+
"type": "boolean",
|
|
124
|
+
"read": true,
|
|
125
|
+
"write": false,
|
|
126
|
+
"def": false
|
|
127
|
+
},
|
|
128
|
+
"native": {}
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iobroker.agent-dvr",
|
|
3
|
+
"version": "0.0.1",
|
|
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
|
+
"author": {
|
|
6
|
+
"name": "ipod86",
|
|
7
|
+
"email": "david@graef.email"
|
|
8
|
+
},
|
|
9
|
+
"contributors": [],
|
|
10
|
+
"homepage": "https://github.com/ipod86/ioBroker.agent-dvr",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"ioBroker",
|
|
14
|
+
"Agentdvr",
|
|
15
|
+
"ispy",
|
|
16
|
+
"ptz"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/ipod86/ioBroker.agent-dvr.git"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">= 22"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@iobroker/adapter-core": "^3.4.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@alcalzone/release-script": "^5.2.1",
|
|
30
|
+
"@alcalzone/release-script-plugin-iobroker": "^5.2.0",
|
|
31
|
+
"@alcalzone/release-script-plugin-license": "^5.2.0",
|
|
32
|
+
"@alcalzone/release-script-plugin-manual-review": "^5.2.0",
|
|
33
|
+
"@iobroker/adapter-dev": "^1.5.0",
|
|
34
|
+
"@iobroker/eslint-config": "^2.3.4",
|
|
35
|
+
"@iobroker/testing": "^5.2.2",
|
|
36
|
+
"@tsconfig/node22": "^22.0.0",
|
|
37
|
+
"@types/iobroker": "npm:@iobroker/types@^7.2.2",
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"rimraf": "^6.1.3",
|
|
40
|
+
"source-map-support": "^0.5.21",
|
|
41
|
+
"ts-node": "^10.9.2",
|
|
42
|
+
"typescript": "~5.9.3"
|
|
43
|
+
},
|
|
44
|
+
"main": "build/main.js",
|
|
45
|
+
"files": [
|
|
46
|
+
"admin{,/!(src)/**}/!(tsconfig|tsconfig.*|.eslintrc).{json,json5}",
|
|
47
|
+
"admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
|
|
48
|
+
"build/",
|
|
49
|
+
"www/",
|
|
50
|
+
"io-package.json",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"prebuild": "rimraf build",
|
|
55
|
+
"build": "build-adapter ts",
|
|
56
|
+
"watch": "build-adapter ts --watch",
|
|
57
|
+
"prebuild:ts": "rimraf build",
|
|
58
|
+
"build:ts": "build-adapter ts",
|
|
59
|
+
"watch:ts": "build-adapter ts --watch",
|
|
60
|
+
"test:ts": "mocha --config test/mocharc.custom.json src/**/*.test.ts",
|
|
61
|
+
"test:package": "mocha test/package --exit",
|
|
62
|
+
"test:integration": "mocha test/integration --exit",
|
|
63
|
+
"test": "npm run test:ts && npm run test:package",
|
|
64
|
+
"check": "tsc --noEmit",
|
|
65
|
+
"lint": "eslint -c eslint.config.mjs .",
|
|
66
|
+
"translate": "translate-adapter",
|
|
67
|
+
"release": "release-script"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/ipod86/ioBroker.agent-dvr/issues"
|
|
71
|
+
},
|
|
72
|
+
"readmeFilename": "README.md"
|
|
73
|
+
}
|