Compare commits

..

74 Commits

Author SHA1 Message Date
Koushik Dutta
6378c5953a server: bump core 2024-01-14 08:06:42 -08:00
Koushik Dutta
846034d7c8 core: fix login 2024-01-14 08:06:25 -08:00
Koushik Dutta
ad47f14922 ha: publish 2024-01-13 22:45:05 -08:00
Koushik Dutta
0066379b1e postrelease 2024-01-13 22:18:49 -08:00
Koushik Dutta
54193251ab server: bump minimum core version 2024-01-13 22:17:40 -08:00
Koushik Dutta
cd5e169439 core: publish 2024-01-13 22:16:18 -08:00
Koushik Dutta
249a87bd4c cameras: fix validation skip, update auth lib 2024-01-13 19:29:35 -08:00
Koushik Dutta
803400c2d8 homekit: bump deps and publish 2024-01-13 18:34:04 -08:00
Koushik Dutta
0e700a53d0 snapshot: give periodic snapshots a moment to return 2024-01-13 17:05:26 -08:00
Koushik Dutta
72647b0099 Update Dockerfile.lite 2024-01-13 16:17:38 -08:00
Koushik Dutta
85e41180b2 Update docker-common.yml 2024-01-13 16:14:38 -08:00
Koushik Dutta
18bf012bb5 docker: udpate base 2024-01-13 16:12:43 -08:00
Koushik Dutta
3f2b8de169 Merge branch 'main' of github.com:koush/scrypted 2024-01-13 16:01:37 -08:00
Koushik Dutta
c568c9a37d shrink lite build further 2024-01-13 16:01:12 -08:00
Koushik Dutta
a831c48f5f server: fix stupid esm mime dependency 2024-01-12 18:22:41 -08:00
Koushik Dutta
f0357d45f2 server: fix stupid esm mime dependency 2024-01-12 18:14:31 -08:00
Koushik Dutta
479b3ce1f3 postrelease 2024-01-12 16:39:30 -08:00
Koushik Dutta
bd7c7de8a5 Update package.json 2024-01-12 16:37:55 -08:00
Koushik Dutta
a06e786d19 client: Fix cors credentials 2024-01-12 15:51:06 -08:00
Koushik Dutta
dff05e733e server: update lockfile 2024-01-12 15:39:29 -08:00
Koushik Dutta
76e34af149 postrelease 2024-01-12 15:13:29 -08:00
Koushik Dutta
4f2e9e88e1 Merge branch 'main' of github.com:koush/scrypted 2024-01-12 09:27:04 -08:00
Koushik Dutta
2761b0745a client: remove http-auth-utils dependency 2024-01-12 09:26:09 -08:00
Brett Jia
ea78b7f59e core: fix scheduler (#1259) 2024-01-12 09:10:31 -08:00
Koushik Dutta
b8d233f08d videoanalysis: cpu usage wip 2024-01-11 20:08:57 -08:00
Koushik Dutta
f4e93c82a2 onvif: publish with latest http-auth-utils 2024-01-11 20:08:39 -08:00
Koushik Dutta
c72c34f954 common: remove node-fetch 2024-01-11 20:06:51 -08:00
Koushik Dutta
baec4e71da remove axios-digest-auth 2024-01-11 19:31:18 -08:00
Koushik Dutta
245c6e3006 doorbird: remove axios digest auth 2024-01-11 19:29:15 -08:00
Koushik Dutta
566c18251c snapshot: add support for periodic snapshots via http 2024-01-11 13:15:18 -08:00
Koushik Dutta
f18e58a108 sdk/homekit/snapshot: simplify periodic snapshot requests. remove homekit debouncer. 2024-01-11 11:29:03 -08:00
Koushik Dutta
5c6ea09d3e videoanalysis: implement dynamic cpu performance profiling 2024-01-11 11:04:41 -08:00
Koushik Dutta
646a9f214a snapshot: Update url fetcher 2024-01-11 09:58:23 -08:00
Koushik Dutta
6506c4236f various: fixup http lib 2024-01-11 00:37:21 -08:00
Koushik Dutta
a3e27ce8f8 Merge branch 'main' of github.com:koush/scrypted 2024-01-11 00:35:26 -08:00
Koushik Dutta
a54d5a5f59 cli: remove axios 2024-01-11 00:35:21 -08:00
Koushik Dutta
7136759f8f Update install-scrypted-proxmox.sh 2024-01-11 00:32:48 -08:00
Koushik Dutta
049d9898b3 http/auth: simplify 2024-01-10 20:45:50 -08:00
Koushik Dutta
6d9e21b7b8 server: Fix import 2024-01-10 16:27:10 -08:00
Koushik Dutta
bfd1aef5d1 client: fixup 2024-01-10 16:23:51 -08:00
Koushik Dutta
5f02e6a272 various: more http refactoring 2024-01-10 16:08:38 -08:00
Koushik Dutta
56bbf00edc various: update http auth utils usage 2024-01-10 13:16:00 -08:00
Koushik Dutta
0c66456a87 sdk: limit chunks to 1. add support for multiple chunks. 2024-01-10 13:06:04 -08:00
Koushik Dutta
6b589b8d5a postrelease 2024-01-10 12:56:02 -08:00
Koushik Dutta
aef218c653 server: update http fetch usage, add support for relative require 2024-01-10 12:50:45 -08:00
Koushik Dutta
aea24a84f0 cameras: update http utils again 2024-01-10 11:13:37 -08:00
Koushik Dutta
bab3bef0d1 cameras: update http utils again 2024-01-10 11:13:17 -08:00
Koushik Dutta
56bda46ae9 webrtc: fix multiple ipv4/ipv6 address usage 2024-01-09 22:44:33 -08:00
Koushik Dutta
368b0fc26a onvif: fix motion resbuscribe 2024-01-09 20:17:13 -08:00
Koushik Dutta
fa50d6faab various: remove axios digest auth 2024-01-09 13:52:51 -08:00
Koushik Dutta
115d168cd3 snapshot: remove axios 2024-01-09 13:12:44 -08:00
Koushik Dutta
7ab93e8883 Merge branch 'main' of github.com:koush/scrypted 2024-01-09 13:04:09 -08:00
Koushik Dutta
e25cf860f0 common: replacement implementation for axios digest auth 2024-01-09 13:04:00 -08:00
Koushik Dutta
b5b56d81a8 Proxmox: fix error check 2024-01-08 17:58:44 -08:00
Koushik Dutta
e7b6cb021c Update install-scrypted-proxmox.sh 2024-01-08 10:45:05 -08:00
Koushik Dutta
e96f374432 Update install-scrypted-proxmox.sh 2024-01-08 10:03:26 -08:00
Koushik Dutta
c4126d7569 onvif: publish 2024-01-08 08:54:36 -08:00
Billy Zoellers
074ba733a3 ONVIF: ignore invalid (array) ONVIF events from Axis cameras (#1253) 2024-01-08 08:50:47 -08:00
Koushik Dutta
622f494703 onvif: publish fixes 2024-01-07 20:03:35 -08:00
Koushik Dutta
28c8b97c26 ha: fix submodule 2024-01-07 20:02:03 -08:00
Brett Jia
c0af17b38d core: query latest docker image via scrypted server (#1247) 2024-01-06 23:54:38 -08:00
Koushik Dutta
44a82a1afa reolink: publish 2024-01-06 16:59:26 -08:00
Koushik Dutta
c9b4c14e35 Merge branch 'main' of github.com:koush/scrypted 2024-01-06 16:59:13 -08:00
Koushik Dutta
76534f1368 onvif: fix unsubscribe crash 2024-01-06 16:58:50 -08:00
Koushik Dutta
3f9a863961 onvif/reolink: fix onvif motion debouncing on motion stop 2024-01-06 10:28:17 -08:00
Koushik Dutta
83b0ebd5f0 docker: fix nvidia script 2024-01-06 09:33:43 -08:00
Koushik Dutta
b923a4ea27 docker: fix nvidia script 2024-01-06 09:32:05 -08:00
Koushik Dutta
941d213087 docker: fix nvidia script 2024-01-06 09:30:09 -08:00
Koushik Dutta
0e11b8b4c5 docker: remove pip reinstall step 2024-01-06 09:29:58 -08:00
Koushik Dutta
1be14878d1 docker: fix nvidia 2024-01-06 09:26:08 -08:00
Koushik Dutta
3e323911c7 proxmox: install script shoud auto boot 2024-01-05 12:27:11 -08:00
Koushik Dutta
ca36ab2d2d ha: publish 2024-01-04 12:27:17 -08:00
Koushik Dutta
a80e95912e python plugins: trigger redownload of deps 2024-01-04 11:35:24 -08:00
Koushik Dutta
4432d8dd67 postrelease 2024-01-04 10:38:49 -08:00
125 changed files with 13355 additions and 16081 deletions

View File

@@ -15,7 +15,7 @@ jobs:
# "20"
]
BASE: ["jammy"]
FLAVOR: ["full", "lite", "thin"]
FLAVOR: ["full", "lite"]
steps:
- name: Check out the repo
uses: actions/checkout@v3

6
.gitmodules vendored
View File

@@ -7,9 +7,6 @@
[submodule "plugins/tensorflow/face-api.js"]
path = external/face-api.js
url = ../../koush/face-api.js
[submodule "external/axios-digest-auth"]
path = external/axios-digest-auth
url = ../../koush/axios-digest-auth
[submodule "external/scrypted-ffmpeg"]
path = external/scrypted-ffmpeg
url = ../../koush/scrypted-ffmpeg
@@ -38,3 +35,6 @@
[submodule "plugins/wyze/docker-wyze-bridge"]
path = plugins/wyze/docker-wyze-bridge
url = ../../koush/docker-wyze-bridge.git
[submodule "plugins/onvif/onvif"]
path = plugins/onvif/onvif
url = ../../koush/onvif.git

View File

@@ -5,17 +5,19 @@
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"name": "ts-node",
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
"args": [
"${workspaceFolder}/src/test.ts",
],
"program": "${workspaceFolder}/dist/common/src/test.js",
"preLaunchTask": "npm: build",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
"runtimeArgs": [
"-r",
"ts-node/register"
],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
},
]
}

608
common/package-lock.json generated
View File

@@ -1,22 +1,22 @@
{
"name": "@scrypted/common",
"version": "1.0.2",
"version": "1.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/common",
"version": "1.0.2",
"version": "1.0.1",
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"ts-node": "^10.9.2"
}
},
"../external/werift/packages/webrtc": {
@@ -74,12 +74,12 @@
},
"../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.68",
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -111,68 +111,103 @@
},
"../server": {
"name": "@scrypted/server",
"version": "0.6.19",
"version": "0.82.0",
"license": "ISC",
"dependencies": {
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@mapbox/node-pre-gyp": "^1.0.10",
"@scrypted/types": "^0.2.63",
"adm-zip": "^0.5.9",
"axios": "^0.21.4",
"body-parser": "^1.19.0",
"@mapbox/node-pre-gyp": "^1.0.11",
"@scrypted/types": "^0.3.4",
"adm-zip": "^0.5.10",
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"debug": "^4.3.4",
"engine.io": "^6.2.0",
"engine.io": "^6.5.4",
"express": "^4.18.2",
"ffmpeg-static": "^5.1.0",
"ffmpeg-static": "^5.2.0",
"follow-redirects": "^1.15.4",
"http-auth": "^4.2.0",
"ip": "^1.1.8",
"level": "^6.0.1",
"level": "^8.0.0",
"linkfs": "^2.1.0",
"lodash": "^4.17.21",
"memfs": "^3.4.7",
"memfs": "^4.6.0",
"mime": "^3.0.0",
"mkdirp": "^1.0.4",
"nan": "^2.17.0",
"nan": "^2.18.0",
"node-dijkstra": "^2.5.0",
"node-forge": "^1.3.1",
"node-gyp": "^8.4.1",
"router": "^1.3.7",
"semver": "^7.3.8",
"node-gyp": "^10.0.1",
"router": "^1.3.8",
"semver": "^7.5.4",
"sharp": "^0.33.1",
"source-map-support": "^0.5.21",
"tar": "^6.1.11",
"tslib": "^2.4.0",
"typescript": "^4.8.4",
"whatwg-mimetype": "^2.3.0",
"ws": "^8.9.0"
"tar": "^6.2.0",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"whatwg-mimetype": "^4.0.0",
"ws": "^8.16.0"
},
"bin": {
"scrypted-serve": "bin/scrypted-serve"
},
"devDependencies": {
"@types/adm-zip": "^0.4.34",
"@types/cookie-parser": "^1.4.3",
"@types/debug": "^4.1.7",
"@types/express": "^4.17.14",
"@types/http-auth": "^4.1.1",
"@types/ip": "^1.1.0",
"@types/lodash": "^4.14.186",
"@types/mime": "^3.0.1",
"@types/mkdirp": "^1.0.2",
"@types/node-dijkstra": "^2.5.3",
"@types/node-forge": "^1.3.0",
"@types/pem": "^1.9.6",
"@types/rimraf": "^3.0.2",
"@types/semver": "^7.3.12",
"@types/source-map-support": "^0.5.6",
"@types/tar": "^4.0.5",
"@types/whatwg-mimetype": "^2.1.1",
"@types/ws": "^7.4.7"
"@types/adm-zip": "^0.5.5",
"@types/cookie-parser": "^1.4.6",
"@types/debug": "^4.1.12",
"@types/express": "^4.17.21",
"@types/follow-redirects": "^1.14.4",
"@types/http-auth": "^4.1.4",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.14.202",
"@types/mime": "^3.0.4",
"@types/node-dijkstra": "^2.5.6",
"@types/node-forge": "^1.3.10",
"@types/pem": "^1.14.4",
"@types/semver": "^7.5.6",
"@types/source-map-support": "^0.5.10",
"@types/tar": "^6.1.10",
"@types/whatwg-mimetype": "^3.0.2",
"@types/ws": "^8.5.10"
},
"optionalDependencies": {
"node-pty-prebuilt-multiarch": "^0.10.1-pre.5"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@scrypted/sdk": {
"resolved": "../sdk",
"link": true
@@ -181,120 +216,215 @@
"resolved": "../server",
"link": true
},
"node_modules/@types/node": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.0.tgz",
"integrity": "sha512-nmP+VR4oT0pJUPFbKE4SXj3Yb4Q/kz3M9dSAO1GGMebRKWHQxLfDNmU/yh3xxCJha3N60nQ/JwXWwOE/ZSEVag==",
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
"dev": true
},
"node_modules/fetch-blob": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"node_modules/@types/node": {
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
"undici-types": "~5.26.4"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=12.20.0"
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/http-auth-utils": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/http-auth-utils/-/http-auth-utils-3.0.2.tgz",
"integrity": "sha512-cQ8957aiUX0lgV1620uIGKGJc0sEuD/QK4ueZ0hb60MGbO0f6ahcuIgPjamAD98D/AUGizKVm+dNvUVHs0f4Ow==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/http-auth-utils/-/http-auth-utils-5.0.1.tgz",
"integrity": "sha512-YPiLVYdwpBEWB85iWYg7V/ZW3mBfPLCTFQWEiPAA5CKXHJOAPbnJ0xDHLiE6KbPRvrYCwLuWqTG0fLfXVjMUcQ==",
"dependencies": {
"yerror": "^6.0.0"
"yerror": "^8.0.0"
},
"engines": {
"node": ">=12.19.0"
"node": ">=18.16.0"
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
"@swc/wasm": {
"optional": true
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch-commonjs": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/node-fetch-commonjs/-/node-fetch-commonjs-3.1.1.tgz",
"integrity": "sha512-TgkdVJdiEaauzWwB9NoD4TvHZFtG6KKEffvotWf9WNIyoRZHsCFjGfb3bhkIXrMt3YFgFi8ZApbwWoe1h3XTpA==",
"dependencies": {
"formdata-polyfill": "^4.0.10",
"web-streams-polyfill": "^3.1.1"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/typescript": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
"integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
"node": ">=14.17"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==",
"engines": {
"node": ">= 8"
}
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"node_modules/yerror": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/yerror/-/yerror-6.0.1.tgz",
"integrity": "sha512-0Bxo+NyeucjxhmPB5z3lmI/N/cOu8L1Q8JVta6/I5G6J/JhCSSPwk8qt9N4yOFSjwkvhDwzUSQglfBIAllvi1Q==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/yerror/-/yerror-8.0.0.tgz",
"integrity": "sha512-FemWD5/UqNm8ffj8oZIbjWXIF2KE0mZssggYpdaQkWDDgXBQ/35PNIxEuz6/YLn9o0kOxDBNJe8x8k9ljD7k/g==",
"engines": {
"node": ">=12.19.0"
"node": ">=18.16.0"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
}
},
"dependencies": {
"@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"requires": {
"@jridgewell/trace-mapping": "0.3.9"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"@scrypted/sdk": {
"version": "file:../sdk",
"requires": {
@@ -302,7 +432,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -322,117 +452,181 @@
"@scrypted/server": {
"version": "file:../server",
"requires": {
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@mapbox/node-pre-gyp": "^1.0.10",
"@scrypted/types": "^0.2.63",
"@types/adm-zip": "^0.4.34",
"@types/cookie-parser": "^1.4.3",
"@types/debug": "^4.1.7",
"@types/express": "^4.17.14",
"@types/http-auth": "^4.1.1",
"@types/ip": "^1.1.0",
"@types/lodash": "^4.14.186",
"@types/mime": "^3.0.1",
"@types/mkdirp": "^1.0.2",
"@types/node-dijkstra": "^2.5.3",
"@types/node-forge": "^1.3.0",
"@types/pem": "^1.9.6",
"@types/rimraf": "^3.0.2",
"@types/semver": "^7.3.12",
"@types/source-map-support": "^0.5.6",
"@types/tar": "^4.0.5",
"@types/whatwg-mimetype": "^2.1.1",
"@types/ws": "^7.4.7",
"adm-zip": "^0.5.9",
"axios": "^0.21.4",
"body-parser": "^1.19.0",
"@mapbox/node-pre-gyp": "^1.0.11",
"@scrypted/types": "^0.3.4",
"@types/adm-zip": "^0.5.5",
"@types/cookie-parser": "^1.4.6",
"@types/debug": "^4.1.12",
"@types/express": "^4.17.21",
"@types/follow-redirects": "^1.14.4",
"@types/http-auth": "^4.1.4",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.14.202",
"@types/mime": "^3.0.4",
"@types/node-dijkstra": "^2.5.6",
"@types/node-forge": "^1.3.10",
"@types/pem": "^1.14.4",
"@types/semver": "^7.5.6",
"@types/source-map-support": "^0.5.10",
"@types/tar": "^6.1.10",
"@types/whatwg-mimetype": "^3.0.2",
"@types/ws": "^8.5.10",
"adm-zip": "^0.5.10",
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"debug": "^4.3.4",
"engine.io": "^6.2.0",
"engine.io": "^6.5.4",
"express": "^4.18.2",
"ffmpeg-static": "^5.1.0",
"ffmpeg-static": "^5.2.0",
"follow-redirects": "^1.15.4",
"http-auth": "^4.2.0",
"ip": "^1.1.8",
"level": "^6.0.1",
"level": "^8.0.0",
"linkfs": "^2.1.0",
"lodash": "^4.17.21",
"memfs": "^3.4.7",
"memfs": "^4.6.0",
"mime": "^3.0.0",
"mkdirp": "^1.0.4",
"nan": "^2.17.0",
"nan": "^2.18.0",
"node-dijkstra": "^2.5.0",
"node-forge": "^1.3.1",
"node-gyp": "^8.4.1",
"node-gyp": "^10.0.1",
"node-pty-prebuilt-multiarch": "^0.10.1-pre.5",
"router": "^1.3.7",
"semver": "^7.3.8",
"router": "^1.3.8",
"semver": "^7.5.4",
"sharp": "^0.33.1",
"source-map-support": "^0.5.21",
"tar": "^6.1.11",
"tslib": "^2.4.0",
"typescript": "^4.8.4",
"whatwg-mimetype": "^2.3.0",
"ws": "^8.9.0"
"tar": "^6.2.0",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"whatwg-mimetype": "^4.0.0",
"ws": "^8.16.0"
}
},
"@types/node": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.0.tgz",
"integrity": "sha512-nmP+VR4oT0pJUPFbKE4SXj3Yb4Q/kz3M9dSAO1GGMebRKWHQxLfDNmU/yh3xxCJha3N60nQ/JwXWwOE/ZSEVag==",
"@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
"dev": true
},
"fetch-blob": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
"@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true
},
"@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true
},
"@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"@types/node": {
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"requires": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
"undici-types": "~5.26.4"
}
},
"formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"requires": {
"fetch-blob": "^3.1.2"
}
"acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true
},
"acorn-walk": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
"dev": true
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"http-auth-utils": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/http-auth-utils/-/http-auth-utils-3.0.2.tgz",
"integrity": "sha512-cQ8957aiUX0lgV1620uIGKGJc0sEuD/QK4ueZ0hb60MGbO0f6ahcuIgPjamAD98D/AUGizKVm+dNvUVHs0f4Ow==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/http-auth-utils/-/http-auth-utils-5.0.1.tgz",
"integrity": "sha512-YPiLVYdwpBEWB85iWYg7V/ZW3mBfPLCTFQWEiPAA5CKXHJOAPbnJ0xDHLiE6KbPRvrYCwLuWqTG0fLfXVjMUcQ==",
"requires": {
"yerror": "^6.0.0"
"yerror": "^8.0.0"
}
},
"node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node-fetch-commonjs": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/node-fetch-commonjs/-/node-fetch-commonjs-3.1.1.tgz",
"integrity": "sha512-TgkdVJdiEaauzWwB9NoD4TvHZFtG6KKEffvotWf9WNIyoRZHsCFjGfb3bhkIXrMt3YFgFi8ZApbwWoe1h3XTpA==",
"ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"requires": {
"formdata-polyfill": "^4.0.10",
"web-streams-polyfill": "^3.1.1"
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
}
},
"typescript": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
"integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA=="
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw=="
},
"web-streams-polyfill": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA=="
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"yerror": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/yerror/-/yerror-6.0.1.tgz",
"integrity": "sha512-0Bxo+NyeucjxhmPB5z3lmI/N/cOu8L1Q8JVta6/I5G6J/JhCSSPwk8qt9N4yOFSjwkvhDwzUSQglfBIAllvi1Q=="
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/yerror/-/yerror-8.0.0.tgz",
"integrity": "sha512-FemWD5/UqNm8ffj8oZIbjWXIF2KE0mZssggYpdaQkWDDgXBQ/35PNIxEuz6/YLn9o0kOxDBNJe8x8k9ljD7k/g=="
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

View File

@@ -11,13 +11,13 @@
"author": "",
"license": "ISC",
"dependencies": {
"@scrypted/server": "file:../server",
"@scrypted/sdk": "file:../sdk",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"ts-node": "^10.9.2"
}
}

View File

@@ -1,30 +0,0 @@
import sdk from "@scrypted/sdk";
const { systemManager, log } = sdk;
export async function alertRecommendedPlugins(plugins: { [pkg: string]: string }) {
const pluginsComponent = await systemManager.getComponent('plugins');
let recommended: any;
try {
recommended = JSON.parse(localStorage.getItem('alert-recommended'));
}
catch (e) {
recommended = {};
}
for (const plugin of Object.keys(plugins)) {
try {
if (recommended[plugin])
continue;
recommended[plugin] = true;
localStorage.setItem('alert-recommended', JSON.stringify(recommended));
const id = await pluginsComponent.getIdForPluginId(plugin);
if (id)
continue;
const name = plugins[plugin];
log.a(`Installation of the ${name} plugin is also recommended. origin:/#/component/plugin/install/${plugin}`)
}
catch (e) {
}
}
}

View File

@@ -1,12 +1,8 @@
import type { TranspileOptions } from "typescript";
import sdk, { ScryptedDeviceBase, MixinDeviceBase, ScryptedInterface, ScryptedDeviceType } from "@scrypted/sdk";
import vm from "vm";
import sdk, { MixinDeviceBase, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedInterfaceDescriptors } from "@scrypted/sdk";
import fs from 'fs';
import type { TranspileOptions } from "typescript";
import vm from "vm";
import { ScriptDevice } from "./monaco/script-device";
import { ScryptedInterfaceDescriptors } from "@scrypted/sdk";
import fetch from 'node-fetch-commonjs';
import { PluginAPIProxy } from '../../../server/src/plugin/plugin-api';
import { SystemManagerImpl } from '../../../server/src/plugin/system';
const { systemManager, deviceManager, mediaManager, endpointManager } = sdk;
@@ -61,7 +57,6 @@ export async function scryptedEval(device: ScryptedDeviceBase, script: string, e
const allParams = Object.assign({}, params, {
sdk,
fs: require('realfs'),
fetch,
ScryptedDeviceBase,
MixinDeviceBase,
systemManager,

View File

@@ -0,0 +1,50 @@
import { httpFetch, httpFetchParseIncomingMessage } from '../../server/src/fetch/http-fetch';
import type { IncomingMessage } from 'http';
import type { Readable } from 'stream';
import { createAuthFetch } from '../../packages/auth-fetch/src/auth-fetch';
export type { HttpFetchOptions, HttpFetchResponseType } from '../../server/src/fetch/http-fetch';
export type { AuthFetchCredentialState, AuthFetchOptions } from '../../packages/auth-fetch/src/auth-fetch';
export const authHttpFetch = createAuthFetch<Readable, IncomingMessage>(httpFetch, httpFetchParseIncomingMessage);
function ensureType<T>(v: T) {
}
async function test() {
const a = await authHttpFetch({
credential: undefined,
url: 'http://example.com',
});
ensureType<Buffer>(a.body);
const b = await authHttpFetch({
credential: undefined,
url: 'http://example.com',
responseType: 'json',
});
ensureType<any>(b.body);
const c = await authHttpFetch({
credential: undefined,
url: 'http://example.com',
responseType: 'readable',
});
ensureType<IncomingMessage>(c.body);
const d = await authHttpFetch({
credential: undefined,
url: 'http://example.com',
responseType: 'buffer',
});
ensureType<Buffer>(d.body);
const e = await authHttpFetch({
credential: undefined,
url: 'http://example.com',
responseType: 'text',
});
ensureType<string>(e.body);
}

View File

@@ -1,8 +1,6 @@
import crypto, { randomBytes } from 'crypto';
import dgram from 'dgram';
import { once } from 'events';
import { BASIC } from 'http-auth-utils/dist/index';
import { parseHTTPHeadersQuotedKeyValueSet } from 'http-auth-utils/dist/utils';
import net from 'net';
import { Duplex, Readable, Writable } from 'stream';
import tls from 'tls';
@@ -363,7 +361,7 @@ export class RtspClient extends RtspBase {
}
}
writeRequest(method: string, headers?: Headers, path?: string, body?: Buffer) {
async writeRequest(method: string, headers?: Headers, path?: string, body?: Buffer) {
headers = headers || {};
let fullUrl = this.url;
@@ -390,7 +388,7 @@ export class RtspClient extends RtspBase {
headers['User-Agent'] = 'Scrypted';
if (this.wwwAuthenticate)
headers['Authorization'] = this.createAuthorizationHeader(method, new URL(fullUrl));
headers['Authorization'] = await this.createAuthorizationHeader(method, new URL(fullUrl));
if (this.session)
headers['Session'] = this.session;
@@ -531,10 +529,13 @@ export class RtspClient extends RtspBase {
}
}
createAuthorizationHeader(method: string, url: URL) {
async createAuthorizationHeader(method: string, url: URL) {
if (!this.wwwAuthenticate)
throw new Error('no WWW-Authenticate found');
const { BASIC } = await import('http-auth-utils');
const { parseHTTPHeadersQuotedKeyValueSet } = await import('http-auth-utils/dist/utils');
if (this.wwwAuthenticate.includes('Basic')) {
const hash = BASIC.computeHash(url);
return `Basic ${hash}`;
@@ -586,7 +587,7 @@ export class RtspClient extends RtspBase {
}
async request(method: string, headers?: Headers, path?: string, body?: Buffer, authenticating?: boolean): Promise<RtspServerResponse> {
this.writeRequest(method, headers, path, body);
await this.writeRequest(method, headers, path, body);
const message = this.requestTimeout ? await timeoutPromise(this.requestTimeout, this.readMessage()) : await this.readMessage();
const statusLine = message[0];

View File

@@ -1,6 +1,6 @@
# Home Assistant Addon Configuration
name: Scrypted
version: "18-jammy-full.s6-v0.79.0"
version: "18-jammy-full.s6-v0.84.0"
slug: scrypted
description: Scrypted is a high performance home video integration and automation platform
url: "https://github.com/koush/scrypted"

View File

@@ -16,6 +16,6 @@ ENV NODE_OPTIONS="--dns-result-order=ipv4first"
# changing this forces pip and npm to perform reinstalls.
# if this base image changes, this version must be updated.
ENV SCRYPTED_BASE_VERSION="20240103"
ENV SCRYPTED_BASE_VERSION="20241303"
CMD npm --prefix /server exec scrypted-serve

View File

@@ -60,11 +60,7 @@ RUN apt-get -y install \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
# pyvips is broken on x86 due to mismatch ffi
# https://stackoverflow.com/questions/62658237/it-seems-that-the-version-of-the-libffi-library-seen-at-runtime-is-different-fro
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install --force-reinstall --no-binary :all: cffi
RUN python3 -m pip install debugpy typing_extensions psutil
################################################################
@@ -90,7 +86,6 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa && \
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install --force-reinstall --no-binary :all: cffi
RUN python3.9 -m pip install debugpy typing_extensions psutil
# Coral Edge TPU
@@ -107,8 +102,6 @@ ENV SCRYPTED_INSTALL_PATH="/server"
RUN test -f "/usr/bin/ffmpeg"
ENV SCRYPTED_FFMPEG_PATH="/usr/bin/ffmpeg"
# changing this forces pip and npm to perform reinstalls.
# if this base image changes, this version must be updated.
ENV SCRYPTED_DOCKER_FLAVOR="full"
################################################################

View File

@@ -6,13 +6,7 @@ ENV DEBIAN_FRONTEND=noninteractive
# base tools and development stuff
RUN apt-get update && apt-get -y install \
curl software-properties-common apt-utils \
build-essential \
cmake \
ffmpeg \
gcc \
libcairo2-dev \
libgirepository1.0-dev \
pkg-config && \
ffmpeg && \
apt-get -y update && \
apt-get -y upgrade

View File

@@ -1,4 +1,4 @@
FROM ghcr.io/koush/18-jammy-full.s6
FROM ghcr.io/koush/scrypted:18-jammy-full.s6
WORKDIR /
@@ -12,11 +12,3 @@ ENV PATH=$CONDA_DIR/bin:$PATH
RUN conda install -c conda-forge cudatoolkit=11.2.2 cudnn=8.1.0
ENV CONDA_PREFIX=/opt/conda
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CONDA_PREFIX/lib/
# this is a copy pasta, seems to need a reinstall.
# python pip
RUN python3 -m pip install --upgrade pip
# pyvips is broken on x86 due to mismatch ffi
# https://stackoverflow.com/questions/62658237/it-seems-that-the-version-of-the-libffi-library-seen-at-runtime-is-different-fro
RUN python3 -m pip install --force-reinstall --no-binary :all: cffi
RUN python3 -m pip install debugpy typing_extensions psutil

View File

@@ -46,6 +46,6 @@ ENV NODE_OPTIONS="--dns-result-order=ipv4first"
# changing this forces pip and npm to perform reinstalls.
# if this base image changes, this version must be updated.
ENV SCRYPTED_BASE_VERSION="20240103"
ENV SCRYPTED_BASE_VERSION="20241303"
CMD npm --prefix /server exec scrypted-serve

View File

@@ -1,3 +1,3 @@
./docker-build.sh
docker build -t ghcr.io/koush/scrypted:18-jammy-full.nvidia -f Dockerfile.nvidia
docker build -t ghcr.io/koush/scrypted:18-jammy-full.nvidia -f Dockerfile.nvidia .

View File

@@ -18,7 +18,6 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa && \
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install --force-reinstall --no-binary :all: cffi
RUN python3.9 -m pip install debugpy typing_extensions psutil
# Coral Edge TPU

View File

@@ -57,11 +57,7 @@ RUN apt-get -y install \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
# pyvips is broken on x86 due to mismatch ffi
# https://stackoverflow.com/questions/62658237/it-seems-that-the-version-of-the-libffi-library-seen-at-runtime-is-different-fro
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install --force-reinstall --no-binary :all: cffi
RUN python3 -m pip install debugpy typing_extensions psutil
################################################################

View File

@@ -10,7 +10,7 @@ function readyn() {
}
cd /tmp
SCRYPTED_VERSION=v0.79.0
SCRYPTED_VERSION=v0.80.0
SCRYPTED_TAR_ZST=scrypted-$SCRYPTED_VERSION.tar.zst
if [ -z "$VMID" ]
then
@@ -51,6 +51,23 @@ then
exit 1
fi
pct set $VMID -net0 name=eth0,bridge=vmbr0,ip=dhcp,ip6=auto
if [ "$?" != "0" ]
then
echo ""
echo "pct set network failed"
echo ""
echo "Ignoring... Please verify your container's network settings."
fi
CONF=/etc/pve/lxc/$VMID.conf
if [ -f "$CONF" ]
then
echo "onboot: 1" >> $CONF
else
echo "$CONF not found? Start on boot must be enabled manually."
fi
echo "Adding udev rule: /etc/udev/rules.d/65-scrypted.rules"
readyn "Add udev rule for hardware acceleration? This may conflict with existing rules."
if [ "$yn" == "y" ]
@@ -58,9 +75,10 @@ then
sh -c "echo 'SUBSYSTEM==\"apex\", MODE=\"0666\"' > /etc/udev/rules.d/65-scrypted.rules"
sh -c "echo 'KERNEL==\"renderD128\", MODE=\"0666\"' >> /etc/udev/rules.d/65-scrypted.rules"
sh -c "echo 'KERNEL==\"card0\", MODE=\"0666\"' >> /etc/udev/rules.d/65-scrypted.rules"
sh -c "echo 'SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"1a6e\", ATTRS{idProduct}==\"089a\", MODE=\"0666\"' >> /etc/udev/rules.d/65-scrypted.rules"
sh -c "echo 'SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"18d1\", ATTRS{idProduct}==\"9302\", MODE=\"0666\"' >> /etc/udev/rules.d/65-scrypted.rules"
udevadm control --reload-rules && udevadm trigger
fi
echo "Scrypted setup is complete and the container resources can be started."
echo "Scrypted NVR users should provide at least 4 cores and 16GB RAM prior to starting."

11
packages/auth-fetch/.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
node_modules
.DS_Store
.gcloud/
dist/
volume
scrypted.db
out
scrypted.db.bak
.exit
.update
.venv

580
packages/auth-fetch/package-lock.json generated Normal file
View File

@@ -0,0 +1,580 @@
{
"name": "@scrypted/auth-fetch",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/auth-fetch",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"follow-redirects": "^1.15.4",
"http-auth-utils": "^5.0.1"
},
"devDependencies": {
"@types/node": "^20.9.4",
"rimraf": "^5.0.5",
"typescript": "^5.3.2"
}
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"optional": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@types/node": {
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
"minimatch": "^9.0.1",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
"path-scurry": "^1.10.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/http-auth-utils": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/http-auth-utils/-/http-auth-utils-5.0.1.tgz",
"integrity": "sha512-YPiLVYdwpBEWB85iWYg7V/ZW3mBfPLCTFQWEiPAA5CKXHJOAPbnJ0xDHLiE6KbPRvrYCwLuWqTG0fLfXVjMUcQ==",
"dependencies": {
"yerror": "^8.0.0"
},
"engines": {
"node": ">=18.16.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
"node_modules/jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dev": true,
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/lru-cache": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz",
"integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==",
"dev": true,
"engines": {
"node": "14 || >=16.14"
}
},
"node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/path-scurry": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
"dev": true,
"dependencies": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz",
"integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==",
"dev": true,
"dependencies": {
"glob": "^10.3.7"
},
"bin": {
"rimraf": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/typescript": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yerror": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/yerror/-/yerror-8.0.0.tgz",
"integrity": "sha512-FemWD5/UqNm8ffj8oZIbjWXIF2KE0mZssggYpdaQkWDDgXBQ/35PNIxEuz6/YLn9o0kOxDBNJe8x8k9ljD7k/g==",
"engines": {
"node": ">=18.16.0"
}
}
}
}

View File

@@ -0,0 +1,23 @@
{
"name": "@scrypted/auth-fetch",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"prebuild": "rimraf dist",
"build": "tsc --outDir dist",
"prepublishOnly": "npm run build",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@types/node": "^20.9.4",
"rimraf": "^5.0.5",
"typescript": "^5.3.2"
},
"dependencies": {
"follow-redirects": "^1.15.4",
"http-auth-utils": "^5.0.1"
},
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,135 @@
import { HttpFetchOptions, HttpFetchResponseType, checkStatus, fetcher, getFetchMethod, setDefaultHttpFetchAccept } from '../../../server/src/fetch';
export interface AuthFetchCredentialState {
username: string;
password: string;
}
export interface AuthFetchOptions {
credential?: AuthFetchCredentialState;
}
async function getAuth(options: AuthFetchOptions, url: string | URL, method: string) {
if (!options.credential)
return;
const { BASIC, DIGEST, parseWWWAuthenticateHeader } = await import('http-auth-utils');
const credential = options.credential as AuthFetchCredentialState & {
count?: number;
digest?: ReturnType<typeof parseWWWAuthenticateHeader<typeof DIGEST>>;
basic?: ReturnType<typeof parseWWWAuthenticateHeader<typeof BASIC>>;
};
const { digest, basic } = credential;
if (digest) {
credential.count ||= 0;
++credential.count;
const nc = ('00000000' + credential.count).slice(-8);
const cnonce = [...Array(24)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
const uri = new URL(url).pathname;
const { DIGEST, buildAuthorizationHeader } = await import('http-auth-utils');
const response = DIGEST.computeHash({
username: options.credential.username,
password: options.credential.password,
method,
uri,
nc,
cnonce,
algorithm: 'MD5',
qop: digest.data.qop!,
...digest.data,
});
const header = buildAuthorizationHeader(DIGEST, {
username: options.credential.username,
uri,
nc,
cnonce,
algorithm: digest.data.algorithm!,
qop: digest.data.qop!,
response,
...digest.data,
});
return header;
}
else if (basic) {
const { BASIC, buildAuthorizationHeader } = await import('http-auth-utils');
const header = buildAuthorizationHeader(BASIC, {
username: options.credential.username,
password: options.credential.password,
});
return header;
}
}
export function createAuthFetch<B, M>(
h: fetcher<B, M>,
parser: (body: M, responseType: HttpFetchResponseType) => Promise<any>
) {
const authHttpFetch = async <T extends HttpFetchOptions<B>>(options: T & AuthFetchOptions): ReturnType<typeof h<T>> => {
const method = getFetchMethod(options);
const headers = new Headers(options.headers);
options.headers = headers;
setDefaultHttpFetchAccept(headers, options.responseType);
const initialHeader = await getAuth(options, options.url, method);
// try to provide an authorization if a session exists, but don't override Authorization if provided already.
// 401 will trigger a proper auth.
if (initialHeader && !headers.has('Authorization'))
headers.set('Authorization', initialHeader);
const initialResponse = await h({
...options,
ignoreStatusCode: true,
responseType: 'readable',
});
if (initialResponse.statusCode !== 401 || !options.credential) {
if (!options?.ignoreStatusCode)
checkStatus(initialResponse.statusCode);
return {
...initialResponse,
body: await parser(initialResponse.body, options.responseType),
};
}
let authenticateHeaders: string | string[] = initialResponse.headers.get('www-authenticate');
if (!authenticateHeaders)
throw new Error('Did not find WWW-Authenticate header.');
if (typeof authenticateHeaders === 'string')
authenticateHeaders = [authenticateHeaders];
const { BASIC, DIGEST, parseWWWAuthenticateHeader } = await import('http-auth-utils');
const parsedHeaders = authenticateHeaders.map(h => parseWWWAuthenticateHeader(h));
const digest = parsedHeaders.find(p => p.type === 'Digest') as ReturnType<typeof parseWWWAuthenticateHeader<typeof DIGEST>>;
const basic = parsedHeaders.find(p => p.type === 'Basic') as ReturnType<typeof parseWWWAuthenticateHeader<typeof BASIC>>;
const credential = options.credential as AuthFetchCredentialState & {
count?: number;
digest?: ReturnType<typeof parseWWWAuthenticateHeader<typeof DIGEST>>;
basic?: ReturnType<typeof parseWWWAuthenticateHeader<typeof BASIC>>;
};
credential.digest = digest;
credential.basic = basic;
if (!digest && !basic)
throw new Error(`Unknown WWW-Authenticate type: ${parsedHeaders[0]?.type}`);
const header = await getAuth(options, options.url, method);
if (header)
headers.set('Authorization', header);
return h(options);
}
return authHttpFetch;
}

View File

@@ -0,0 +1,19 @@
import { createAuthFetch } from "./auth-fetch";
import { httpFetch, httpFetchParseIncomingMessage } from '../../../server/src/fetch/http-fetch';
import type { Readable } from "stream";
import type { IncomingMessage } from "http";
import { domFetch, domFetchParseIncomingMessage } from "../../../server/src/fetch";
function init() {
try {
require('net');
require('events');
return createAuthFetch<Readable, IncomingMessage>(httpFetch, httpFetchParseIncomingMessage);
}
catch (e) {
}
return createAuthFetch<BodyInit, Response>(domFetch, domFetchParseIncomingMessage);
}
export const authFetch = init();

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "esnext",
"noImplicitAny": true,
"outDir": "./dist",
"esModuleInterop": true,
"sourceMap": true,
"inlineSources": true,
"declaration": true,
"resolveJsonModule": true,
},
"include": [
"src/**/*"
],
}

View File

@@ -1,17 +1,16 @@
{
"name": "scrypted",
"version": "1.3.4",
"version": "1.3.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "scrypted",
"version": "1.3.4",
"version": "1.3.6",
"license": "ISC",
"dependencies": {
"@scrypted/client": "^1.3.2",
"@scrypted/client": "^1.3.3",
"@scrypted/types": "^0.2.99",
"axios": "^0.25.0",
"engine.io-client": "^6.5.3",
"readline-sync": "^1.4.10",
"semver": "^7.5.4",
@@ -92,16 +91,21 @@
}
},
"node_modules/@scrypted/client": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@scrypted/client/-/client-1.3.2.tgz",
"integrity": "sha512-PZwjfKUYIMxBYm7V2o0/vAMlQmznKLN/d4rpshb5vV086mnhh578ik3h39awkwoPyWzNGDcYeoBY0BchhwtdOQ==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@scrypted/client/-/client-1.3.3.tgz",
"integrity": "sha512-Wuy7x02TCRy1buaDNX8NOIaL1j4ZXu4dqTTJsKHlPe3+umsBvpwbylD+YyyU8ghQJC6a40Bs5UMsvnCvNa/1fg==",
"dependencies": {
"@scrypted/types": "^0.2.99",
"axios": "^0.25.0",
"@scrypted/types": "^0.3.4",
"engine.io-client": "^6.5.3",
"follow-redirects": "^1.15.4",
"rimraf": "^5.0.5"
}
},
"node_modules/@scrypted/client/node_modules/@scrypted/types": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.4.tgz",
"integrity": "sha512-k/YMx8lIWOkePgXfKW9POr12mb+erFU2JKxO7TW92GyW8ojUWw9VOc0PK6O9bybi0vhsEnvMFkO6pO6bAonsVA=="
},
"node_modules/@scrypted/types": {
"version": "0.2.99",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.2.99.tgz",
@@ -206,14 +210,6 @@
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/axios": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
"dependencies": {
"follow-redirects": "^1.14.7"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -318,9 +314,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"funding": [
{
"type": "individual",

View File

@@ -1,6 +1,6 @@
{
"name": "scrypted",
"version": "1.3.5",
"version": "1.3.6",
"description": "",
"main": "./dist/packages/cli/src/main.js",
"bin": {
@@ -16,19 +16,18 @@
"author": "",
"license": "ISC",
"dependencies": {
"@scrypted/client": "^1.3.2",
"@scrypted/client": "^1.3.3",
"@scrypted/types": "^0.2.99",
"axios": "^0.25.0",
"engine.io-client": "^6.5.3",
"readline-sync": "^1.4.10",
"semver": "^7.5.4",
"tslib": "^2.6.2"
},
"devDependencies": {
"rimraf": "^5.0.5",
"@types/node": "^20.9.4",
"@types/readline-sync": "^1.4.8",
"@types/semver": "^7.5.6",
"rimraf": "^5.0.5",
"ts-node": "^10.9.1",
"typescript": "^5.3.2"
}

View File

@@ -2,13 +2,13 @@
import { connectScryptedClient } from '@scrypted/client';
import { FFmpegInput, ScryptedMimeTypes } from '@scrypted/types';
import axios, { AxiosRequestConfig } from 'axios';
import child_process from 'child_process';
import fs from 'fs';
import https from 'https';
import path from 'path';
import readline from 'readline-sync';
import semver from 'semver';
import { authHttpFetch } from '../../../common/src/http-auth-fetch';
import { installServe, serveMain } from './service';
import { connectShell } from './shell';
@@ -54,15 +54,16 @@ async function doLogin(host: string) {
});
const url = `https://${host}/login`;
const response = await axios(Object.assign({
const response = await authHttpFetch({
method: 'GET',
auth: {
credential: {
username,
password,
},
url,
httpsAgent,
}, axiosConfig));
rejectUnauthorized: false,
responseType: 'json',
});
fs.mkdirSync(scryptedHome, {
recursive: true,
@@ -78,7 +79,7 @@ async function doLogin(host: string) {
login = {};
login = login || {};
login[host] = response.data;
login[host] = response.body;
fs.writeFileSync(loginPath, JSON.stringify(login));
return login;
}
@@ -102,12 +103,6 @@ async function getOrDoLogin(host: string): Promise<{
return login[host];
}
const axiosConfig: AxiosRequestConfig = {
httpsAgent: new https.Agent({
rejectUnauthorized: false
})
}
async function runCommand() {
const [idOrName, optionalHost] = process.argv[3].split('@');
const host = toIpAndPort(optionalHost || '127.0.0.1');
@@ -119,9 +114,6 @@ async function runCommand() {
pluginId: '@scrypted/core',
username: login.username,
password: login.token,
axiosConfig: {
httpsAgent,
}
});
const device: any = sdk.systemManager.getDeviceById(idOrName) || sdk.systemManager.getDeviceByName(idOrName);
@@ -211,16 +203,18 @@ async function main() {
const login = await getOrDoLogin(ip);
const url = `https://${ip}/web/component/script/install/${pkg}`;
const response = await axios(Object.assign({
const response = await authHttpFetch({
method: 'POST',
auth: {
credential: {
username: login.username,
password: login.token,
},
url,
}, axiosConfig));
rejectUnauthorized: false,
responseType: 'json',
});
console.log('install successful. id:', response.data.id);
console.log('install successful. id:', response.body.id);
}
else if (process.argv[2] === 'shell') {
console.log = () => { };
@@ -232,9 +226,6 @@ async function main() {
pluginId: '@scrypted/core',
username: login.username,
password: login.token,
axiosConfig: {
httpsAgent,
}
});
const separator = process.argv.indexOf("--");

View File

@@ -9,3 +9,4 @@ scrypted.db.bak
.exit
.update
.venv
.vscode/launch.json

View File

@@ -1,27 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ts-node",
"type": "node",
"request": "launch",
"args": [
"${relativeFile}"
],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"env": {
"SCRYPTED_USERNAME": "koush",
"SCRYPTED_PASSWORD": "k9copUSA",
},
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

View File

@@ -1,21 +1,12 @@
import { Camera, VideoCamera, VideoFrameGenerator } from '@scrypted/types';
import { connectScryptedClient } from '../dist/packages/client/src';
import https from 'https';
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
})
async function example() {
const sdk = await connectScryptedClient({
baseUrl: 'https://localhost:10443',
pluginId: "@scrypted/core",
username: process.env.SCRYPTED_USERNAME || 'admin',
password: process.env.SCRYPTED_PASSWORD || 'swordfish',
axiosConfig: {
httpsAgent,
}
});
console.log('server version', sdk.serverVersion);

View File

@@ -1,25 +1,16 @@
import { ObjectDetector, ObjectsDetected, ScryptedInterface } from '@scrypted/types';
import { connectScryptedClient } from '../dist/packages/client/src';
import https from 'https';
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
})
async function example() {
const sdk = await connectScryptedClient({
baseUrl: 'https://localhost:10443',
pluginId: "@scrypted/core",
username: process.env.SCRYPTED_USERNAME || 'admin',
password: process.env.SCRYPTED_PASSWORD || 'swordfish',
axiosConfig: {
httpsAgent,
}
});
console.log('server version', sdk.serverVersion);
const backyard = sdk.systemManager.getDeviceByName<ObjectDetector>("Hikvision Test");
const backyard = sdk.systemManager.getDeviceByName<ObjectDetector>("IP CAMERA");
if (!backyard)
throw new Error('Device not found');

View File

@@ -1,21 +1,12 @@
import { connectScryptedClient } from '../dist/packages/client/src';
import { OnOff } from '@scrypted/types';
import https from 'https';
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
})
async function example() {
const sdk = await connectScryptedClient({
baseUrl: 'https://localhost:10443',
pluginId: "@scrypted/core",
username: process.env.SCRYPTED_USERNAME || 'admin',
password: process.env.SCRYPTED_PASSWORD || 'swordfish',
axiosConfig: {
httpsAgent,
}
});
console.log('server version', sdk.serverVersion);

View File

@@ -1,23 +1,36 @@
{
"name": "@scrypted/client",
"version": "1.3.1",
"version": "1.3.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/client",
"version": "1.3.1",
"version": "1.3.4",
"license": "ISC",
"dependencies": {
"@scrypted/types": "^0.2.99",
"axios": "^0.25.0",
"@scrypted/types": "^0.3.4",
"engine.io-client": "^6.5.3",
"follow-redirects": "^1.15.4",
"rimraf": "^5.0.5"
},
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^20.9.4",
"typescript": "^5.3.2"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@isaacs/cliui": {
@@ -36,6 +49,31 @@
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -46,15 +84,39 @@
}
},
"node_modules/@scrypted/types": {
"version": "0.2.99",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.2.99.tgz",
"integrity": "sha512-2J1FH7tpAW5X3rgA70gJ+z0HFM90c/tBA+JXdP1vI1d/0yVmh9TSxnHoCuADN4R2NQXHmoZ6Nbds9kKAQ/25XQ=="
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.4.tgz",
"integrity": "sha512-k/YMx8lIWOkePgXfKW9POr12mb+erFU2JKxO7TW92GyW8ojUWw9VOc0PK6O9bybi0vhsEnvMFkO6pO6bAonsVA=="
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"node_modules/@types/ip": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.3.tgz",
@@ -65,14 +127,35 @@
}
},
"node_modules/@types/node": {
"version": "20.9.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
"integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
@@ -95,13 +178,11 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/axios": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
"dependencies": {
"follow-redirects": "^1.14.7"
}
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
@@ -132,6 +213,12 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -161,6 +248,15 @@
}
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -192,9 +288,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"funding": [
{
"type": "individual",
@@ -284,6 +380,12 @@
"node": "14 || >=16.14"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
@@ -469,10 +571,53 @@
"node": ">=8"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/typescript": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -488,6 +633,12 @@
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -613,6 +764,15 @@
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/client",
"version": "1.3.2",
"version": "1.3.4",
"description": "",
"main": "dist/packages/client/src/index.js",
"scripts": {
@@ -13,13 +13,14 @@
"license": "ISC",
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^20.9.4",
"typescript": "^5.3.2"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
},
"dependencies": {
"@scrypted/types": "^0.2.99",
"axios": "^0.25.0",
"@scrypted/types": "^0.3.4",
"engine.io-client": "^6.5.3",
"follow-redirects": "^1.15.4",
"rimraf": "^5.0.5"
}
}

View File

@@ -1,20 +1,34 @@
import { MediaObjectOptions, RTCConnectionManagement, RTCSignalingSession, ScryptedStatic } from "@scrypted/types";
import axios, { AxiosRequestConfig, AxiosRequestHeaders } from 'axios';
import * as eio from 'engine.io-client';
import { SocketOptions } from 'engine.io-client';
import { Deferred } from "../../../common/src/deferred";
import { timeoutPromise } from "../../../common/src/promise-utils";
import { BrowserSignalingSession, waitPeerConnectionIceConnected, waitPeerIceConnectionClosed } from "../../../common/src/rtc-signaling";
import { DataChannelDebouncer } from "../../../plugins/webrtc/src/datachannel-debouncer";
import type { ClusterObject, ConnectRPCObject } from '../../../server/src/cluster/connect-rpc-object';
import type { IOSocket } from '../../../server/src/io';
import { MediaObject } from '../../../server/src/plugin/mediaobject';
import { attachPluginRemote } from '../../../server/src/plugin/plugin-remote';
import type { ClusterObject, ConnectRPCObject } from '../../../server/src/cluster/connect-rpc-object';
import { RpcPeer } from '../../../server/src/rpc';
import { createRpcDuplexSerializer, createRpcSerializer } from '../../../server/src/rpc-serializer';
import packageJson from '../package.json';
import { isIPAddress } from "./ip";
import { domFetch } from "../../../server/src/fetch";
import { httpFetch } from '../../../server/src/fetch/http-fetch';
let fetcher: typeof httpFetch | typeof domFetch;
try {
if (process.arch === 'browser' as any)
throw new Error();
require('net');
require('events');
fetcher = httpFetch;
}
catch (e) {
fetcher = domFetch;
}
const sourcePeerId = RpcPeer.generateId();
type IOClientSocket = eio.Socket & IOSocket;
@@ -59,7 +73,6 @@ export interface ScryptedConnectionOptions {
local?: boolean;
webrtc?: boolean;
baseUrl?: string;
axiosConfig?: AxiosRequestConfig;
previousLoginResult?: ScryptedClientLoginResult;
}
@@ -90,10 +103,13 @@ function isRunningStandalone() {
export async function logoutScryptedClient(baseUrl?: string) {
const url = combineBaseUrl(baseUrl, 'logout');
const response = await axios(url, {
const response = await fetcher({
url,
withCredentials: true,
responseType: 'json',
rejectUnauthorized: false,
});
return response.data;
return response.body;
}
export function getCurrentBaseUrl() {
@@ -122,38 +138,43 @@ export async function loginScryptedClient(options: ScryptedLoginOptions) {
maxAge = 365 * 24 * 60 * 60 * 1000;
const url = combineBaseUrl(baseUrl, 'login');
const response = await axios.post(url, {
username,
password,
change_password,
maxAge,
}, {
const response = await fetcher({
url,
body: {
username,
password,
change_password,
maxAge,
},
rejectUnauthorized: false,
withCredentials: true,
...options.axiosConfig,
responseType: 'json',
});
if (response.status !== 200)
throw new Error('status ' + response.status);
if (response.statusCode !== 200)
throw new Error('status ' + response.statusCode);
const { body } = response;
return {
error: response.data.error as string,
authorization: response.data.authorization as string,
queryToken: response.data.queryToken as any,
token: response.data.token as string,
addresses: response.data.addresses as string[],
externalAddresses: response.data.externalAddresses as string[],
error: body.error as string,
authorization: body.authorization as string,
queryToken: body.queryToken as any,
token: body.token as string,
addresses: body.addresses as string[],
externalAddresses: body.externalAddresses as string[],
// the cloud plugin will include this header.
// should maybe move this into the cloud server itself.
scryptedCloud: response.headers['x-scrypted-cloud'] === 'true',
directAddress: response.headers['x-scrypted-direct-address'],
cloudAddress: response.headers['x-scrypted-cloud-address'],
scryptedCloud: response.headers.get('x-scrypted-cloud') === 'true',
directAddress: response.headers.get('x-scrypted-direct-address'),
cloudAddress: response.headers.get('x-scrypted-cloud-address'),
};
}
export async function checkScryptedClientLogin(options?: ScryptedConnectionOptions) {
let { baseUrl } = options || {};
let url = combineBaseUrl(baseUrl, 'login');
const headers: AxiosRequestHeaders = {};
const headers = new Headers();
if (options?.previousLoginResult?.queryToken) {
// headers.Authorization = options?.previousLoginResult?.authorization;
// const search = new URLSearchParams(options.previousLoginResult.queryToken);
@@ -161,32 +182,36 @@ export async function checkScryptedClientLogin(options?: ScryptedConnectionOptio
const token = options?.previousLoginResult.username + ":" + options.previousLoginResult.token;
const hash = Buffer.from(token).toString('base64');
headers.Authorization = `Basic ${hash}`;
headers.set('Authorization', `Basic ${hash}`);
}
const response = await axios.get(url, {
const response = await fetcher({
url,
withCredentials: true,
headers,
...options?.axiosConfig,
rejectUnauthorized: false,
responseType: 'json',
});
const { body } = response;
return {
baseUrl,
hostname: response.data.hostname as string,
redirect: response.data.redirect as string,
username: response.data.username as string,
expiration: response.data.expiration as number,
hasLogin: !!response.data.hasLogin,
error: response.data.error as string,
authorization: response.data.authorization as string,
queryToken: response.data.queryToken as any,
token: response.data.token as string,
addresses: response.data.addresses as string[],
externalAddresses: response.data.externalAddresses as string[],
hostname: body.hostname as string,
redirect: body.redirect as string,
username: body.username as string,
expiration: body.expiration as number,
hasLogin: !!body.hasLogin,
error: body.error as string,
authorization: body.authorization as string,
queryToken: body.queryToken as any,
token: body.token as string,
addresses: body.addresses as string[],
externalAddresses: body.externalAddresses as string[],
// the cloud plugin will include this header.
// should maybe move this into the cloud server itself.
scryptedCloud: response.headers['x-scrypted-cloud'] === 'true',
directAddress: response.headers['x-scrypted-direct-address'],
cloudAddress: response.headers['x-scrypted-cloud-address'],
scryptedCloud: response.headers.get('x-scrypted-cloud') === 'true',
directAddress: response.headers.get('x-scrypted-direct-address'),
cloudAddress: response.headers.get('x-scrypted-cloud-address'),
};
}
@@ -786,7 +811,7 @@ export async function connectScryptedClient(options: ScryptedClientOptions): Pro
return value;
}
const { port, proxyId } = clusterObject;
const { port, proxyId } = clusterObject;
// check if object is already connected
const resolved = await resolveObject(proxyId, port);

View File

@@ -1,22 +1,19 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.131",
"version": "0.0.132",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/amcrest",
"version": "0.0.131",
"version": "0.0.132",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/multiparty": "^0.0.33",
"multiparty": "^4.2.3"
"@scrypted/sdk": "file:../../sdk"
},
"devDependencies": {
"@types/node": "^18.16.18"
"@types/node": "^20.10.8"
}
},
"../../common": {
@@ -28,10 +25,11 @@
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
@@ -71,15 +69,6 @@
"typedoc": "^0.23.21"
}
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -88,150 +77,20 @@
"resolved": "../../sdk",
"link": true
},
"node_modules/@types/multiparty": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/@types/multiparty/-/multiparty-0.0.33.tgz",
"integrity": "sha512-Il6cJUpSqgojT7NxbVJUvXkCblm50/yEJYtblISDsNIeNYf4yMAhdizzidUk6h8pJ8yhwK/3Fkb+3Dwcgtwl8w==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.16.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.18.tgz",
"integrity": "sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw=="
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.0"
"undici-types": "~5.26.4"
}
},
"node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/multiparty": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz",
"integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==",
"dependencies": {
"http-errors": "~1.8.1",
"safe-buffer": "5.2.1",
"uid-safe": "2.1.5"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.131",
"version": "0.0.132",
"description": "Amcrest Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",
@@ -35,13 +35,10 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/multiparty": "^0.0.33",
"multiparty": "^4.2.3"
"@scrypted/sdk": "file:../../sdk"
},
"devDependencies": {
"@types/node": "^18.16.18"
"@types/node": "^20.10.8"
}
}

View File

@@ -1,8 +1,6 @@
import AxiosDigestAuth from '@koush/axios-digest-auth';
import { AuthFetchCredentialState, HttpFetchOptions, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { Readable } from 'stream';
import https from 'https';
import { IncomingMessage } from 'http';
import { amcrestHttpsAgent, getDeviceInfo } from './probe';
import { getDeviceInfo } from './probe';
export enum AmcrestEvent {
MotionStart = "Code=VideoMotion;action=Start",
@@ -22,35 +20,42 @@ export enum AmcrestEvent {
DahuaTalkPulse = "Code=_CallNoAnswer_;action=Pulse",
}
export class AmcrestCameraClient {
digestAuth: AxiosDigestAuth;
credential: AuthFetchCredentialState;
constructor(public ip: string, username: string, password: string, public console?: Console) {
this.digestAuth = new AxiosDigestAuth({
this.credential = {
username,
password,
};
}
async request(urlOrOptions: string | URL | HttpFetchOptions<Readable>, body?: Readable) {
const response = await authHttpFetch({
...typeof urlOrOptions !== 'string' && !(urlOrOptions instanceof URL) ? urlOrOptions : {
url: urlOrOptions,
},
rejectUnauthorized: false,
credential: this.credential,
body,
});
return response;
}
async reboot() {
const response = await this.digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "GET",
responseType: 'text',
const response = await this.request({
url: `http://${this.ip}/cgi-bin/magicBox.cgi?action=reboot`,
responseType: 'text',
});
return response.data as string;
return response.body;
}
async checkTwoWayAudio() {
const response = await this.digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "GET",
responseType: 'text',
const response = await this.request({
url: `http://${this.ip}/cgi-bin/devAudioOutput.cgi?action=getCollect`,
responseType: 'text',
});
return (response.data as string).includes('result=1');
return response.body.includes('result=1');
}
// appAutoStart=true
@@ -61,33 +66,27 @@ export class AmcrestCameraClient {
// updateSerial=IPC-AW46WN-S2
// updateSerialCloudUpgrade=IPC-AW46WN-.....
async getDeviceInfo() {
return getDeviceInfo(this.digestAuth, this.ip);
return getDeviceInfo(this.credential, this.ip);
}
async jpegSnapshot(): Promise<Buffer> {
const response = await this.digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "GET",
responseType: 'arraybuffer',
const response = await this.request({
url: `http://${this.ip}/cgi-bin/snapshot.cgi`,
timeout: 60000,
});
return Buffer.from(response.data);
return response.body;
}
async listenEvents() {
const url = `http://${this.ip}/cgi-bin/eventManager.cgi?action=attach&codes=[All]`;
console.log('preparing event listener', url);
const response = await this.digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "GET",
responseType: 'stream',
const response = await this.request({
url,
responseType: 'readable',
});
const stream = response.data as IncomingMessage;
const stream = response.body;
stream.socket.setKeepAlive(true);
stream.on('data', (buffer: Buffer) => {
@@ -118,12 +117,12 @@ export class AmcrestCameraClient {
async enableContinousRecording(channel: number) {
for (let i = 0; i < 7; i++) {
const url = `http://${this.ip}/cgi-bin/configManager.cgi?action=setConfig&Record[${channel - 1}].TimeSection[${i}][0]=1 00:00:00-23:59:59`;
const response = await this.digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "POST",
const response = await this.request({
url,
});
this.console.log(response.data);
method: 'POST',
responseType: 'text',
},);
this.console.log(response.body);
}
}
}

View File

@@ -6,7 +6,6 @@ import { PassThrough, Readable, Stream } from "stream";
import { OnvifIntercom } from "../../onvif/src/onvif-intercom";
import { RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { AmcrestCameraClient, AmcrestEvent } from "./amcrest-api";
import { amcrestHttpsAgent } from './probe';
const { mediaManager } = sdk;
@@ -94,12 +93,11 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
for (const element of deviceParameters) {
try {
const response = await this.getClient().digestAuth.request({
httpsAgent: amcrestHttpsAgent,
url: `http://${this.getHttpAddress()}/cgi-bin/magicBox.cgi?action=${element.action}`
const response = await this.getClient().request({
url: `http://${this.getHttpAddress()}/cgi-bin/magicBox.cgi?action=${element.action}`,
responseType: 'text',
});
const result = String(response.data).replace(element.replace, "").trim();
const result = String(response.body).replace(element.replace, "").trim();
deviceInfo[element.parameter] = result;
}
catch (e) {
@@ -147,11 +145,11 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
if (![...params.keys()].length)
return;
const response = await this.getClient().digestAuth.request({
httpsAgent: amcrestHttpsAgent,
url: `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=setConfig&${params}`
const response = await this.getClient().request({
url: `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=setConfig&${params}`,
responseType: 'text',
});
this.console.log('reconfigure result', response.data);
this.console.log('reconfigure result', response.body);
}
getClient() {
@@ -309,9 +307,6 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
}
async takeSmartCameraPicture(option?: PictureOptions): Promise<MediaObject> {
return this.createMediaObject(await this.getClient().jpegSnapshot(), 'image/jpeg');
}
@@ -334,7 +329,6 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
return this.storage.getItem('rtspChannel');
}
createRtspMediaStreamOptions(url: string, index: number) {
const ret = super.createRtspMediaStreamOptions(url, index);
ret.tool = 'scrypted';
@@ -348,12 +342,11 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
this.videoStreamOptions = (async () => {
let mas: string;
try {
const response = await client.digestAuth.request({
const response = await client.request({
url: `http://${this.getHttpAddress()}/cgi-bin/magicBox.cgi?action=getProductDefinition&name=MaxExtraStream`,
responseType: 'text',
httpsAgent: amcrestHttpsAgent,
})
mas = response.data.split('=')[1].trim();
mas = response.body.split('=')[1].trim();
this.storage.setItem('maxExtraStreams', mas.toString());
}
catch (e) {
@@ -366,18 +359,16 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
const vsos = [...Array(maxExtraStreams + 1).keys()].map(subtype => this.createRtspMediaStreamOptions(`rtsp://${this.getRtspAddress()}/cam/realmonitor?channel=${channel}&subtype=${subtype}`, subtype));
try {
const capResponse = await client.digestAuth.request({
const capResponse = await client.request({
url: `http://${this.getHttpAddress()}/cgi-bin/encode.cgi?action=getConfigCaps&channel=0`,
responseType: 'text',
httpsAgent: amcrestHttpsAgent,
});
this.console.log(capResponse.data);
const encodeResponse = await client.digestAuth.request({
this.console.log(capResponse.body);
const encodeResponse = await client.request({
url: `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=getConfig&name=Encode`,
responseType: 'text',
httpsAgent: amcrestHttpsAgent,
});
this.console.log(encodeResponse.data);
this.console.log(encodeResponse.body);
for (let i = 0; i < vsos.length; i++) {
const vso = vsos[i];
@@ -392,9 +383,9 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
encName = `table.Encode[${channel - 1}].ExtraFormat[${i - 1}]`;
}
const videoCodec = findValue(encodeResponse.data, encName, 'Video.Compression')
const videoCodec = findValue(encodeResponse.body, encName, 'Video.Compression')
?.replace('.', '')?.toLowerCase()?.trim();
let audioCodec = findValue(encodeResponse.data, encName, 'Audio.Compression')
let audioCodec = findValue(encodeResponse.body, encName, 'Audio.Compression')
?.replace('.', '')?.toLowerCase()?.trim();
if (audioCodec?.includes('aac'))
audioCodec = 'aac';
@@ -409,18 +400,18 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
vso.audio.codec = audioCodec;
vso.video.codec = videoCodec;
const width = findValue(encodeResponse.data, encName, 'Video.Width');
const height = findValue(encodeResponse.data, encName, 'Video.Height');
const width = findValue(encodeResponse.body, encName, 'Video.Width');
const height = findValue(encodeResponse.body, encName, 'Video.Height');
if (width && height) {
vso.video.width = parseInt(width);
vso.video.height = parseInt(height);
}
const bitrateOptions = findValue(capResponse.data, capName, 'Video.BitRateOptions');
const bitrateOptions = findValue(capResponse.body, capName, 'Video.BitRateOptions');
if (!bitrateOptions)
continue;
const encodeOptions = findValue(encodeResponse.data, encName, 'Video.BitRate');
const encodeOptions = findValue(encodeResponse.body, encName, 'Video.BitRate');
if (!encodeOptions)
continue;
@@ -538,16 +529,15 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
// seems the dahua doorbells preferred 1024 chunks. should investigate adts
// parsing and sending multipart chunks instead.
const passthrough = new PassThrough();
this.getClient().digestAuth.request({
method: 'POST',
this.getClient().request({
url,
method: 'POST',
headers: {
'Content-Type': 'Audio/AAC',
'Content-Length': '9999999'
},
httpsAgent: amcrestHttpsAgent,
data: passthrough,
});
responseType: 'readable',
}, passthrough);
try {
while (true) {
@@ -598,7 +588,7 @@ class AmcrestProvider extends RtspProvider {
const username = settings.username?.toString();
const password = settings.password?.toString();
const skipValidate = settings.skipValidate === 'true';
const skipValidate = settings.skipValidate?.toString() === 'true';
let twoWayAudio: string;
if (!skipValidate) {
const api = new AmcrestCameraClient(httpAddress, username, password, this.console);

View File

@@ -1,8 +1,4 @@
import https from 'https';
export const amcrestHttpsAgent = new https.Agent({
rejectUnauthorized: false,
});
import { AuthFetchCredentialState, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
// appAutoStart=true
// deviceType=IP4M-1041B
@@ -11,17 +7,16 @@ export const amcrestHttpsAgent = new https.Agent({
// serialNumber=12345
// updateSerial=IPC-AW46WN-S2
import AxiosDigestAuth from "@koush/axios-digest-auth";
// updateSerialCloudUpgrade=IPC-AW46WN-.....
export async function getDeviceInfo(digestAuth: AxiosDigestAuth, address: string) {
const response = await digestAuth.request({
httpsAgent: amcrestHttpsAgent,
method: "GET",
responseType: 'text',
export async function getDeviceInfo(credential: AuthFetchCredentialState, address: string) {
const response = await authHttpFetch({
credential,
url: `http://${address}/cgi-bin/magicBox.cgi?action=getSystemInfo`,
rejectUnauthorized: false,
responseType: 'text',
});
const lines = (response.data as string).split('\n');
const lines = response.body.split('\n');
const vals: {
[key: string]: string,
} = {};

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/core",
"version": "0.2.3",
"version": "0.2.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/core",
"version": "0.2.3",
"version": "0.2.5",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",
@@ -88,7 +88,7 @@
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.108",
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/core",
"version": "0.2.3",
"version": "0.2.5",
"description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.",
"author": "Scrypted",
"license": "Apache-2.0",

View File

@@ -47,37 +47,45 @@ export class Scheduler {
const day = future.getDay();
if (!days[day])
continue;
source.log.i(`event will fire at ${future.toLocaleString()}`);
return future;
}
source.log.w('event will never fire');
}
const when = reschedule();
if (!when) {
return {
removeListener() {
}
}
}
const delay = when.getTime() - Date.now();
source.log.i(`event will fire in ${Math.round(delay / 60 / 1000)} minutes.`);
let timeout = setTimeout(() => {
reschedule();
let timeout: NodeJS.Timeout = null;
let when: Date = null;
function timerCb() {
timeout = null;
const prevWhen = when;
setupTimer();
callback(ret, {
eventId: undefined,
eventInterface: 'Scheduler',
eventTime: Date.now(),
}, when)
}, delay);
}, prevWhen)
}
function setupTimer() {
when = reschedule();
if (when) {
const delay = when.getTime() - Date.now();
source.log.i(`event will fire in ${Math.round(delay / 60 / 1000)} minutes.`);
timeout = setTimeout(timerCb, delay);
}
}
setupTimer();
return {
removeListener() {
clearTimeout(timeout);
if (timeout) {
clearTimeout(timeout);
}
timeout = null;
when = null;
}
}
}

View File

@@ -111,22 +111,22 @@
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"ts-node": "^10.9.2"
}
},
"../../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.108",
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -158,7 +158,7 @@
},
"../../../sdk/types": {
"name": "@scrypted/types",
"version": "0.2.99",
"version": "0.3.4",
"license": "ISC",
"devDependencies": {
"@types/rimraf": "^3.0.2",

View File

@@ -173,7 +173,7 @@ export default {
const version = await info.getVersion();
const scryptedEnv = await info.getScryptedEnv();
this.currentVersion = version;
const { updateAvailable } = await checkServerUpdate(version, scryptedEnv.SCRYPTED_INSTALL_ENVIRONMENT);
const { updateAvailable } = await checkServerUpdate(this.$scrypted.mediaManager, version, scryptedEnv.SCRYPTED_INSTALL_ENVIRONMENT);
this.updateAvailable = updateAvailable;
}

View File

@@ -141,7 +141,7 @@ export default {
// old scrypted servers dont support this call, or it may be unimplemented
// in which case fall back and determine what the install type is.
const scryptedEnv = await info.getScryptedEnv();
const { updateAvailable } = await checkServerUpdate(version, scryptedEnv.SCRYPTED_INSTALL_ENVIRONMENT);
const { updateAvailable } = await checkServerUpdate(this.$scrypted.mediaManager, version, scryptedEnv.SCRYPTED_INSTALL_ENVIRONMENT);
this.updateAvailable = updateAvailable;
}
},

View File

@@ -1,4 +1,4 @@
import { DeviceCreator, Scriptable, ScryptedInterface, ScryptedStatic, SystemManager } from '@scrypted/types';
import { DeviceCreator, MediaObject, Scriptable, ScryptedInterface, ScryptedStatic, SystemManager, MediaManager } from '@scrypted/types';
import axios, { AxiosResponse } from 'axios';
import semver from 'semver';
import { getAllDevices } from '../../common/mixin';
@@ -66,7 +66,7 @@ export async function checkUpdate(npmPackage: string, npmPackageVersion: string)
};
}
export async function checkServerUpdate(version: string, installEnvironment: string): Promise<PluginUpdateCheck> {
export async function checkServerUpdate(mediaManager: MediaManager, version: string, installEnvironment: string): Promise<PluginUpdateCheck> {
const { updateAvailable, updatePublished, versions } = await checkUpdate(
"@scrypted/server",
version
@@ -78,8 +78,9 @@ export async function checkServerUpdate(version: string, installEnvironment: str
// check if there is a new docker image available, using 'latest' tag
// this is done so newer server versions in npm are not immediately
// displayed until a docker image has been published
let response: AxiosResponse<any> = await axios.get("https://corsproxy.io?https://hub.docker.com/v2/namespaces/koush/repositories/scrypted/tags/latest");
const { data } = response;
// due to CORS restrictions, we query this through scrypted server
const mo: MediaObject = await mediaManager.createMediaObjectFromUrl('https://hub.docker.com/v2/namespaces/koush/repositories/scrypted/tags/latest');
const data: any = await mediaManager.convertMediaObjectToJSON(mo, 'application/json');
const imagePublished = new Date(data.last_updated);
console.log(`Latest docker image published ${imagePublished}`);

View File

@@ -8,7 +8,6 @@
"name": "@scrypted/doorbird",
"version": "0.0.2",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"doorbird": "^2.1.2"
},
"devDependencies": {
@@ -26,23 +25,24 @@
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"http-auth-utils": "^5.0.1",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.103",
"version": "0.3.4",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -72,23 +72,6 @@
"typedoc": "^0.23.21"
}
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.5.tgz",
"integrity": "sha512-EZMM0gMJ3hMUD4EuUqSwP6UGt5Vmw2TZtY7Ypec55AnxkExSXM0ySgPtqkAcnL43g1R27yAg/dQL7dRTLMqO3Q==",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@koush/axios-digest-auth/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -108,17 +91,12 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz",
"integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==",
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"dependencies": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -199,9 +177,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"funding": [
{
"type": "individual",

View File

@@ -33,7 +33,6 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"doorbird": "^2.1.2"
},
"devDependencies": {

View File

@@ -5,8 +5,8 @@ import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/comm
import net from 'net';
import { randomBytes } from 'crypto';
import { PassThrough, Readable } from "stream";
import AxiosDigestAuth from '@koush/axios-digest-auth';
import { readLength } from "@scrypted/common/src/read-stream";
import { authHttpFetch } from "@scrypted/common/src/http-auth-fetch";
import { ApiRingEvent, ApiMotionEvent, DoorbirdAPI } from "./doorbird-api";
const { deviceManager, mediaManager } = sdk;
@@ -27,7 +27,7 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.binaryState = false;
this.doorbellAudioActive = false;
this.updateDeviceInfo();
this.updateDeviceInfo();
}
getDoorbirdApi() {
@@ -49,8 +49,8 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.console?.log("Time:", event.timestamp);
this.triggerMotionSensor();
});
this.getDoorbirdApi()?.startEventSocket();
}
this.getDoorbirdApi()?.startEventSocket();
}
return this.doorbirdApi;
}
@@ -157,7 +157,7 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.stopAudioTransmitter();
this.stopAudioReceiver();
}
async startAudioTransmitter(media: MediaObject): Promise<void> {
const ffmpegInput: FFmpegInput = JSON.parse((await mediaManager.convertMediaObjectToBuffer(media, ScryptedMimeTypes.FFmpegInput)).toString());
@@ -194,13 +194,13 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.console.log('Doorbird: audio transmitter started.');
const passthrough = new PassThrough();
const digestAuth = new AxiosDigestAuth({
username,
password
});
digestAuth.request({
authHttpFetch({
method: 'POST',
url: audioTxUrl,
credential: {
username,
password,
},
headers: {
'Content-Type': 'audio/basic',
'Content-Length': '9999999'
@@ -293,7 +293,8 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
// this is a hint to let homekit, et al, know that it's OPUS audio and does not need transcoding.
codec: 'pcm_mulaw',
}
}]; }
}];
}
async getVideoStream(options?: ResponseMediaStreamOptions): Promise<MediaObject> {
@@ -327,7 +328,7 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
if (this.audioSilenceProcess)
return;
this.console.log('Doorbird: starting audio silence generator...')
this.console.log('Doorbird: starting audio silence generator...')
const ffmpegPath = await mediaManager.getFFmpegPath();
const ffmpegArgs = [
@@ -552,10 +553,10 @@ export class DoorbirdCamProvider extends ScryptedDeviceBase implements DevicePro
}
async releaseDevice(id: string, nativeId: string): Promise<void> {
if( this.devices.delete( nativeId ) ) {
this.console.log("Doorbird: Removed device from list: " + id + " / " + nativeId )
if (this.devices.delete(nativeId)) {
this.console.log("Doorbird: Removed device from list: " + id + " / " + nativeId)
}
}
}
createCamera(nativeId: string): DoorbirdCamera {
return new DoorbirdCamera(nativeId, this);

View File

@@ -9,40 +9,37 @@
"version": "0.0.22",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"url-parse": "^1.4.7"
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^16.9.6"
"@types/node": "^20.10.8"
}
},
"../../common": {
"name": "@scrypted/common",
"version": "1.0.1",
"dev": true,
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.103",
"dev": true,
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -75,15 +72,6 @@
"../sdk": {
"extraneous": true
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.5.tgz",
"integrity": "sha512-EZMM0gMJ3hMUD4EuUqSwP6UGt5Vmw2TZtY7Ypec55AnxkExSXM0ySgPtqkAcnL43g1R27yAg/dQL7dRTLMqO3Q==",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -93,82 +81,32 @@
"link": true
},
"node_modules/@types/node": {
"version": "16.9.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz",
"integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==",
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/querystringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
}
},
"dependencies": {
"@koush/axios-digest-auth": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.5.tgz",
"integrity": "sha512-EZMM0gMJ3hMUD4EuUqSwP6UGt5Vmw2TZtY7Ypec55AnxkExSXM0ySgPtqkAcnL43g1R27yAg/dQL7dRTLMqO3Q==",
"requires": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"@scrypted/common": {
"version": "file:../../common",
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"@types/node": "^20.10.8",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -178,7 +116,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -196,47 +134,19 @@
}
},
"@types/node": {
"version": "16.9.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz",
"integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==",
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"requires": {
"undici-types": "~5.26.4"
}
},
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"requires": {
"follow-redirects": "^1.14.0"
}
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"querystringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"requires": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
}
}
}

View File

@@ -36,12 +36,10 @@
]
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^16.9.6"
"@types/node": "^20.10.8"
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"url-parse": "^1.4.7"
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk"
}
}

View File

@@ -1,44 +1,21 @@
import AxiosDigestAuth from '@koush/axios-digest-auth';
import sdk, { Camera, DeviceCreator, DeviceCreatorSettings, DeviceProvider, MediaObject, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedNativeId, Setting, Settings, SettingValue, VideoCamera } from "@scrypted/sdk";
import { randomBytes } from "crypto";
import https from 'https';
const { deviceManager, mediaManager } = sdk;
const httpsAgent = new https.Agent({
rejectUnauthorized: false
});
const { deviceManager } = sdk;
export interface UrlMediaStreamOptions extends ResponseMediaStreamOptions {
url: string;
}
export abstract class CameraBase<T extends ResponseMediaStreamOptions> extends ScryptedDeviceBase implements Camera, VideoCamera, Settings {
snapshotAuth: AxiosDigestAuth;
constructor(nativeId: string, public provider: CameraProviderBase<T>) {
super(nativeId);
}
protected async takePictureUrl(snapshotUrl: string) {
if (!this.snapshotAuth) {
this.snapshotAuth = new AxiosDigestAuth({
username: this.getUsername(),
password: this.getPassword(),
});
}
const response = await this.snapshotAuth.request({
httpsAgent,
method: "GET",
responseType: 'arraybuffer',
url: snapshotUrl,
});
return mediaManager.createMediaObject(Buffer.from(response.data), response.headers['Content-Type'] || 'image/jpeg');
takePicture(option?: PictureOptions): Promise<MediaObject> {
throw new Error("The RTSP Camera does not provide snapshots. Install the Snapshot Plugin if snapshots are available via an URL.");
}
abstract takePicture(option?: PictureOptions): Promise<MediaObject>;
async getPictureOptions(): Promise<PictureOptions[]> {
return;
}
@@ -140,8 +117,6 @@ export abstract class CameraBase<T extends ResponseMediaStreamOptions> extends S
this.storage.setItem(key, value.toString());
}
this.snapshotAuth = undefined;
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
}

View File

@@ -1,4 +1,4 @@
import sdk, { FFmpegInput, MediaObject, PictureOptions, Setting, SettingValue } from "@scrypted/sdk";
import sdk, { FFmpegInput, MediaObject, Setting, SettingValue } from "@scrypted/sdk";
import { StorageSettings } from "@scrypted/sdk/storage-settings";
import { CameraBase, CameraProviderBase, UrlMediaStreamOptions } from "./common";
@@ -15,10 +15,6 @@ function parseDoubleQuotedArguments(input: string) {
}
class FFmpegCamera extends CameraBase<UrlMediaStreamOptions> {
takePictureThrottled(option?: PictureOptions): Promise<MediaObject> {
throw new Error("The RTSP Camera does not provide snapshots. Install the Snapshot Plugin if snapshots are available via an URL.");
}
storageSettings = new StorageSettings(this, {
ffmpegInputs: {
title: 'FFmpeg Input Stream Arguments',

File diff suppressed because it is too large Load Diff

View File

@@ -32,12 +32,10 @@
]
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^16.9.6"
"@types/node": "^20.10.8"
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"url-parse": "^1.4.7"
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk"
}
}

View File

@@ -1,295 +0,0 @@
import sdk, { ScryptedDeviceBase, DeviceProvider, Settings, Setting, ScryptedDeviceType, VideoCamera, MediaObject, MediaStreamOptions, ScryptedInterface, FFmpegInput, Camera, PictureOptions, SettingValue, DeviceCreator, DeviceCreatorSettings, ResponseMediaStreamOptions } from "@scrypted/sdk";
import { recommendRebroadcast } from "./recommend";
import AxiosDigestAuth from '@koush/axios-digest-auth';
import https from 'https';
import { randomBytes } from "crypto";
const { log, deviceManager, mediaManager } = sdk;
const httpsAgent = new https.Agent({
rejectUnauthorized: false
});
export interface UrlMediaStreamOptions extends MediaStreamOptions {
url: string;
}
export abstract class CameraBase<T extends ResponseMediaStreamOptions> extends ScryptedDeviceBase implements Camera, VideoCamera, Settings {
snapshotAuth: AxiosDigestAuth;
pendingPicture: Promise<MediaObject>;
constructor(nativeId: string, public provider: CameraProviderBase<T>) {
super(nativeId);
}
getSnapshotUrl() {
return this.storage.getItem('snapshotUrl');
}
async takePicture(option?: PictureOptions): Promise<MediaObject> {
if (!this.pendingPicture) {
this.pendingPicture = this.takePictureThrottled(option);
this.pendingPicture.finally(() => this.pendingPicture = undefined);
}
return this.pendingPicture;
}
async takePictureThrottled(option?: PictureOptions): Promise<MediaObject> {
const snapshotUrl = this.getSnapshotUrl();
if (!snapshotUrl) {
throw new Error('Camera has no snapshot URL');
}
if (!this.snapshotAuth) {
this.snapshotAuth = new AxiosDigestAuth({
username: this.getUsername(),
password: this.getPassword(),
});
}
const response = await this.snapshotAuth.request({
httpsAgent,
method: "GET",
responseType: 'arraybuffer',
url: snapshotUrl,
});
return mediaManager.createMediaObject(Buffer.from(response.data), response.headers['Content-Type'] || 'image/jpeg');
}
async getPictureOptions(): Promise<PictureOptions[]> {
return;
}
getDefaultOrderedVideoStreamOptions(vsos: T[]) {
if (!vsos || !vsos.length)
return vsos;
const defaultStream = this.getDefaultStream(vsos);
if (!defaultStream)
return vsos;
vsos = vsos.filter(vso => vso.id !== defaultStream?.id);
vsos.unshift(defaultStream);
return vsos;
}
async getVideoStreamOptions(): Promise<T[]> {
let vsos = this.getRawVideoStreamOptions();
return this.getDefaultOrderedVideoStreamOptions(vsos);
}
abstract getRawVideoStreamOptions(): T[];
isAudioDisabled() {
return this.storage.getItem('noAudio') === 'true';
}
async getVideoStream(options?: T): Promise<MediaObject> {
const vsos = await this.getVideoStreamOptions();
const vso = vsos?.find(s => s.id === options?.id) || this.getDefaultStream(vsos);
return this.createVideoStream(vso);
}
abstract createVideoStream(options?: T): Promise<MediaObject>;
async getSnapshotUrlSettings(): Promise<Setting[]> {
return [
{
key: 'snapshotUrl',
title: 'Snapshot URL',
placeholder: 'http://192.168.1.100[:80]/snapshot.jpg',
value: this.getSnapshotUrl(),
description: 'Optional: The snapshot URL that will returns the current JPEG image.'
},
];
}
async getUrlSettings(): Promise<Setting[]> {
return [
...await this.getSnapshotUrlSettings(),
];
}
getUsername() {
return this.storage.getItem('username');
}
getPassword() {
return this.storage.getItem('password');
}
async getOtherSettings(): Promise<Setting[]> {
return [];
}
getDefaultStream(vsos: T[]) {
let defaultStreamIndex = vsos?.findIndex(vso => vso.id === this.storage.getItem('defaultStream'));
if (defaultStreamIndex === -1)
defaultStreamIndex = 0;
defaultStreamIndex = defaultStreamIndex || 0;
return vsos?.[defaultStreamIndex];
}
async getStreamSettings(): Promise<Setting[]> {
try {
const vsos = await this.getVideoStreamOptions();
if (!vsos?.length || vsos?.length === 1)
return [];
const defaultStream = this.getDefaultStream(vsos);
return [
{
title: 'Default Stream',
key: 'defaultStream',
value: defaultStream?.name,
choices: vsos.map(vso => vso.name),
description: 'The default stream to use when not specified',
}
];
}
catch (e) {
return [];
}
}
getUsernameDescription(): string {
return 'Optional: Username for snapshot http requests.';
}
getPasswordDescription(): string {
return 'Optional: Password for snapshot http requests.';
}
async getSettings(): Promise<Setting[]> {
return [
{
key: 'username',
title: 'Username',
value: this.getUsername(),
description: this.getUsernameDescription(),
},
{
key: 'password',
title: 'Password',
value: this.getPassword(),
type: 'password',
description: this.getPasswordDescription(),
},
...await this.getUrlSettings(),
...await this.getStreamSettings(),
...await this.getOtherSettings(),
{
key: 'noAudio',
title: 'No Audio',
description: 'Enable this setting if the camera does not have audio or to mute audio.',
type: 'boolean',
value: (this.isAudioDisabled()).toString(),
},
];
}
async putSettingBase(key: string, value: SettingValue) {
if (key === 'defaultStream') {
const vsos = await this.getVideoStreamOptions();
const stream = vsos.find(vso => vso.name === value);
this.storage.setItem('defaultStream', stream?.id || '');
}
else {
this.storage.setItem(key, value.toString());
}
this.snapshotAuth = undefined;
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
}
async putSetting(key: string, value: SettingValue) {
this.putSettingBase(key, value);
if (key === 'snapshotUrl') {
let interfaces = this.providedInterfaces;
if (!value)
interfaces = interfaces.filter(iface => iface !== ScryptedInterface.Camera)
else
interfaces.push(ScryptedInterface.Camera);
this.provider.updateDevice(this.nativeId, this.providedName, interfaces);
}
}
}
export abstract class CameraProviderBase<T extends ResponseMediaStreamOptions> extends ScryptedDeviceBase implements DeviceProvider, DeviceCreator {
devices = new Map<string, any>();
constructor(nativeId?: string) {
super(nativeId);
for (const camId of deviceManager.getNativeIds()) {
if (camId)
this.getDevice(camId);
}
recommendRebroadcast();
}
async releaseDevice(id: string, nativeId: string): Promise<void> {
}
async createDevice(settings: DeviceCreatorSettings): Promise<string> {
const nativeId = randomBytes(4).toString('hex');
const name = settings.newCamera.toString();
await this.updateDevice(nativeId, name, this.getInterfaces());
return nativeId;
}
async getCreateDeviceSettings(): Promise<Setting[]> {
return [
{
key: 'newCamera',
title: 'Add Camera',
placeholder: 'Camera name, e.g.: Back Yard Camera, Baby Camera, etc',
}
]
}
getAdditionalInterfaces(): string[] {
return [
];
}
getInterfaces() {
return [ScryptedInterface.VideoCamera,
ScryptedInterface.Settings, ...this.getAdditionalInterfaces()];
}
updateDevice(nativeId: string, name: string, interfaces: string[], type?: ScryptedDeviceType) {
return deviceManager.onDeviceDiscovered({
nativeId,
name,
interfaces,
type: type || ScryptedDeviceType.Camera,
});
}
async putSetting(key: string, value: string | number) {
// generate a random id
const nativeId = randomBytes(4).toString('hex');
const name = value.toString();
this.updateDevice(nativeId, name, this.getInterfaces());
}
abstract createCamera(nativeId: string): CameraBase<T>;
getDevice(nativeId: string) {
let ret = this.devices.get(nativeId);
if (!ret) {
ret = this.createCamera(nativeId);
if (ret)
this.devices.set(nativeId, ret);
}
return ret;
}
}

View File

@@ -1,6 +1,6 @@
import sdk, { FFmpegInput, MediaObject, MediaStreamOptions, ResponseMediaStreamOptions, Setting, SettingValue } from "@scrypted/sdk";
import child_process, { ChildProcess } from "child_process";
import { CameraProviderBase, CameraBase, UrlMediaStreamOptions } from "./common";
import { CameraProviderBase, CameraBase, UrlMediaStreamOptions } from "../../ffmpeg-camera/src/common";
// import {} from "../../../common/src/stream-parser"
// import {} from "../../../common/src/ffmpeg-rebroadcast"
import net from 'net';
@@ -81,7 +81,6 @@ class GStreamerCamera extends CameraBase<ResponseMediaStreamOptions> {
async getUrlSettings(): Promise<Setting[]> {
return [
...await this.getSnapshotUrlSettings(),
...await this.getGStreamerInputSettings(),
];
}

View File

@@ -1,19 +1,17 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.133",
"version": "0.0.134",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.133",
"version": "0.0.134",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/xml2js": "^0.4.11",
"axios": "^1.4.0",
"lodash": "^4.17.21",
"xml2js": "^0.6.0"
},
@@ -28,12 +26,13 @@
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"http-auth-utils": "^5.0.1",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
@@ -43,7 +42,7 @@
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -76,23 +75,6 @@
"../sdk": {
"extraneous": true
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@koush/axios-digest-auth/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -114,106 +96,11 @@
"@types/node": "*"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@@ -241,34 +128,16 @@
}
},
"dependencies": {
"@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"requires": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
},
"dependencies": {
"axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"requires": {
"follow-redirects": "^1.14.0"
}
}
}
},
"@scrypted/common": {
"version": "file:../../common",
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"http-auth-utils": "^3.0.2",
"@types/node": "^20.10.8",
"http-auth-utils": "^5.0.1",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -278,7 +147,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -308,77 +177,11 @@
"@types/node": "*"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.133",
"version": "0.0.134",
"description": "Hikvision Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",
@@ -35,11 +35,9 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/xml2js": "^0.4.11",
"axios": "^1.4.0",
"lodash": "^4.17.21",
"xml2js": "^0.6.0"
},

View File

@@ -1,6 +1,7 @@
import AxiosDigestAuth from '@koush/axios-digest-auth';
import { AuthFetchCredentialState, HttpFetchOptions, HttpFetchResponseType, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { IncomingMessage } from 'http';
import { getDeviceInfo, hikvisionHttpsAgent } from './probe';
import { Readable } from 'stream';
import { getDeviceInfo } from './probe';
export function getChannel(channel: string) {
return channel || '101';
@@ -28,47 +29,57 @@ export interface HikvisionCameraStreamSetup {
}
export class HikvisionCameraAPI {
digestAuth: AxiosDigestAuth;
credential: AuthFetchCredentialState;
deviceModel: Promise<string>;
listenerPromise: Promise<IncomingMessage>;
constructor(public ip: string, username: string, password: string, public console: Console) {
this.digestAuth = new AxiosDigestAuth({
this.credential = {
username,
password,
};
}
async request(urlOrOptions: string | URL | HttpFetchOptions<Readable>, body?: Readable) {
const response = await authHttpFetch({
...typeof urlOrOptions !== 'string' && !(urlOrOptions instanceof URL) ? urlOrOptions : {
url: urlOrOptions,
},
rejectUnauthorized: false,
credential: this.credential,
body,
});
return response;
}
async reboot() {
const response = await this.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
const response = await this.request({
url: `http://${this.ip}/ISAPI/System/reboot`,
method: "PUT",
responseType: 'text',
url: `http://${this.ip}/ISAPI/System/reboot`,
});
return response.data;
return response.body;
}
async getDeviceInfo() {
return getDeviceInfo(this.digestAuth, this.ip);
return getDeviceInfo(this.credential, this.ip);
}
async checkTwoWayAudio() {
const response = await this.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: "GET",
responseType: 'text',
const response = await this.request({
url: `http://${this.ip}/ISAPI/System/TwoWayAudio/channels`,
responseType: 'text',
});
return (response.data as string).includes('Speaker');
return response.body.includes('Speaker');
}
async checkDeviceModel(): Promise<string> {
if (!this.deviceModel) {
this.deviceModel = this.getDeviceInfo().then(d => d.deviceModel).catch(e => {
this.console.error('error checking NVR model', e);
return undefined;
});
}
return await this.deviceModel;
@@ -91,17 +102,15 @@ export class HikvisionCameraAPI {
}
}
const response = await this.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: "GET",
responseType: 'text',
const response = await this.request({
url: `http://${this.ip}/ISAPI/Streaming/channels/${getChannel(channel)}/capabilities`,
responseType: 'text',
});
// this is bad:
// <videoCodecType opt="H.264,H.265">H.265</videoCodecType>
const vcodec = response.data.match(/>(.*?)<\/videoCodecType>/);
const acodec = response.data.match(/>(.*?)<\/audioCompressionType>/);
const vcodec = response.body.match(/>(.*?)<\/videoCodecType>/);
const acodec = response.body.match(/>(.*?)<\/audioCompressionType>/);
return {
videoCodecType: vcodec?.[1],
@@ -112,15 +121,12 @@ export class HikvisionCameraAPI {
async jpegSnapshot(channel: string): Promise<Buffer> {
const url = `http://${this.ip}/ISAPI/Streaming/channels/${getChannel(channel)}/picture?snapShotImageType=JPEG`
const response = await this.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: "GET",
responseType: 'arraybuffer',
const response = await this.request({
url: url,
timeout: 60000,
});
return Buffer.from(response.data);
return response.body;
}
async listenEvents() {
@@ -128,13 +134,11 @@ export class HikvisionCameraAPI {
if (!this.listenerPromise) {
const url = `http://${this.ip}/ISAPI/Event/notification/alertStream`;
this.listenerPromise = this.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: "GET",
this.listenerPromise = this.request({
url,
responseType: 'stream',
responseType: 'readable',
}).then(response => {
const stream = response.data as IncomingMessage;
const stream = response.body;
stream.socket.setKeepAlive(true);
stream.on('data', (buffer: Buffer) => {

View File

@@ -6,7 +6,6 @@ import { OnvifIntercom } from "../../onvif/src/onvif-intercom";
import { RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { startRtpForwarderProcess } from '../../webrtc/src/rtp-forwarders';
import { HikvisionCameraAPI, HikvisionCameraEvent } from "./hikvision-camera-api";
import { hikvisionHttpsAgent } from './probe';
const { mediaManager } = sdk;
@@ -207,12 +206,11 @@ class HikvisionCamera extends RtspSmartCamera implements Camera, Intercom, Reboo
try {
let xml: string;
try {
const response = await client.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
const response = await client.request({
url: `http://${this.getHttpAddress()}/ISAPI/Streaming/channels`,
responseType: 'text',
});
xml = response.data;
xml = response.body;
this.storage.setItem('channels', xml);
}
catch (e) {
@@ -382,12 +380,12 @@ class HikvisionCamera extends RtspSmartCamera implements Camera, Intercom, Reboo
try {
const parameters = `http://${this.getHttpAddress()}/ISAPI/System/TwoWayAudio/channels`;
const { data: parametersData } = await this.getClient().digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
const { body } = await this.getClient().request({
url: parameters,
responseType: 'text',
});
const parsedXml = await xml2js.parseStringPromise(parametersData);
const parsedXml = await xml2js.parseStringPromise(body);
for (const twoWayChannel of parsedXml.TwoWayAudioChannelList.TwoWayAudioChannel) {
const [id] = twoWayChannel.id;
if (id !== channel)
@@ -423,27 +421,25 @@ class HikvisionCamera extends RtspSmartCamera implements Camera, Intercom, Reboo
const passthrough = new PassThrough();
const open = `http://${this.getHttpAddress()}/ISAPI/System/TwoWayAudio/channels/${channel}/open`;
const { data } = await this.getClient().digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: 'PUT',
const { body } = await this.getClient().request({
url: open,
responseType: 'text',
method: 'PUT',
});
this.console.log('two way audio opened', data);
this.console.log('two way audio opened', body);
const url = `http://${this.getHttpAddress()}/ISAPI/System/TwoWayAudio/channels/${channel}/audioData`;
this.console.log('posting audio data to', url);
const put = this.getClient().digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: 'PUT',
const put = this.getClient().request({
url,
responseType: 'readable',
headers: {
'Content-Type': 'application/octet-stream',
// 'Connection': 'close',
'Content-Length': '0'
},
data: passthrough,
});
}, passthrough);
let available = Buffer.alloc(0);
this.activeIntercom?.kill();
@@ -484,11 +480,10 @@ class HikvisionCamera extends RtspSmartCamera implements Camera, Intercom, Reboo
}
const client = this.getClient();
await client.digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: 'PUT',
await client.request({
url: `http://${this.getHttpAddress()}/ISAPI/System/TwoWayAudio/channels/${this.getRtspChannel() || '1'}/close`,
})
method: 'PUT',
});
}
}
@@ -530,7 +525,7 @@ class HikvisionProvider extends RtspProvider {
const username = settings.username?.toString();
const password = settings.password?.toString();
const skipValidate = settings.skipValidate === 'true';
const skipValidate = settings.skipValidate?.toString() === 'true';
let twoWayAudio: string;
if (!skipValidate) {
const api = new HikvisionCameraAPI(httpAddress, username, password, this.console);

View File

@@ -1,34 +1,30 @@
import https from 'https';
import AxiosDigestAuth from '@koush/axios-digest-auth';
import { AuthFetchCredentialState, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { checkStatus } from '../../../server/src/fetch';
export const hikvisionHttpsAgent = new https.Agent({
rejectUnauthorized: false,
});
export async function getDeviceInfo(credential: AuthFetchCredentialState, address: string) {
const response = await authHttpFetch({
credential,
url: `http://${address}/ISAPI/System/deviceInfo`,
ignoreStatusCode: true,
responseType: 'text',
rejectUnauthorized: false,
});
export async function getDeviceInfo(digestAuth: AxiosDigestAuth, address: string) {
try {
const response = await digestAuth.request({
httpsAgent: hikvisionHttpsAgent,
method: "GET",
responseType: 'text',
url: `http://${address}/ISAPI/System/deviceInfo`,
});
const deviceModel = response.data.match(/>(.*?)<\/model>/)?.[1];
const deviceName = response.data.match(/>(.*?)<\/deviceName>/)?.[1];
const serialNumber = response.data.match(/>(.*?)<\/serialNumber>/)?.[1];
const macAddress = response.data.match(/>(.*?)<\/macAddress>/)?.[1];
const firmwareVersion = response.data.match(/>(.*?)<\/firmwareVersion>/)?.[1];
return {
deviceModel,
deviceName,
serialNumber,
macAddress,
firmwareVersion,
};
}
catch (e) {
if (e?.response?.data?.includes('notActivated'))
throw new Error(`Camera must be first be activated at http://${address}.`)
throw e;
}
if (response.body.includes('notActivated'))
throw new Error(`Camera must be first be activated at http://${address}.`);
checkStatus(response.statusCode);
const deviceModel = response.body.match(/>(.*?)<\/model>/)?.[1];
const deviceName = response.body.match(/>(.*?)<\/deviceName>/)?.[1];
const serialNumber = response.body.match(/>(.*?)<\/serialNumber>/)?.[1];
const macAddress = response.body.match(/>(.*?)<\/macAddress>/)?.[1];
const firmwareVersion = response.body.match(/>(.*?)<\/firmwareVersion>/)?.[1];
return {
deviceModel,
deviceName,
serialNumber,
macAddress,
firmwareVersion,
};
}

View File

@@ -1,26 +1,26 @@
{
"name": "@scrypted/homekit",
"version": "1.2.33",
"version": "1.2.35",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/homekit",
"version": "1.2.33",
"version": "1.2.35",
"dependencies": {
"@koush/werift-src": "file:../../external/werift",
"check-disk-space": "^3.3.1",
"hap-nodejs": "^0.11.0",
"check-disk-space": "^3.4.0",
"hap-nodejs": "^0.11.1",
"lodash": "^4.17.21",
"mkdirp": "^2.1.6"
"mkdirp": "^3.0.1"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/debug": "^4.1.7",
"@types/lodash": "^4.14.192",
"@types/node": "^18.15.11",
"@types/url-parse": "^1.4.8"
"@types/debug": "^4.1.12",
"@types/lodash": "^4.14.202",
"@types/node": "^20.11.0",
"@types/url-parse": "^1.4.11"
}
},
"../../common": {
@@ -31,12 +31,12 @@
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"ts-node": "^10.9.2"
}
},
"../../external/werift": {
@@ -47,25 +47,26 @@
"examples/*"
],
"devDependencies": {
"@types/jest": "^29.2.4",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-simple-import-sort": "^8.0.0",
"jest": "^29.3.1",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.4",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"jest": "^29.7.0",
"knip": "^3.7.0",
"node-actionlint": "^1.2.2",
"organize-imports-cli": "^0.10.0",
"prettier": "^2.8.1",
"prettier": "^3.1.1",
"process": "^0.11.10",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"typedoc": "^0.23.23",
"typedoc-plugin-markdown": "^3.14.0",
"typescript": "^4.9.4"
"typedoc": "0.25.4",
"typedoc-plugin-markdown": "3.17.1",
"typescript": "5.0.4"
},
"engines": {
"node": ">=16"
@@ -126,13 +127,13 @@
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.86",
"version": "0.3.4",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -220,9 +221,9 @@
}
},
"node_modules/@homebridge/dbus-native": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.0.tgz",
"integrity": "sha512-ei0jyHE/uNDl/6D6heRwsqnESrrXuSlfp+xlwGfg3mo1OqhKvyb/Kp73uxQyOJ3f1T1ocLSyA5uzoR1AbfaXIQ==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz",
"integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==",
"dependencies": {
"@homebridge/long": "^5.2.1",
"@homebridge/put": "~0.0.8",
@@ -230,7 +231,7 @@
"hexy": "^0.2.10",
"minimist": "^1.2.6",
"safe-buffer": "^5.1.1",
"xml2js": "^0.4.17"
"xml2js": "^0.5.0"
},
"bin": {
"dbus2js": "bin/dbus2js.js"
@@ -267,18 +268,18 @@
"link": true
},
"node_modules/@types/debug": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
"integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"dev": true,
"dependencies": {
"@types/ms": "*"
}
},
"node_modules/@types/lodash": {
"version": "4.14.192",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
"integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==",
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
"dev": true
},
"node_modules/@types/ms": {
@@ -288,15 +289,18 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.15.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
"dev": true
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/url-parse": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
"integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
"version": "1.4.11",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.11.tgz",
"integrity": "sha512-FKvKIqRaykZtd4n47LbK/W/5fhQQ1X7cxxzG9A48h0BGN+S04NH7ervcCjM8tyR0lyGru83FAHSmw2ObgKoESg==",
"dev": true
},
"node_modules/array-flatten": {
@@ -345,11 +349,11 @@
}
},
"node_modules/check-disk-space": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.3.1.tgz",
"integrity": "sha512-iOrT8yCZjSnyNZ43476FE2rnssvgw5hnuwOM0hm8Nj1qa0v4ieUUEbCyxxsEliaoDUb/75yCOL71zkDiDBLbMQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz",
"integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==",
"engines": {
"node": ">=12"
"node": ">=16"
}
},
"node_modules/debug": {
@@ -486,9 +490,12 @@
"integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g=="
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/functions-have-names": {
"version": "1.2.3",
@@ -531,12 +538,12 @@
}
},
"node_modules/hap-nodejs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.0.tgz",
"integrity": "sha512-ZKSc/DIECXH1vSlruv6tBVcO+LF/BDtjdVk7IIiAAS+KKjw9PylkXbtdU23mmLhM69BsWl9u+BuToAfkf0voSw==",
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz",
"integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==",
"dependencies": {
"@homebridge/ciao": "^1.1.5",
"@homebridge/dbus-native": "^0.5.0",
"@homebridge/dbus-native": "^0.5.1",
"bonjour-hap": "~3.6.4",
"debug": "^4.3.4",
"fast-srp-hap": "~2.0.4",
@@ -856,9 +863,9 @@
}
},
"node_modules/mkdirp": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
"integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
"bin": {
"mkdirp": "dist/cjs/src/bin.js"
},
@@ -1012,9 +1019,9 @@
]
},
"node_modules/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"node_modules/side-channel": {
"version": "1.0.4",
@@ -1097,6 +1104,12 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
@@ -1146,9 +1159,9 @@
}
},
"node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
@@ -1157,7 +1170,7 @@
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"node_modules/xml2js/node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
@@ -1179,9 +1192,9 @@
}
},
"@homebridge/dbus-native": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.0.tgz",
"integrity": "sha512-ei0jyHE/uNDl/6D6heRwsqnESrrXuSlfp+xlwGfg3mo1OqhKvyb/Kp73uxQyOJ3f1T1ocLSyA5uzoR1AbfaXIQ==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz",
"integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==",
"requires": {
"@homebridge/long": "^5.2.1",
"@homebridge/put": "~0.0.8",
@@ -1189,7 +1202,7 @@
"hexy": "^0.2.10",
"minimist": "^1.2.6",
"safe-buffer": "^5.1.1",
"xml2js": "^0.4.17"
"xml2js": "^0.5.0"
}
},
"@homebridge/long": {
@@ -1205,25 +1218,26 @@
"@koush/werift-src": {
"version": "file:../../external/werift",
"requires": {
"@types/jest": "^29.2.4",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-simple-import-sort": "^8.0.0",
"jest": "^29.3.1",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.4",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"jest": "^29.7.0",
"knip": "^3.7.0",
"node-actionlint": "^1.2.2",
"organize-imports-cli": "^0.10.0",
"prettier": "^2.8.1",
"prettier": "^3.1.1",
"process": "^0.11.10",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"typedoc": "^0.23.23",
"typedoc-plugin-markdown": "^3.14.0",
"typescript": "^4.9.4"
"typedoc": "0.25.4",
"typedoc-plugin-markdown": "3.17.1",
"typescript": "5.0.4"
}
},
"@leichtgewicht/ip-codec": {
@@ -1236,10 +1250,10 @@
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"@types/node": "^20.11.0",
"http-auth-utils": "^5.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -1249,7 +1263,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -1267,18 +1281,18 @@
}
},
"@types/debug": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
"integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"dev": true,
"requires": {
"@types/ms": "*"
}
},
"@types/lodash": {
"version": "4.14.192",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
"integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==",
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
"dev": true
},
"@types/ms": {
@@ -1288,15 +1302,18 @@
"dev": true
},
"@types/node": {
"version": "18.15.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
"dev": true
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"requires": {
"undici-types": "~5.26.4"
}
},
"@types/url-parse": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
"integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
"version": "1.4.11",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.11.tgz",
"integrity": "sha512-FKvKIqRaykZtd4n47LbK/W/5fhQQ1X7cxxzG9A48h0BGN+S04NH7ervcCjM8tyR0lyGru83FAHSmw2ObgKoESg==",
"dev": true
},
"array-flatten": {
@@ -1336,9 +1353,9 @@
}
},
"check-disk-space": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.3.1.tgz",
"integrity": "sha512-iOrT8yCZjSnyNZ43476FE2rnssvgw5hnuwOM0hm8Nj1qa0v4ieUUEbCyxxsEliaoDUb/75yCOL71zkDiDBLbMQ=="
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz",
"integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw=="
},
"debug": {
"version": "4.3.4",
@@ -1448,9 +1465,9 @@
"integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g=="
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"functions-have-names": {
"version": "1.2.3",
@@ -1481,12 +1498,12 @@
}
},
"hap-nodejs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.0.tgz",
"integrity": "sha512-ZKSc/DIECXH1vSlruv6tBVcO+LF/BDtjdVk7IIiAAS+KKjw9PylkXbtdU23mmLhM69BsWl9u+BuToAfkf0voSw==",
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz",
"integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==",
"requires": {
"@homebridge/ciao": "^1.1.5",
"@homebridge/dbus-native": "^0.5.0",
"@homebridge/dbus-native": "^0.5.1",
"bonjour-hap": "~3.6.4",
"debug": "^4.3.4",
"fast-srp-hap": "~2.0.4",
@@ -1698,9 +1715,9 @@
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
},
"mkdirp": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
"integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A=="
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="
},
"ms": {
"version": "2.1.2",
@@ -1799,9 +1816,9 @@
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"side-channel": {
"version": "1.0.4",
@@ -1872,6 +1889,12 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
@@ -1909,18 +1932,20 @@
}
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"dependencies": {
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/homekit",
"version": "1.2.33",
"version": "1.2.35",
"description": "HomeKit Plugin for Scrypted",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
@@ -35,17 +35,17 @@
},
"dependencies": {
"@koush/werift-src": "file:../../external/werift",
"check-disk-space": "^3.3.1",
"hap-nodejs": "^0.11.0",
"check-disk-space": "^3.4.0",
"hap-nodejs": "^0.11.1",
"lodash": "^4.17.21",
"mkdirp": "^2.1.6"
"mkdirp": "^3.0.1"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/debug": "^4.1.7",
"@types/lodash": "^4.14.192",
"@types/node": "^18.15.11",
"@types/url-parse": "^1.4.8"
"@types/debug": "^4.1.12",
"@types/lodash": "^4.14.202",
"@types/node": "^20.11.0",
"@types/url-parse": "^1.4.11"
}
}

View File

@@ -1,7 +1,7 @@
import { sleep } from "@scrypted/common/src/sleep";
import sdk, { AudioSensor, Camera, Intercom, Logger, MotionSensor, ScryptedDevice, ScryptedInterface, VideoCamera } from "@scrypted/sdk";
import throttle from "lodash/throttle";
import { SnapshotRequest, SnapshotRequestCallback } from "../../hap";
import { ResourceRequestReason, SnapshotRequest, SnapshotRequestCallback } from "../../hap";
import type { HomeKitPlugin } from "../../main";
const { systemManager, mediaManager } = sdk;
@@ -14,41 +14,18 @@ function recommendSnapshotPlugin(console: Console, log: Logger, message: string)
}
export function createSnapshotHandler(device: ScryptedDevice & VideoCamera & Camera & MotionSensor & AudioSensor & Intercom, storage: Storage, homekitPlugin: HomeKitPlugin, console: Console) {
let pendingPicture: Promise<Buffer>;
const takePicture = async (request: SnapshotRequest) => {
if (!device.interfaces.includes(ScryptedInterface.Camera))
throw new Error('Camera does not provide native snapshots. Please install the Snapshot Plugin.');
const takePicture = (request: SnapshotRequest) => {
if (pendingPicture)
return pendingPicture;
if (device.interfaces.includes(ScryptedInterface.Camera)) {
pendingPicture = device.takePicture({
picture: {
width: request.width,
height: request.height,
}
})
.then(media => mediaManager.convertMediaObjectToBuffer(media, 'image/jpeg'));
}
else {
pendingPicture = Promise.reject(new Error('Camera does not provide native snapshots. Please install the Snapshot Plugin.'));
}
pendingPicture
.finally(() => {
pendingPicture = undefined;
})
return pendingPicture;
}
const throttledTakePicture = throttle(takePicture, 9000, {
leading: true,
trailing: true,
});
function snapshotAll(request: SnapshotRequest) {
for (const snapshotThrottle of homekitPlugin.snapshotThrottles.values()) {
snapshotThrottle(request);
}
const media = await device.takePicture({
reason: request.reason === ResourceRequestReason.EVENT ? 'event' : 'periodic',
picture: {
width: request.width,
height: request.height,
}
})
return await mediaManager.convertMediaObjectToBuffer(media, 'image/jpeg');
}
homekitPlugin.snapshotThrottles.set(device.id, takePicture);
@@ -72,11 +49,7 @@ export function createSnapshotHandler(device: ScryptedDevice & VideoCamera & Cam
// this call is not a bug, to force lodash to take a picture on the trailing edge,
// throttle must be called twice.
// no longer necessary in accessory mode?
snapshotAll(request);
snapshotAll(request);
callback(null, await throttledTakePicture(request));
callback(null, await takePicture(request));
}
catch (e) {
console.error('snapshot error', e);

View File

@@ -1,24 +1,22 @@
{
"name": "@scrypted/objectdetector",
"version": "0.1.19",
"version": "0.1.20",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/objectdetector",
"version": "0.1.19",
"version": "0.1.20",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"lodash": "^4.17.21",
"polygon-clipping": "^0.15.3",
"semver": "^7.3.8"
"polygon-clipping": "^0.15.7",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/lodash": "^4.14.175",
"@types/node": "^14.17.11",
"@types/semver": "^7.3.13"
"@types/node": "^20.11.0",
"@types/semver": "^7.5.6"
}
},
"../../common": {
@@ -28,22 +26,22 @@
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.2",
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -81,29 +79,21 @@
"resolved": "../../sdk",
"link": true
},
"node_modules/@types/lodash": {
"version": "4.14.177",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.177.tgz",
"integrity": "sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw==",
"dev": true
},
"node_modules/@types/node": {
"version": "14.17.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.33.tgz",
"integrity": "sha512-noEeJ06zbn3lOh4gqe2v7NMGS33jrulfNqYFDjjEbhpDEHR5VTxgYNQSBqBlJIsBJW3uEYDgD6kvMnrrhGzq8g==",
"dev": true
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -116,13 +106,19 @@
}
},
"node_modules/polygon-clipping": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz",
"integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==",
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.7.tgz",
"integrity": "sha512-nhfdr83ECBg6xtqOAJab1tbksbBAOMUltN60bU+llHVOL0e5Onm1WpAXXWXVB39L8AJFssoIhEVuy/S90MmotA==",
"dependencies": {
"robust-predicates": "^3.0.2",
"splaytree": "^3.1.0"
}
},
"node_modules/robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -142,6 +138,12 @@
"resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz",
"integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A=="
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@@ -171,10 +173,10 @@
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"@types/node": "^20.11.0",
"http-auth-utils": "^5.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -184,7 +186,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -201,29 +203,21 @@
"webpack-bundle-analyzer": "^4.5.0"
}
},
"@types/lodash": {
"version": "4.14.177",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.177.tgz",
"integrity": "sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw==",
"dev": true
},
"@types/node": {
"version": "14.17.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.33.tgz",
"integrity": "sha512-noEeJ06zbn3lOh4gqe2v7NMGS33jrulfNqYFDjjEbhpDEHR5VTxgYNQSBqBlJIsBJW3uEYDgD6kvMnrrhGzq8g==",
"dev": true
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"dev": true,
"requires": {
"undici-types": "~5.26.4"
}
},
"@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -233,13 +227,19 @@
}
},
"polygon-clipping": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz",
"integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==",
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.7.tgz",
"integrity": "sha512-nhfdr83ECBg6xtqOAJab1tbksbBAOMUltN60bU+llHVOL0e5Onm1WpAXXWXVB39L8AJFssoIhEVuy/S90MmotA==",
"requires": {
"robust-predicates": "^3.0.2",
"splaytree": "^3.1.0"
}
},
"robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -253,6 +253,12 @@
"resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz",
"integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A=="
},
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/objectdetector",
"version": "0.1.19",
"version": "0.1.20",
"description": "Scrypted Video Analysis Plugin. Installed alongside a detection service like OpenCV or TensorFlow.",
"author": "Scrypted",
"license": "Apache-2.0",
@@ -45,13 +45,11 @@
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"lodash": "^4.17.21",
"polygon-clipping": "^0.15.3",
"semver": "^7.3.8"
"polygon-clipping": "^0.15.7",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/lodash": "^4.14.175",
"@types/node": "^14.17.11",
"@types/semver": "^7.3.13"
"@types/node": "^20.11.0",
"@types/semver": "^7.5.6"
}
}

View File

@@ -0,0 +1,36 @@
import { CpuInfo, cpus } from 'os';
function getIdleTotal(cpu: CpuInfo) {
const t = cpu.times;
const total = t.user + t.nice + t.sys + t.idle + t.irq;
const idle = t.idle;
return {
idle,
total,
}
}
export class CpuTimer {
previousSample: ReturnType<typeof cpus>;
sample(): number {
const sample = cpus();
const previousSample = this.previousSample;
this.previousSample = sample;
// can cpu count change at runtime, who knows
if (!previousSample || previousSample.length !== sample.length)
return 0;
const times = sample.map((v, i) => {
const c = getIdleTotal(v);
const p = getIdleTotal(previousSample[i]);
const total = c.total - p.total;
const idle = c.idle - p.idle;
return 1 - idle / total;
});
const total = times.reduce((p, c) => p + c, 0);
return total / sample.length;
}
}

View File

@@ -5,10 +5,9 @@ import { StorageSettings } from '@scrypted/sdk/storage-settings';
import crypto from 'crypto';
import { AutoenableMixinProvider } from "../../../common/src/autoenable-mixin-provider";
import { SettingsMixinDeviceBase } from "../../../common/src/settings-mixin";
import { CpuTimer } from './cpu-timer';
import { FFmpegVideoFrameGenerator } from './ffmpeg-videoframes';
import { getMaxConcurrentObjectDetectionSessions } from './performance-profile';
import { insidePolygon, normalizeBox, polygonOverlap } from './polygon';
import { serverSupportsMixinEventMasking } from './server-version';
import { SMART_MOTIONSENSOR_PREFIX, SmartMotionSensor, createObjectDetectorStorageSetting } from './smart-motionsensor';
import { getAllDevices, safeParseJson } from './util';
@@ -125,11 +124,14 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
this.bindObjectDetection();
this.register();
this.detectionIntervalTimeout = setInterval(async () => {
if (this.released)
return;
this.maybeStartDetection();
}, 60000);
// ensure motion sensors stay alive. plugin will manage object detection throttling.
if (this.hasMotionType) {
this.detectionIntervalTimeout = setInterval(async () => {
if (this.released)
return;
this.maybeStartDetection();
}, 60000);
}
this.storageSettings.settings.zones.mapGet = () => Object.keys(this.zones);
this.storageSettings.settings.zones.onGet = async () => {
@@ -187,8 +189,10 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
maybeStartDetection() {
if (!this.hasMotionType) {
// object detection may be restarted if there are slots available.
if (this.cameraDevice.motionDetected && this.plugin.canStartObjectDetection(this))
if (this.cameraDevice.motionDetected && this.plugin.canStartObjectDetection(this)) {
this.startPipelineAnalysis();
return true;
}
return;
}
@@ -238,7 +242,7 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
return;
}
this.startPipelineAnalysis();
this.maybeStartDetection();
});
return;
@@ -627,7 +631,7 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
}
get motionSensorSupplementation() {
if (!serverSupportsMixinEventMasking() || !this.interfaces.includes(ScryptedInterface.MotionSensor))
if (!this.interfaces.includes(ScryptedInterface.MotionSensor))
return BUILTIN_MOTION_SENSOR_REPLACE;
const supp = this.storage.getItem('motionSensorSupplementation');
@@ -934,19 +938,6 @@ export class ObjectDetectionPlugin extends AutoenableMixinProvider implements Se
statsSnapshotDetections: number;
statsSnapshotConcurrent = 0;
storageSettings = new StorageSettings(this, {
maxConcurrentDetections: {
title: 'Max Concurrent Detections',
description: `The max number concurrent cameras that will perform object detection while their motion sensor is triggered. Older sessions will be terminated when the limit is reached. The default value is ${getMaxConcurrentObjectDetectionSessions()}.`,
defaultValue: 'Default',
combobox: true,
choices: [
'Default',
...[2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => i.toString()),
],
mapPut: (o, v) => {
return parseInt(v) || 'Default';
}
},
activeMotionDetections: {
title: 'Active Motion Detection Sessions',
multiple: true,
@@ -1010,6 +1001,8 @@ export class ObjectDetectionPlugin extends AutoenableMixinProvider implements Se
},
});
devices = new Map<string, any>();
cpuTimer = new CpuTimer();
cpuUsage = 0;
pruneOldStatistics() {
const now = Date.now();
@@ -1024,69 +1017,53 @@ export class ObjectDetectionPlugin extends AutoenableMixinProvider implements Se
this.statsSnapshotDetections++;
}
get maxConcurrent() {
let maxConcurrent = this.storageSettings.values.maxConcurrentDetections || 'Default';
maxConcurrent = Math.max(parseInt(maxConcurrent)) || getMaxConcurrentObjectDetectionSessions();
return maxConcurrent;
}
canStartObjectDetection(mixin: ObjectDetectionMixin) {
const maxConcurrent = this.maxConcurrent;
const runningDetections = [...this.currentMixins.values()]
.map(d => [...d.currentMixins.values()].filter(dd => !dd.hasMotionType)).flat()
.filter(c => c.detectorRunning)
.sort((a, b) => a.detectionStartTime - b.detectionStartTime);
const runningDetections = this.runningObjectDetections;
// already running
if (runningDetections.find(o => o.id === mixin.id))
return false;
if (runningDetections.length < maxConcurrent)
if (!runningDetections.length)
return true;
const [first] = runningDetections;
if (Date.now() - first.detectionStartTime > 30000)
return true;
const cpuPerDetector = this.cpuUsage / runningDetections.length;
const cpuPercent = Math.round(this.cpuUsage * 100);
if (cpuPerDetector * (runningDetections.length + 1) > .9) {
const [first] = runningDetections;
if (Date.now() - first.detectionStartTime > 30000) {
first.console.warn(`CPU is at capacity: ${cpuPercent} with ${runningDetections.length} cameras. Ending object detection to process activity on ${mixin.name}.`);
first.endObjectDetection();
mixin.console.warn(`CPU is at capacity: ${cpuPercent} with ${runningDetections.length} cameras. Ending object detection on ${first.name} to process activity.`);
return true;
}
mixin.console.log(`Not starting object detection to continue processing recent activity on ${first.name}.`);
return false;
mixin.console.warn(`CPU is at capacity: ${cpuPercent} with ${runningDetections.length} cameras. Not starting object detection to continue processing recent activity on ${first.name}.`);
return false;
}
// CPU capacity is fine
return true;
}
get runningObjectDetections() {
const runningDetections = [...this.currentMixins.values()]
.map(d => [...d.currentMixins.values()].filter(dd => !dd.hasMotionType)).flat()
.filter(c => c.detectorRunning)
.sort((a, b) => a.detectionStartTime - b.detectionStartTime);
return runningDetections;
}
objectDetectionStarted(name: string, console: Console) {
this.resetStats(console);
this.statsSnapshotConcurrent++;
const maxConcurrent = this.maxConcurrent;
const objectDetections = [...this.currentMixins.values()]
.map(d => [...d.currentMixins.values()].filter(dd => !dd.hasMotionType)).flat()
.filter(c => c.detectorRunning)
.sort((a, b) => a.detectionStartTime - b.detectionStartTime);
while (objectDetections.length > maxConcurrent) {
const old = objectDetections.shift();
// allow exceeding the concurrency limit if user interaction triggered analyze.
if (old.analyzeStop)
continue;
old.console.log(`Ending object detection to process activity on ${name}.`);
old.endObjectDetection();
}
}
objectDetectionEnded(console: Console) {
this.resetStats(console);
this.statsSnapshotConcurrent--;
const objectDetections = [...this.currentMixins.values()]
.map(d => [...d.currentMixins.values()].filter(dd => !dd.hasMotionType)).flat()
.filter(c => !c.detectorRunning);
for (const notRunning of objectDetections) {
notRunning.maybeStartDetection();
}
}
resetStats(console: Console) {
@@ -1126,7 +1103,34 @@ export class ObjectDetectionPlugin extends AutoenableMixinProvider implements Se
],
nativeId: 'ffmpeg',
})
})
});
setInterval(() => {
this.cpuUsage = this.cpuTimer.sample();
// this.console.log('cpu usage', Math.round(this.cpuUsage * 100));
const runningDetections = this.runningObjectDetections;
let allowStart = 1;
if (runningDetections.length) {
const cpuPerDetector = this.cpuUsage / runningDetections.length;
allowStart = Math.ceil(1 / cpuPerDetector) - runningDetections.length;
if (allowStart <= 0)
return;
}
const idleDetectors = [...this.currentMixins.values()]
.map(d => [...d.currentMixins.values()].filter(dd => !dd.hasMotionType)).flat()
.filter(c => !c.detectorRunning);
for (const notRunning of idleDetectors) {
if (notRunning.maybeStartDetection()) {
allowStart--;
if (allowStart <= 0)
return;
}
}
}, 10000)
}
async getDevice(nativeId: string): Promise<any> {

View File

@@ -1,32 +0,0 @@
import os from 'os';
let totalGigahertz = 0;
export function getMaxConcurrentObjectDetectionSessions() {
const cpus = os.cpus();
// apple silicon cpu.speed is incorrect, and can handle quite a bit due to
// gpu decode and neural core usage.
// .5 detect per cpu is a conservative guess. so an m1 ultra would handle 10
// simultaneous camera detections.
// apple silicon also reports cpu speed as 24 mhz, so the following code would
// fail anyways.
if (process.platform === 'darwin' && process.arch === 'arm64')
return cpus.length * .5;
let speed = 0;
for (const cpu of cpus) {
// can cpu speed be zero? is that a thing?
speed += cpu.speed || 600;
}
totalGigahertz = Math.max(speed, totalGigahertz);
// a wyse 5070 self reports in description as 1.5ghz and has 4 cores and can comfortably handle
// two 2k detections at the same time.
// the speed reported while detecting caps at 2500, presumably due to burst?
// the total mhz would be 10000 in this case.
// observed idle per cpu speed is 800.
// not sure how hyperthreading plays into this.
return Math.max(2, Math.round(totalGigahertz / 4000));
}

View File

@@ -1,13 +0,0 @@
import semver from 'semver';
import sdk from '@scrypted/sdk';
export function serverSupportsMixinEventMasking() {
try {
if (!sdk.serverVersion)
return false;
return semver.gte(sdk.serverVersion, '0.5.0');
}
catch (e) {
}
return false;
}

View File

@@ -6,3 +6,4 @@ fs
src
.vscode
dist/*.js
onvif

View File

@@ -10,7 +10,7 @@
"port": 10081,
"request": "attach",
"skipFiles": [
"**/plugin-remote-worker.*",
"**/plugin-console.*",
"<node_internals>/**"
],
"preLaunchTask": "scrypted: deploy+debug",

1
plugins/onvif/onvif Submodule

Submodule plugins/onvif/onvif added at 5641b572c4

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/onvif",
"version": "0.0.128",
"version": "0.1.8",
"description": "ONVIF Camera Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",
@@ -36,18 +36,16 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"base-64": "^1.0.0",
"http-auth-utils": "^4.0.0",
"md5": "^2.3.0",
"onvif": "^0.6.8",
"xml2js": "^0.6.0"
"onvif": "file:./onvif",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@types/md5": "^2.3.2",
"@types/node": "^20.3.2",
"@types/xml2js": "^0.4.11"
"@types/md5": "^2.3.5",
"@types/node": "^20.11.0",
"@types/xml2js": "^0.4.14"
}
}

View File

@@ -492,7 +492,7 @@ class OnvifProvider extends RtspProvider implements DeviceDiscovery {
const username = settings.username?.toString();
const password = settings.password?.toString();
const skipValidate = settings.skipValidate === 'true';
const skipValidate = settings.skipValidate?.toString() === 'true';
let ptzCapabilities: string[];
if (!skipValidate) {
try {

View File

@@ -1,10 +1,7 @@
import { HttpFetchOptions, HttpFetchResponseType, AuthFetchCredentialState, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { EventEmitter } from 'events';
import AxiosDigestAuth from '@koush/axios-digest-auth';
import https from 'https';
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
})
import { Readable } from 'stream';
const onvif = require('onvif');
const { Cam } = onvif;
@@ -58,15 +55,27 @@ export class OnvifCameraAPI {
rtspUrls = new Map<string, string>();
profiles: Promise<any>;
binaryStateEvent: string;
digestAuth: AxiosDigestAuth;
credential: AuthFetchCredentialState;
detections: Map<string, string>;
constructor(public cam: any, username: string, password: string, public console: Console, binaryStateEvent: string) {
this.binaryStateEvent = binaryStateEvent
this.digestAuth = new AxiosDigestAuth({
this.credential = {
username,
password,
};
}
async request(urlOrOptions: string | URL | HttpFetchOptions<Readable>, body?: Readable) {
const response = await authHttpFetch({
...typeof urlOrOptions !== 'string' && !(urlOrOptions instanceof URL) ? urlOrOptions : {
url: urlOrOptions,
},
rejectUnauthorized: false,
credential: this.credential,
body,
});
return response;
}
async reboot() {
@@ -88,67 +97,68 @@ export class OnvifCameraAPI {
this.cam.on('event', (event: any, xml: string) => {
ret.emit('data', xml);
if (!event.message.message.data?.simpleItem?.$)
return;
const dataValue = event.message.message.data.simpleItem.$.Value;
const eventTopic = stripNamespaces(event.topic._);
if (event.message.message.data && event.message.message.data.simpleItem) {
const dataValue = event.message.message.data.simpleItem.$.Value;
if (eventTopic.includes('MotionAlarm')) {
// ret.emit('event', OnvifEvent.MotionBuggy);
if (dataValue)
ret.emit('event', OnvifEvent.MotionStart)
else
ret.emit('event', OnvifEvent.MotionStop)
if (eventTopic.includes('MotionAlarm')) {
// ret.emit('event', OnvifEvent.MotionBuggy);
if (dataValue)
ret.emit('event', OnvifEvent.MotionStart)
else
ret.emit('event', OnvifEvent.MotionStop)
}
else if (eventTopic.includes('DetectedSound')) {
if (dataValue)
ret.emit('event', OnvifEvent.AudioStart)
else
ret.emit('event', OnvifEvent.AudioStop)
}
// Reolink
else if (eventTopic.includes('Visitor') && (dataValue === true || dataValue === false)) {
if (dataValue) {
ret.emit('event', OnvifEvent.BinaryStart)
}
else if (eventTopic.includes('DetectedSound')) {
if (dataValue)
ret.emit('event', OnvifEvent.AudioStart)
else
ret.emit('event', OnvifEvent.AudioStop)
else {
ret.emit('event', OnvifEvent.BinaryStop)
}
// Reolink
else if (eventTopic.includes('Visitor') && (dataValue === true || dataValue === false)) {
if (dataValue) {
ret.emit('event', OnvifEvent.BinaryStart)
}
// Mobotix T26
else if (eventTopic.includes('VideoSource/Alarm')) {
if (dataValue === "Ring" || dataValue === "CameraBellButton") {
ret.emit('event', OnvifEvent.BinaryRingEvent);
}
}
// else if (eventTopic.includes('DigitalInput')) {
// if (dataValue)
// ret.emit('event', OnvifEvent.BinaryStart)
// else
// ret.emit('event', OnvifEvent.BinaryStop)
// }
else if (this.binaryStateEvent && eventTopic.includes(this.binaryStateEvent)) {
if (dataValue)
ret.emit('event', OnvifEvent.BinaryStart)
else
ret.emit('event', OnvifEvent.BinaryStop)
}
else if (eventTopic.includes('RuleEngine/CellMotionDetector/Motion')) {
// unclear if the IsMotion false is indicative of motion stop?
if (event.message.message.data.simpleItem.$.Name === 'IsMotion' && dataValue) {
ret.emit('event', OnvifEvent.MotionBuggy);
}
}
else if (eventTopic.includes('RuleEngine/ObjectDetector')) {
if (dataValue) {
try {
const eventName = event.message.message.data.simpleItem.$.Name;
const className = this.detections.get(eventName);
this.console.log('object detected:', className);
ret.emit('event', OnvifEvent.Detection, className);
}
else {
ret.emit('event', OnvifEvent.BinaryStop)
}
}
// Mobotix T26
else if (eventTopic.includes('VideoSource/Alarm')) {
if (dataValue === "Ring" || dataValue === "CameraBellButton") {
ret.emit('event', OnvifEvent.BinaryRingEvent);
}
}
// else if (eventTopic.includes('DigitalInput')) {
// if (dataValue)
// ret.emit('event', OnvifEvent.BinaryStart)
// else
// ret.emit('event', OnvifEvent.BinaryStop)
// }
else if (this.binaryStateEvent && eventTopic.includes(this.binaryStateEvent)) {
if (dataValue)
ret.emit('event', OnvifEvent.BinaryStart)
else
ret.emit('event', OnvifEvent.BinaryStop)
}
else if (eventTopic.includes('RuleEngine/CellMotionDetector/Motion')) {
// unclear if the IsMotion false is indicative of motion stop?
if (event.message.message.data.simpleItem.$.Name === 'IsMotion' && dataValue) {
ret.emit('event', OnvifEvent.MotionBuggy);
}
}
else if (eventTopic.includes('RuleEngine/ObjectDetector')) {
if (dataValue) {
try {
const eventName = event.message.message.data.simpleItem.$.Name;
const className = this.detections.get(eventName);
this.console.log('object detected:', className);
ret.emit('event', OnvifEvent.Detection, className);
}
catch (e) {
this.console.warn('error parsing detection', e);
}
catch (e) {
this.console.warn('error parsing detection', e);
}
}
}
@@ -228,13 +238,14 @@ export class OnvifCameraAPI {
this.console.log(xml);
this.detections = new Map();
try {
for (const [className, entry] of Object.entries(data.topicSet.ruleEngine.objectDetector) as any) {
try {
const eventName = entry.messageDescription.data.simpleItemDescription.$.Name;
this.detections.set(eventName, className);
}
catch (e) {
if (data.topicSet.ruleEngine.objectDetector) {
for (const [className, entry] of Object.entries(data.topicSet.ruleEngine.objectDetector) as any) {
try {
const eventName = entry.messageDescription.data.simpleItemDescription.$.Name;
this.detections.set(eventName, className);
}
catch (e) {
}
}
}
}
@@ -279,15 +290,12 @@ export class OnvifCameraAPI {
if (!snapshotUri)
return;
const response = await this.digestAuth.request({
method: 'GET',
const response = await this.request({
url: snapshotUri,
responseType: 'arraybuffer',
httpsAgent,
timeout: 60000,
});
return Buffer.from(response.data);
return response.body;
}
getDeviceInformation(): Promise<any> {

View File

@@ -44,7 +44,8 @@ export async function listenEvents(thisDevice: ScryptedDeviceBase, client: Onvif
}
else if (event === OnvifEvent.MotionStop) {
// reset the trigger to debounce per above.
triggerMotion();
if (thisDevice.motionDetected)
triggerMotion();
// thisDevice.motionDetected = false;
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/openvino",
"version": "0.1.46",
"version": "0.1.48",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/openvino",
"version": "0.1.46",
"version": "0.1.48",
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
}

View File

@@ -41,5 +41,5 @@
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
},
"version": "0.1.46"
"version": "0.1.48"
}

View File

@@ -1,5 +1,6 @@
openvino==2023.2.0
# pillow for anything not intel linux, pillow-simd is available on x64 linux
# pillow-simd is available on x64 linux
# pillow-simd confirmed not building with arm64 linux or apple silicon
Pillow>=5.4.1; sys_platform != 'linux' or platform_machine != 'x86_64'
pillow-simd; sys_platform == 'linux' and platform_machine == 'x86_64'

View File

@@ -10,7 +10,7 @@
"port": 10081,
"request": "attach",
"skipFiles": [
"**/plugin-remote-worker.*",
"**/plugin-console.*",
"<node_internals>/**"
],
"preLaunchTask": "scrypted: deploy+debug",

View File

@@ -1,20 +1,17 @@
{
"name": "@scrypted/reolink",
"version": "0.0.54",
"version": "0.0.58",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/reolink",
"version": "0.0.54",
"version": "0.0.58",
"license": "Apache",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/multiparty": "^0.0.33",
"multiparty": "^4.2.3",
"onvif": "^0.6.8"
"onvif": "file:../onvif/onvif"
},
"devDependencies": {
"@types/node": "^18.16.18"
@@ -29,10 +26,11 @@
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
@@ -72,13 +70,27 @@
"typedoc": "^0.23.21"
}
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"../onvif/onvif": {
"version": "0.7.0",
"license": "MIT",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
"lodash.get": "^4.4.2",
"xml2js": "^0.5.0"
},
"devDependencies": {
"coveralls": "^3.1.1",
"dot": "^1.1.3",
"eslint": "^8.3.0",
"eslint-plugin-node": "^11.1.0",
"ip": "^1.1.5",
"keypress": "^0.2.1",
"mocha": "^10.0.0",
"mocha-lcov-reporter": "^1.3.0",
"nimble": "^0.0.2",
"nyc": "^15.1.0"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/@scrypted/common": {
@@ -89,192 +101,15 @@
"resolved": "../../sdk",
"link": true
},
"node_modules/@types/multiparty": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/@types/multiparty/-/multiparty-0.0.33.tgz",
"integrity": "sha512-Il6cJUpSqgojT7NxbVJUvXkCblm50/yEJYtblISDsNIeNYf4yMAhdizzidUk6h8pJ8yhwK/3Fkb+3Dwcgtwl8w==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.16.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.18.tgz",
"integrity": "sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw=="
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
},
"node_modules/multiparty": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz",
"integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==",
"dependencies": {
"http-errors": "~1.8.1",
"safe-buffer": "5.2.1",
"uid-safe": "2.1.5"
},
"engines": {
"node": ">= 0.10"
}
"integrity": "sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw==",
"dev": true
},
"node_modules/onvif": {
"version": "0.6.9",
"resolved": "https://registry.npmjs.org/onvif/-/onvif-0.6.9.tgz",
"integrity": "sha512-aKr14CG8dkHMEF3bUqBZA1OdZi4ffzfmR5E1Y3v4WpweCGkywERAQDhQM3PRUvLNtqnWbcDEcq4l7gBSZ7JCyA==",
"dependencies": {
"lodash.get": "^4.4.2",
"xml2js": "^0.5.0"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/sax": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
"resolved": "../onvif/onvif",
"link": true
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/reolink",
"version": "0.0.54",
"version": "0.0.58",
"description": "Reolink Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",
@@ -35,12 +35,9 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/multiparty": "^0.0.33",
"multiparty": "^4.2.3",
"onvif": "^0.6.8"
"onvif": "file:../onvif/onvif"
},
"devDependencies": {
"@types/node": "^18.16.18"

View File

@@ -1,23 +1,25 @@
import AxiosDigestAuth from "@koush/axios-digest-auth";
import { AuthFetchCredentialState, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import https from 'https';
export const reolinkHttpsAgent = new https.Agent({
rejectUnauthorized: false,
});
export async function getMotionState(digestAuth: AxiosDigestAuth, username: string, password: string, address: string, channelId: number) {
export async function getMotionState(credential: AuthFetchCredentialState, username: string, password: string, address: string, channelId: number) {
const url = new URL(`http://${address}/api.cgi`);
const params = url.searchParams;
params.set('cmd', 'GetMdState');
params.set('channel', channelId.toString());
params.set('user', username);
params.set('password', password);
const response = await digestAuth.request({
const response = await authHttpFetch({
credential,
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
rejectUnauthorized: false,
responseType: 'json',
});
return {
value: !!response.data?.[0]?.value?.state,
data: response.data,
value: !!response.body?.[0]?.value?.state,
data: response.body,
};
}

View File

@@ -1,4 +1,9 @@
import AxiosDigestAuth from "@koush/axios-digest-auth";
import { AuthFetchCredentialState, AuthFetchOptions, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { EventEmitter } from 'events';
import https, { RequestOptions } from 'https';
import { PassThrough, Readable } from 'stream';
import { HttpFetchOptions, HttpFetchResponseType } from '../../../server/src/fetch/http-fetch';
import { getMotionState, reolinkHttpsAgent } from './probe';
import { PanTiltZoomCommand } from "@scrypted/sdk";
import { sleep } from "@scrypted/common/src/sleep";
@@ -55,13 +60,25 @@ export type AIState = {
};
export class ReolinkCameraClient {
digestAuth: AxiosDigestAuth;
credential: AuthFetchCredentialState;
constructor(public host: string, public username: string, public password: string, public channelId: number, public console: Console) {
this.digestAuth = new AxiosDigestAuth({
password,
this.credential = {
username,
password,
};
}
async request(urlOrOptions: string | URL | HttpFetchOptions<Readable>, body?: Readable) {
const response = await authHttpFetch({
...typeof urlOrOptions !== 'string' && !(urlOrOptions instanceof URL) ? urlOrOptions : {
url: urlOrOptions,
},
rejectUnauthorized: false,
credential: this.credential,
body,
});
return response;
}
async reboot() {
@@ -70,13 +87,13 @@ export class ReolinkCameraClient {
params.set('cmd', 'Reboot');
params.set('user', this.username);
params.set('password', this.password);
const response = await this.digestAuth.request({
const response = await this.request({
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
responseType: 'json',
});
return {
value: response.data?.[0]?.value?.rspCode,
data: response.data,
value: response.body?.[0]?.value?.rspCode,
data: response.body,
};
}
@@ -90,7 +107,7 @@ export class ReolinkCameraClient {
// }
// ]
async getMotionState() {
return getMotionState(this.digestAuth, this.username, this.password, this.host, this.channelId);
return getMotionState(this.credential, this.username, this.password, this.host, this.channelId);
}
async getAiState() {
@@ -100,13 +117,13 @@ export class ReolinkCameraClient {
params.set('channel', this.channelId.toString());
params.set('user', this.username);
params.set('password', this.password);
const response = await this.digestAuth.request({
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
const response = await this.request({
url,
responseType: 'json',
});
return {
value: response.data?.[0]?.value as AIState,
data: response.data,
value: response.body?.[0]?.value as AIState,
data: response.body,
};
}
@@ -119,14 +136,12 @@ export class ReolinkCameraClient {
params.set('user', this.username);
params.set('password', this.password);
const response = await this.digestAuth.request({
url: url.toString(),
responseType: 'arraybuffer',
httpsAgent: reolinkHttpsAgent,
const response = await this.request({
url,
timeout: 60000,
});
return Buffer.from(response.data);
return response.body;
}
async getEncoderConfiguration(): Promise<Enc> {
@@ -137,12 +152,12 @@ export class ReolinkCameraClient {
params.set('channel', this.channelId.toString());
params.set('user', this.username);
params.set('password', this.password);
const response = await this.digestAuth.request({
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
const response = await this.request({
url,
responseType: 'json',
});
return response.data?.[0]?.value?.Enc;
return response.body?.[0]?.value?.Enc;
}
async getDeviceInfo(): Promise<DevInfo> {
@@ -151,12 +166,12 @@ export class ReolinkCameraClient {
params.set('cmd', 'GetDevInfo');
params.set('user', this.username);
params.set('password', this.password);
const response = await this.digestAuth.request({
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
const response = await this.request({
url,
responseType: 'json',
});
return response.data?.[0]?.value?.DevInfo;
return response.body?.[0]?.value?.DevInfo;
}
async ptz(command: PanTiltZoomCommand) {
@@ -179,39 +194,43 @@ export class ReolinkCameraClient {
params.set('user', this.username);
params.set('password', this.password);
const c1 = this.digestAuth.request({
const createReadable = (data: any) => {
const pt = new PassThrough();
pt.write(Buffer.from(JSON.stringify(data)));
pt.end();
return pt;
}
const c1 = this.request({
url,
method: 'POST',
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
data: [
{
cmd: "PtzCtrl",
param: {
channel: this.channelId,
op,
speed: 10,
timeout: 1,
}
},
]
});
responseType: 'text',
}, createReadable([
{
cmd: "PtzCtrl",
param: {
channel: this.channelId,
op,
speed: 10,
timeout: 1,
}
},
]));
await sleep(500);
const c2 = this.digestAuth.request({
const c2 = this.request({
url,
method: 'POST',
url: url.toString(),
httpsAgent: reolinkHttpsAgent,
data: [
{
cmd: "PtzCtrl",
param: {
channel: this.channelId,
op: "Stop"
}
},
]
});
}, createReadable([
{
cmd: "PtzCtrl",
param: {
channel: this.channelId,
op: "Stop"
}
},
]));
this.console.log(await c1);
this.console.log(await c2);

File diff suppressed because it is too large Load Diff

View File

@@ -35,14 +35,11 @@
"@scrypted/snapshot"
]
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^16.9.6"
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"axios": "^0.23.0",
"url-parse": "^1.4.7"
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk"
},
"devDependencies": {
"@types/node": "^20.10.8"
}
}

View File

@@ -1,8 +1,7 @@
import sdk, { Setting, MediaObject, ScryptedInterface, FFmpegInput, PictureOptions, SettingValue, MediaStreamOptions, ResponseMediaStreamOptions, ScryptedMimeTypes, MediaStreamUrl } from "@scrypted/sdk";
import { EventEmitter } from "stream";
import { CameraProviderBase, CameraBase, UrlMediaStreamOptions } from "../../ffmpeg-camera/src/common";
import { timeoutPromise } from '@scrypted/common/src/promise-utils';
import sdk, { MediaObject, MediaStreamUrl, PictureOptions, ResponseMediaStreamOptions, ScryptedInterface, ScryptedMimeTypes, Setting, SettingValue } from "@scrypted/sdk";
import url from 'url';
import { timeoutFunction, timeoutPromise } from '@scrypted/common/src/promise-utils';
import { CameraBase, CameraProviderBase, UrlMediaStreamOptions } from "../../ffmpeg-camera/src/common";
export { UrlMediaStreamOptions } from "../../ffmpeg-camera/src/common";

View File

@@ -1,16 +1,14 @@
{
"name": "@scrypted/snapshot",
"version": "0.2.31",
"version": "0.2.34",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/snapshot",
"version": "0.2.31",
"version": "0.2.34",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@types/node": "^20.10.6",
"axios": "^0.21.4",
"sharp": "^0.33.1",
"whatwg-mimetype": "^4.0.0"
},
@@ -30,10 +28,11 @@
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
@@ -514,15 +513,6 @@
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -545,19 +535,6 @@
"integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==",
"dev": true
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -603,25 +580,6 @@
"node": ">=8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
@@ -875,24 +833,16 @@
"integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==",
"optional": true
},
"@koush/axios-digest-auth": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.7.tgz",
"integrity": "sha512-sZepmWhDt4JUMB1ycX8k9SmDfHeCX+g+pGslrpLORHhEo2vLYFzTjAzL62NFmZO9uG4xmedDn4i0eJW5IK3//Q==",
"requires": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"@scrypted/common": {
"version": "file:../../common",
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"@types/node": "^20.10.8",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -933,19 +883,6 @@
"integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==",
"dev": true
},
"auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
},
"axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"requires": {
"follow-redirects": "^1.14.0"
}
},
"color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -982,11 +919,6 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
"integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/snapshot",
"version": "0.2.31",
"version": "0.2.34",
"description": "Snapshot Plugin for Scrypted",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
@@ -34,9 +34,7 @@
]
},
"dependencies": {
"@koush/axios-digest-auth": "^0.8.7",
"@types/node": "^20.10.6",
"axios": "^0.21.4",
"sharp": "^0.33.1",
"whatwg-mimetype": "^4.0.0"
},

View File

@@ -1,18 +1,17 @@
import AxiosDigestAuth from '@koush/axios-digest-auth';
import { AutoenableMixinProvider } from "@scrypted/common/src/autoenable-mixin-provider";
import { createMapPromiseDebouncer, RefreshPromise, singletonPromise, TimeoutError } from "@scrypted/common/src/promise-utils";
import { AuthFetchCredentialState, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { RefreshPromise, TimeoutError, createMapPromiseDebouncer, singletonPromise, timeoutPromise } from "@scrypted/common/src/promise-utils";
import { SettingsMixinDeviceBase, SettingsMixinDeviceOptions } from "@scrypted/common/src/settings-mixin";
import sdk, { BufferConverter, Camera, DeviceManifest, DeviceProvider, FFmpegInput, HttpRequest, HttpRequestHandler, HttpResponse, MediaObject, MediaObjectOptions, MixinProvider, RequestMediaStreamOptions, RequestPictureOptions, ResponsePictureOptions, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera } from "@scrypted/sdk";
import sdk, { BufferConverter, Camera, DeviceManifest, DeviceProvider, FFmpegInput, HttpRequest, HttpRequestHandler, HttpResponse, MediaObject, MediaObjectOptions, MixinProvider, RequestMediaStreamOptions, RequestPictureOptions, ResponsePictureOptions, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, SettingValue, Settings, VideoCamera } from "@scrypted/sdk";
import { StorageSettings } from "@scrypted/sdk/storage-settings";
import axios, { AxiosInstance } from "axios";
import https from 'https';
import os from 'os';
import path from 'path';
import url from 'url';
import { ffmpegFilterImage, ffmpegFilterImageBuffer } from './ffmpeg-image-filter';
import { ImageConverter, ImageConverterNativeId } from './image-converter';
import { ImageReader, ImageReaderNativeId, loadSharp, loadVipsImage } from './image-reader';
import { ImageWriter, ImageWriterNativeId } from './image-writer';
import os from 'os';
const { mediaManager, systemManager } = sdk;
if (os.cpus().find(cpu => cpu.model?.toLowerCase().includes('qemu'))) {
@@ -217,30 +216,26 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
password = settings?.find(setting => setting.key === 'password')?.value?.toString();
}
let axiosClient: AxiosDigestAuth | AxiosInstance;
let credential: AuthFetchCredentialState;
if (username && password) {
axiosClient = new AxiosDigestAuth({
credential = {
username,
password,
});
}
else {
axiosClient = axios;
};
}
try {
const response = await axiosClient.request({
httpsAgent,
method: "GET",
responseType: 'arraybuffer',
const response = await authHttpFetch({
rejectUnauthorized: false,
url: this.storageSettings.values.snapshotUrl,
credential,
timeout: 60000,
headers: {
'Accept': 'image/*',
}
},
});
return response.data;
return response.body;
}
catch (e) {
return retryWithPrebuffer(e);
@@ -274,9 +269,10 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
async takePictureRaw(options?: RequestPictureOptions): Promise<Buffer> {
let picture: Buffer;
const eventSnapshot = options?.reason === 'event';
const periodicSnapshot = options?.reason === 'periodic';
try {
picture = await this.snapshotDebouncer({
const debounced = this.snapshotDebouncer({
id: options?.id,
reason: options?.reason,
}, eventSnapshot ? 0 : 2000, async () => {
@@ -288,6 +284,22 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
this.lastAvailablePicture = picture;
return picture;
});
// periodic snapshot should get the immediately available picture.
// the debounce has already triggered a refresh for the next go around.
if (periodicSnapshot && this.currentPicture) {
const cp = this.currentPicture;
debounced.catch(() => {});
try {
picture = await timeoutPromise(1000, debounced);
}
catch (e) {
picture = cp;
}
}
else {
picture = await debounced;
}
}
catch (e) {
// use the fallback cached picture if it is somewhat recent.
@@ -667,6 +679,7 @@ export class SnapshotPlugin extends AutoenableMixinProvider implements MixinProv
const mixin = this.mixinDevices.get(id);
let buffer: Buffer;
const rpo: RequestPictureOptions = {
reason: search.get('reason') as 'event' | 'periodic',
picture: {
width: parseInt(search.get('width')) || undefined,
height: parseInt(search.get('height')) || undefined,

View File

@@ -8,42 +8,39 @@
"name": "@scrypted/tapo",
"version": "0.0.11",
"dependencies": {
"axios": "^1.3.4",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"crc-32": "^1.2.2"
},
"devDependencies": {
"@koush/axios-digest-auth": "0.8.6",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.14.6",
"@types/node": "^20.10.8",
"ts-node": "^10.9.1"
}
},
"../../common": {
"name": "@scrypted/common",
"version": "1.0.1",
"dev": true,
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.2",
"dev": true,
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -110,25 +107,6 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@koush/axios-digest-auth": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/@koush/axios-digest-auth/-/axios-digest-auth-0.8.6.tgz",
"integrity": "sha512-e/XKs7/BYpPQkces0Cm4dUmhT9hR0rjvnNZAVRyRnNWdQ8cyCMFWS9HIrMWOdzAocKDNBXi1vKjJ8CywrW5xgQ==",
"dev": true,
"dependencies": {
"auth-header": "^1.0.0",
"axios": "^0.21.4"
}
},
"node_modules/@koush/axios-digest-auth/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/@scrypted/common": {
"resolved": "../../common",
"link": true
@@ -162,10 +140,13 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.14.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==",
"dev": true
"version": "20.10.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/acorn": {
"version": "8.8.2",
@@ -194,38 +175,6 @@
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/auth-header": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA==",
"dev": true
},
"node_modules/axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
@@ -243,14 +192,6 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@@ -260,68 +201,12 @@
"node": ">=0.3.1"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/ts-node": {
"version": "10.9.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
@@ -379,6 +264,12 @@
"node": ">=4.2.0"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",

View File

@@ -30,13 +30,12 @@
]
},
"dependencies": {
"axios": "^1.3.4",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"crc-32": "^1.2.2"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.14.6",
"@types/node": "^20.10.8",
"ts-node": "^10.9.1"
}
}

View File

@@ -1,9 +1,10 @@
import { Deferred } from '@scrypted/common/src/deferred';
import { authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { readLine } from '@scrypted/common/src/read-stream';
import { parseHeaders, readBody, readMessage, writeMessage } from '@scrypted/common/src/rtsp-server';
import axios from 'axios';
import crypto from 'crypto';
import { Duplex, PassThrough, Writable } from 'stream';
import { BufferParser, StreamParser } from '../../../server/src/http-fetch-helpers';
import { digestAuthHeader } from './digest-auth';
export function getTapoAdminPassword(cloudPassword: string, useSHA256: boolean) {
@@ -27,16 +28,19 @@ export class TapoAPI {
const url = `http://${options.address}/stream`;
// will fail with auth required.
const response = await axios({
const response = await authHttpFetch({
credential: undefined,
url: url,
ignoreStatusCode: true,
}, {
method: 'POST',
headers: {
'Content-Type': 'multipart/mixed; boundary=--client-stream-boundary--',
},
validateStatus(status) {
return status === 401;
},
});
}, BufferParser);
if (response.statusCode !== 401)
throw new Error('Expected 401 status code for two way audio init')
const wwwAuthenticate = response.headers['www-authenticate'];
const useSHA256 = wwwAuthenticate.includes('encrypt_type="3"');
@@ -45,20 +49,21 @@ export class TapoAPI {
const auth = digestAuthHeader('POST', '/stream', wwwAuthenticate, 'admin', password, 0) + ', algorithm=MD5';
const response2 = await axios({
const response2 = await authHttpFetch({
credential: undefined,
url: url,
}, {
method: 'POST',
headers: {
'Authorization': auth,
'Content-Type': 'multipart/mixed; boundary=--client-stream-boundary--',
},
responseType: "stream",
})
}, StreamParser)
const tapo = new TapoAPI();
tapo.keyExchange = response2.headers['key-exchange'];
tapo.stream = response2.data.socket;
tapo.stream.on('close', () => console.error('strema closed'));
tapo.keyExchange = response2.headers['key-exchange'] as string;
tapo.stream = response2.body.socket;
tapo.stream.on('close', () => console.error('stream closed'));
// this.stream.on('data', data => console.log('data', data));
// this.stream.resume();
return tapo;

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/webrtc",
"version": "0.2.3",
"version": "0.2.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/webrtc",
"version": "0.2.3",
"version": "0.2.4",
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
@@ -26,10 +26,11 @@
"@scrypted/server": "file:../server",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.10.8",
"ts-node": "^10.9.2"
}
},
"../../external/werift/packages/webrtc": {
@@ -83,12 +84,12 @@
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.68",
"version": "0.3.4",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
@@ -153,10 +154,11 @@
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^16.9.0",
"@types/node": "^20.10.8",
"http-auth-utils": "^3.0.2",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^4.4.3"
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
},
"@scrypted/sdk": {
@@ -166,7 +168,7 @@
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",

Some files were not shown because too many files have changed in this diff Show More