Compare commits

..

551 Commits
unifi ... libav

Author SHA1 Message Date
Koushik Dutta
dd3e7fe238 rebroadcast: improve cleanups 2025-04-11 21:38:43 -07:00
Koushik Dutta
b02c17e185 rebroadcast: beta 2025-04-11 16:23:44 -07:00
Koushik Dutta
6dee9b04df rebroadcast: update libav 2025-04-11 16:17:48 -07:00
Koushik Dutta
378fb41908 rebroadcast: update libav with new pipeline 2025-04-11 14:46:22 -07:00
Koushik Dutta
48f7208d55 Merge branch 'main' into libav 2025-04-11 14:22:23 -07:00
Koushik Dutta
d1bfed3019 install: make sure amd installer updates repos? 2025-04-10 20:35:37 -07:00
Koushik Dutta
6bf10d4aff install: update intel repos 2025-04-10 19:31:11 -07:00
Koushik Dutta
3ceef8ff87 install: update intel repos 2025-04-10 19:10:41 -07:00
Koushik Dutta
df1155cf82 postbeta 2025-04-10 10:52:51 -07:00
Koushik Dutta
453469ed98 server: implement sendStream backpressure handling 2025-04-10 10:52:42 -07:00
Koushik Dutta
2e4dbceb0e postbeta 2025-04-10 10:47:58 -07:00
Koushik Dutta
c620a4e126 server: ensure sendStream terminates on connection close 2025-04-10 10:47:48 -07:00
Koushik Dutta
5698551b7e common: fix h265 aggregation packet recency check 2025-04-09 15:33:50 -07:00
Koushik Dutta
9e655c0a53 postbeta 2025-04-09 09:37:54 -07:00
Koushik Dutta
35dadaab93 server: enable tcp keepalive for cluster 2025-04-09 09:37:45 -07:00
Koushik Dutta
71a93805ef Merge branch 'main' into libav 2025-04-09 09:13:53 -07:00
pir8radio
76487091da install: windows script requests elevation to to admin automatically (#1788)
let the script relaunch itself with admin privileges.  Can be a pain, when launching powershell as admin, you can't drag and drop the script into a powershell window.   This just makes it easier for people new to powershell.
2025-04-09 08:24:07 -07:00
Koushik Dutta
3c5b8bc940 common: fix h265 sei prefix vs suffix separation 2025-04-08 12:28:50 -07:00
Koushik Dutta
37e5c49729 github: remove router build 2025-04-08 10:45:50 -07:00
Koushik Dutta
16fc4407c1 use mime rather than send 2025-04-08 09:00:51 -07:00
Koushik Dutta
3e76c1b1d3 snapshot: remove audio feed in prebuffer request 2025-04-08 08:32:59 -07:00
Koushik Dutta
4880c18c48 Merge remote-tracking branch 'origin/libav' into libav 2025-04-08 08:32:22 -07:00
Koushik Dutta
198d4808cb Merge branch 'main' into libav 2025-04-08 08:32:04 -07:00
Koushik Dutta
ef8f4ba9b8 Merge branch 'main' into libav 2025-04-07 15:27:02 -07:00
Koushik Dutta
d6c6e3c594 install: fix macos install 2025-04-07 10:55:54 -07:00
apocaliss92
6c904da49b reolink: Add locallink endpoint (#1782)
* Add API to check wifi connectivity

* Comment removed

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-04-07 08:30:58 -07:00
Koushik Dutta
6ac790f824 webhook: prevent enable on internal types, fixup code to not require mixin existence 2025-04-07 08:17:38 -07:00
Koushik Dutta
3638f80cef mqtt: prevent enable on internal types 2025-04-07 08:17:23 -07:00
Koushik Dutta
809b632417 server: add more cluster logging 2025-04-05 14:07:35 -07:00
Koushik Dutta
f53330c861 webrtc: improve sending codec information only after a marker packet 2025-04-05 10:00:12 -07:00
Koushik Dutta
66455c8f01 rebroadcast: fix bug where stream may be started on fragmented key frame 2025-04-05 09:57:21 -07:00
Koushik Dutta
e6eb61f04f webrtc: more h265 packetizer fixes 2025-04-04 22:48:51 -07:00
Koushik Dutta
adeb3d837e Merge branch 'main' of github.com:koush/scrypted 2025-04-04 15:58:05 -07:00
Koushik Dutta
3da3f85513 webrtc: fix h265 packetizer ap resent for chrome 2025-04-04 15:58:00 -07:00
Koushik Dutta
cbe251e345 docker: bump node to 22 2025-04-04 12:18:59 -07:00
Koushik Dutta
dfa2dacde4 postbeta 2025-04-04 11:40:16 -07:00
Koushik Dutta
9395253b50 server: more express 5.0 fixes 2025-04-04 11:40:04 -07:00
Koushik Dutta
e020ee1517 server: fix breakage caused by path-to-regexp updates 2025-04-04 11:39:03 -07:00
Koushik Dutta
a7ecb9b5e5 postbeta 2025-04-04 11:39:03 -07:00
Koushik Dutta
24f9b0fca3 postbeta 2025-04-04 11:39:03 -07:00
Koushik Dutta
a78ad99f50 server: update deps 2025-04-04 11:39:03 -07:00
Koushik Dutta
c26c5e94a4 server: fix type error in createRpcIoPeer 2025-04-04 11:38:55 -07:00
Koushik Dutta
2d93a69c91 homekit/rebroadcast: fix prebuffer calculation, remove prebuffer warning 2025-04-02 22:12:12 -07:00
Koushik Dutta
1c52297e74 sdk: remove legacy flush/queued from VideoFrame 2025-04-02 20:58:25 -07:00
Koushik Dutta
5bc76642cc webrtc: fix ice restart 2025-04-02 20:57:37 -07:00
Koushik Dutta
15fa27029d webrtc: update werift with connection related hang fixes 2025-04-02 12:34:50 -07:00
Koushik Dutta
553678ed1a rebroadcast: Fix cluster addresses not being used 2025-04-02 12:33:45 -07:00
Koushik Dutta
b3b7265263 rebroadcast: wipe acodec arguments if encoder arguments are explicitly provided 2025-04-01 20:51:07 -07:00
Koushik Dutta
d87d9bb751 rebroadcast: wip libav 2025-04-01 11:09:57 -07:00
Koushik Dutta
301213fc5f rebroadcast: remove dead code 2025-03-31 11:07:28 -07:00
Koushik Dutta
da393ae4e0 rebroadcast: ensure audio mute/no audio is in sync 2025-03-31 10:57:09 -07:00
Koushik Dutta
9376fc4ba6 common: fixup codec info in packet delivery 2025-03-28 12:58:32 -07:00
Koushik Dutta
51d4aa7b3e sdk: update 2025-03-27 09:38:28 -07:00
Koushik Dutta
30334e5bd0 webrtc: support for alternateCodecs and codec switching 2025-03-26 23:58:21 -07:00
Koushik Dutta
dffc05d165 external: update werift 2025-03-26 19:40:45 -07:00
Koushik Dutta
172e5b3ccb sdk: add codec switch hint 2025-03-25 16:15:51 -07:00
Koushik Dutta
cad60e7730 webrtc/common: fix sdp construction when audio is sideband copied. maybe get rid of this process? 2025-03-25 09:08:46 -07:00
Koushik Dutta
131458576c webrtc: fix handshake negotiation resetting the sender 2025-03-24 20:41:16 -07:00
Koushik Dutta
0d7b47e1e9 webrtc: update 2025-03-22 20:56:56 -07:00
Koushik Dutta
1a33384115 webrtc: fixup h265 keyframe hunting 2025-03-21 23:51:24 -07:00
Koushik Dutta
1fa5f66b44 Merge branch 'main' of github.com:koush/scrypted 2025-03-21 23:21:24 -07:00
Koushik Dutta
1032d444fb google-home: fix build 2025-03-21 23:19:52 -07:00
Koushik Dutta
2883824690 webrtc: add alternate codecs 2025-03-21 19:32:51 -07:00
Koushik Dutta
a505394852 sdk: add audio request hints 2025-03-21 19:22:59 -07:00
Koushik Dutta
1240f401d7 alexa: clean up removed devices 2025-03-21 08:08:27 -07:00
Koushik Dutta
b49faaa033 webrtc: fix rtcp pli from browser 2025-03-20 23:24:37 -07:00
Koushik Dutta
cbb1d4533a vscode-typescript: update sample 2025-03-20 23:24:18 -07:00
Koushik Dutta
a5a027bd6d ncnn: doc flags 2025-03-20 22:30:29 -07:00
Koushik Dutta
94acd0e800 unifi-protect: Fixup codec reporting 2025-03-19 13:19:20 -07:00
Koushik Dutta
cabdd91a92 unifi-protect: update sdk 2025-03-19 13:14:36 -07:00
Koushik Dutta
93c9b62e87 common: disposable queue 2025-03-19 09:11:15 -07:00
Koushik Dutta
21c771d50f common: deferred dispose 2025-03-18 19:08:34 -07:00
Koushik Dutta
bb2ecd7bd8 reolink: fix optional chaining for mainEncType 2025-03-18 11:57:02 -07:00
apocaliss92
6c0864b883 reolink: Disable siren polling (#1774)
Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-03-18 11:54:33 -07:00
Koushik Dutta
3c8ef7a2cf core: publiush 2025-03-18 09:14:21 -07:00
Koushik Dutta
6afecc8185 homekit: workaround homekit requesting low resolution streams 2025-03-17 10:42:16 -07:00
Koushik Dutta
ea16381b7a homekit: build fixes 2025-03-17 10:19:55 -07:00
Koushik Dutta
09d3ac587f webrtc: publish h265 support 2025-03-16 23:31:05 -07:00
Koushik Dutta
3872cb391a rebroadcast: publish with h265 parsing fixes 2025-03-16 23:22:39 -07:00
Koushik Dutta
7d985937ca webrtc: send desired codecs 2025-03-16 21:16:09 -07:00
Koushik Dutta
cef8482b93 sdk: partial revert of ffmpeg input changes 2025-03-16 19:52:47 -07:00
Koushik Dutta
f729c76346 various: remove defunct ffmpeg args 2025-03-16 19:09:40 -07:00
Koushik Dutta
9aa9498aae sdk: video stream negotiation cleanups 2025-03-16 18:56:48 -07:00
Koushik Dutta
afe832a32a webrtc: h265 beta, requires new nvr plugin or nvr will break 2025-03-15 23:23:35 -07:00
Koushik Dutta
be6a81c9a2 common: fix h265 agg parsing 2025-03-15 22:21:41 -07:00
Koushik Dutta
964bb27d48 common: fix h265 idr seeking 2025-03-15 22:00:24 -07:00
Koushik Dutta
6bca83b338 webrtc: provide h265 hint when available 2025-03-15 17:12:23 -07:00
Koushik Dutta
11860409f1 snapshot: fix h265 prebuffer snapshot 2025-03-15 16:32:00 -07:00
Koushik Dutta
6743f76e09 webrtc: wip h265 2025-03-15 16:24:48 -07:00
Koushik Dutta
771d90ea73 rebroadcast: publish 2025-03-15 08:11:39 -07:00
Koushik Dutta
ba28899dc3 rebroadcast: beta 2025-03-15 00:52:44 -07:00
Koushik Dutta
3e57c90208 rebroadcast: fix mixin order 2025-03-15 00:52:07 -07:00
Koushik Dutta
e155584373 reolink: publish 2025-03-13 21:12:08 -07:00
Koushik Dutta
4a3968956e snapshot: publish 2025-03-13 21:11:07 -07:00
Koushik Dutta
78c259d14e hikvision: light/alarm 2025-03-13 21:10:12 -07:00
Koushik Dutta
6f4b360d2a nanokvm: persist settings from device creation 2025-03-13 15:27:39 -07:00
Koushik Dutta
642795dd9d nanokvm: ip hint 2025-03-13 15:26:39 -07:00
Koushik Dutta
4b3d37b628 nanokvm: heartbeat 2025-03-13 15:22:33 -07:00
Koushik Dutta
8e28e6d19e nanokvm: fixup keywords 2025-03-13 11:29:25 -07:00
Koushik Dutta
d13171551d nanokvm: readme 2025-03-13 11:28:16 -07:00
Koushik Dutta
ea1474c21e nanokvm: publish 2025-03-13 11:22:41 -07:00
Koushik Dutta
7abff3a91b nanokvm: fixup modifiers 2025-03-13 11:14:50 -07:00
Koushik Dutta
40f11a0053 nanokvm: remove logging 2025-03-13 10:48:42 -07:00
Koushik Dutta
1d3450455b core: publish 2025-03-13 10:13:38 -07:00
Koushik Dutta
bd3b4ac387 client: publish 2025-03-13 10:12:56 -07:00
Koushik Dutta
6787153c30 nanokvm: initial commit 2025-03-13 10:05:15 -07:00
Koushik Dutta
7024daba53 sdk: kvm input 2025-03-12 16:32:57 -07:00
Koushik Dutta
28a2e0d898 sdk: shim for es modules 2025-03-12 10:13:19 -07:00
Koushik Dutta
a7757a9a54 docker: bump node version 2025-03-12 10:03:42 -07:00
Koushik Dutta
84fc40e1e5 postbeta 2025-03-12 09:46:36 -07:00
Koushik Dutta
b3b8f6bc70 server: remove eseval 2025-03-12 09:46:28 -07:00
Koushik Dutta
7962606a2b postbeta 2025-03-12 09:32:31 -07:00
Koushik Dutta
9c2ea7d2bc server: another attempt at node/esmodule interop with tsc 2025-03-12 09:32:20 -07:00
Koushik Dutta
4e653a9942 Revert "server: fixup es-eval"
This reverts commit 51836ca59f.
2025-03-12 09:19:29 -07:00
Koushik Dutta
167db0f11a router: usbmuxd persistence 2025-03-12 09:07:04 -07:00
Koushik Dutta
49064de767 postbeta 2025-03-12 09:01:21 -07:00
Koushik Dutta
51836ca59f server: fixup es-eval 2025-03-12 09:01:12 -07:00
Koushik Dutta
d64ed629b0 router: install usbmuxd for iphone tethering 2025-03-11 23:40:01 -07:00
Koushik Dutta
83a9ad2250 rebroadcast: reorder mixin order for regular (ie, non webrtc) cameras to be first to prevent stream flapping due to mixin change noise 2025-03-11 15:24:40 -07:00
Koushik Dutta
7f9358a3b5 webrtc: fix potential webrtc camera thread leak 2025-03-11 14:45:30 -07:00
Koushik Dutta
9cf3d6c912 webrtc: leak and crash fixes 2025-03-11 14:41:51 -07:00
Koushik Dutta
5e3d1c423c common: build fixes 2025-03-11 10:05:24 -07:00
Koushik Dutta
64fa68f2d0 core: publish 2025-03-11 10:05:12 -07:00
Koushik Dutta
45cc859636 router: enable all ip forwarding, install coturn 2025-03-10 11:27:28 -07:00
Koushik Dutta
1984bb44ba router: enable all ip forwarding, install coturn 2025-03-10 11:24:37 -07:00
Koushik Dutta
1164e4b15b router: ipv6 forwarding 2025-03-10 00:43:58 -07:00
Koushik Dutta
9e5fbc5251 postbeta 2025-03-09 19:54:38 -07:00
Koushik Dutta
6f52390067 Merge branch 'main' of github.com:koush/scrypted 2025-03-09 19:54:09 -07:00
Koushik Dutta
d34afab6a4 server: ensure proper ip type checking 2025-03-09 19:53:36 -07:00
Koushik Dutta
2edc74f75b postbeta 2025-03-09 10:13:56 -07:00
Koushik Dutta
e913131f90 server: log denied address 2025-03-09 10:13:43 -07:00
Koushik Dutta
bca752addb postbeta 2025-03-09 09:55:16 -07:00
Koushik Dutta
43fc6c9fc9 server: fix address check 2025-03-09 09:54:48 -07:00
Koushik Dutta
448e2c4e6e router: fix names 2025-03-08 23:51:15 -08:00
Koushik Dutta
625ea7981e router: fix paths 2025-03-08 23:32:58 -08:00
Koushik Dutta
1be806eb8e docker: add router builds 2025-03-08 23:31:10 -08:00
Koushik Dutta
e4b71ffbd4 postbeta 2025-03-08 23:16:51 -08:00
Koushik Dutta
16f4cafea3 server: fix listen sets to listen all and reject on unauthorized address 2025-03-08 23:16:42 -08:00
Koushik Dutta
f78df27341 ncnn: initial commit 2025-03-08 14:08:53 -08:00
Koushik Dutta
57d4e4b9bd core: publish 2025-03-07 21:20:42 -08:00
Koushik Dutta
cb1c062b5e core: publish 2025-03-07 21:19:07 -08:00
Koushik Dutta
e3b996562c Merge branch 'main' of github.com:koush/scrypted 2025-03-07 21:11:22 -08:00
Koushik Dutta
c96bf237b5 core: publish 2025-03-07 21:11:20 -08:00
apocaliss92
5bde86fd15 hikvision: Ptz + presets implemented (#1764)
* Hikvision: Ptz + presets implemented

* Sweeter ptz commands

* Presets fetching

* Capabilities used to enable PTZ

* Redundant call removed

* Logs removed

* Variable moved

* Revert some async changes

* Persist hasPtz

* Move alarm and light to same block

* Log removed

* Fix ptz presets selection

* never disable ptz

* Make devices and ptz caps user-selectable

* undefined check for presets result

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-03-07 19:31:20 -08:00
Koushik Dutta
5075920308 postbeta 2025-03-05 08:34:16 -08:00
Koushik Dutta
9e4845b868 server: allow interface name in SCRYPTED_CLUSTER_ADDRESS 2025-03-05 08:34:05 -08:00
Koushik Dutta
0cab8f2faf core: fix buikd 2025-03-04 20:52:32 -08:00
Koushik Dutta
510321b7d6 postbeta 2025-03-04 19:46:46 -08:00
Koushik Dutta
efb0a39e52 server: fixup SCRYPTED_SERVER_LISTEN_HOSTNAMES 2025-03-04 19:46:13 -08:00
Koushik Dutta
467d89ccaf postbeta 2025-03-04 18:58:40 -08:00
Brett Jia
19832c9537 python: partial repl reimplementation (#1763)
* python: partial repl reimplementation

* make more readable?

* document questionable design choices
2025-03-04 14:37:55 -08:00
Koushik Dutta
0b24e57262 sdk: cleanup peer dependencies 2025-03-04 10:00:40 -08:00
Koushik Dutta
f406969140 sdk: remove col1/2 for description 2025-03-04 09:35:32 -08:00
Koushik Dutta
4db26a1779 sdk: relax types 2025-03-04 08:15:32 -08:00
Koushik Dutta
bfc82d0010 sdk: network types 2025-03-03 19:05:47 -08:00
Koushik Dutta
df3a3d279c router: fix file path 2025-03-03 10:53:33 -08:00
Koushik Dutta
bb7f2a0c9b postbeta 2025-03-03 10:38:28 -08:00
Koushik Dutta
3f83d4b8f7 server: improve plugin kill race conditions on update 2025-03-03 10:38:18 -08:00
Koushik Dutta
779fa1df9c Merge branch 'main' of github.com:koush/scrypted 2025-03-03 09:43:56 -08:00
Koushik Dutta
1c08313e8b server: cleanup runtime worker hooks 2025-03-03 09:43:51 -08:00
root
64e8dc2cc9 router: fix nft flush 2025-03-03 17:42:47 +00:00
Koushik Dutta
1914fa60ea router: file naming consistency 2025-03-03 08:39:25 -08:00
Koushik Dutta
8073a80bae router: typo 2025-03-03 08:28:26 -08:00
Koushik Dutta
cd7d45155f proxmox: fixup confusion around reset script and storage 2025-03-03 08:00:38 -08:00
Koushik Dutta
6f6ccff5b1 server: missing dhcp client 2025-03-03 07:55:48 -08:00
Koushik Dutta
4ea8049d22 server: additional service files 2025-03-03 07:55:02 -08:00
Koushik Dutta
8354564157 postbeta 2025-03-02 18:50:14 -08:00
Koushik Dutta
26518f0693 server: reduced listening address set 2025-03-02 18:48:01 -08:00
Koushik Dutta
72df40c422 postbeta 2025-03-02 15:02:45 -08:00
Koushik Dutta
fe1b677381 server: limit address binding in cluster mode 2025-03-02 14:57:56 -08:00
Koushik Dutta
16a9abeb9e Merge branch 'main' of github.com:koush/scrypted 2025-02-28 21:05:08 -08:00
Koushik Dutta
ba07aa7765 router: caddy 2025-02-28 21:05:04 -08:00
apocaliss92
35e508a01e snapshot: Allow sleeping cameras to have longer lived snapshots (#1747)
Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-27 22:30:30 -08:00
apocaliss92
1e709a058d reolink: Add polling to reolink discovered devices (#1744)
* Add polling to reolink discovered devices

* Don't poll battery devices

* Logic moved to forever cycle

* Poll battery devices only when they wake up

* Wrap each poll in try/catch

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-27 22:29:12 -08:00
Mehmet Bayram
f5a4bab0a8 hikvision: Improve handling of supplemental light and alarm (#1739)
* hikvision: Remove settings from alarm switch
Dynamically choose supplemental light mode
Rename floodlight to supplemental light
Prevent child device removal if no devices detected
Report devices when settings are saved
Remove unused functions

* fix: push DeviceProvider interface

* hikvision: Add README support to Alarm Switch and update interfaces

* hikvision: add device release method

* hikvision: add IP check before accessing alarm and light capabilities

* hikvision: Centralize alarm activation logic
2025-02-27 22:28:24 -08:00
Koushik Dutta
e373a3935e router: fixup policies 2025-02-26 19:15:46 -08:00
Koushik Dutta
f9f9762046 docker: router shuffling 2025-02-26 11:20:35 -08:00
Koushik Dutta
4b6751785c Merge branch 'main' of github.com:koush/scrypted 2025-02-25 21:14:20 -08:00
Koushik Dutta
133cbcf5f5 sdk: add col 2025-02-25 21:14:14 -08:00
LV Nilesh
817c171757 docker: update BASE (#1748)
https://github.com/koush/scrypted/pull/1745#issuecomment-2677176155
2025-02-25 09:04:36 -08:00
LV Nilesh
9af9359b26 docker: Update Dockerfile.full.header (#1749) 2025-02-25 09:04:17 -08:00
Koushik Dutta
b684ced629 install: nftables 2025-02-23 18:54:58 -08:00
apocaliss92
977db49f87 reolink: Add optional chain to live check (#1746)
Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-22 23:53:13 -08:00
Koushik Dutta
992fe98f5e core/sdk: update 2025-02-22 19:39:08 -08:00
Koushik Dutta
a74157168e sdk: update 2025-02-22 14:20:55 -08:00
Koushik Dutta
0eed5241f0 sdk: update 2025-02-22 14:20:00 -08:00
Koushik Dutta
c0680736e7 sdk: update 2025-02-21 19:25:41 -08:00
Koushik Dutta
c345f173d2 docker: set SHELL 2025-02-21 08:25:06 -08:00
Koushik Dutta
1ed10cd1cb sdk: radio support 2025-02-20 12:06:51 -08:00
Koushik Dutta
9426db12aa client/server: update deps 2025-02-19 14:56:53 -08:00
Koushik Dutta
a35e821f79 intall: router dockerfile updates 2025-02-19 14:56:39 -08:00
Koushik Dutta
983794d5d0 plugins: remove usage of builtin in favor of internal 2025-02-19 14:56:00 -08:00
Koushik Dutta
cd3e2340b8 rebroadcast: most camera plugins depend on this, so ensure snapshot and webrtc are downloaded as well 2025-02-19 14:55:32 -08:00
Koushik Dutta
bb82eb6bde sdk: Update 2025-02-19 14:28:56 -08:00
Koushik Dutta
5006bb90fc postbeta 2025-02-18 13:53:13 -08:00
Koushik Dutta
7134ef114a server: fixup staged cleanup 2025-02-18 13:53:03 -08:00
Koushik Dutta
2f5b1f6526 postbeta 2025-02-18 13:46:21 -08:00
Koushik Dutta
f88f0a25db server: try staged cleanup 2025-02-18 13:46:11 -08:00
Koushik Dutta
d2810b09ed docker: lite/systemd test 2025-02-17 23:06:33 -08:00
Koushik Dutta
f103ddf660 openvino: fix npu/gpu crashes caused by dynamic input sizes 2025-02-16 15:32:02 -08:00
Koushik Dutta
47edffa56d openvino: regenerate face embedding model 2025-02-16 11:50:05 -08:00
Koushik Dutta
86a5a73276 openvino: workaround for npu crash https://github.com/openvinotoolkit/openvino/issues/29003#issuecomment-2660865184 2025-02-15 08:17:02 -08:00
Koushik Dutta
1a47015558 openvino: more precise npu usage 2025-02-14 11:58:57 -08:00
Koushik Dutta
0de9812760 videoanalysis: fix zone names with hyphens 2025-02-14 11:46:36 -08:00
Koushik Dutta
10d16dab21 hikvision: remove dead code/ 2025-02-14 09:05:38 -08:00
Koushik Dutta
f3f4bbc77f hikvision-doorbell: fix buikd 2025-02-13 13:54:42 -08:00
Koushik Dutta
029f788407 hikvision: cleanup 2025-02-12 21:55:13 -08:00
Mehmet Bayram
89b93eb2f4 hikvision: Add Supplemental Light & Alarm Support to Hikvision Plugin (#1737)
* feat: add supplemental light control for Hikvision cameras

* Add supplemental light control as device

* Add alarm switch with audio/light alarm settings

* Get alarm trigger configuration and capabilities for audio and white light alarms

* Simplify alarm settings retrieval
2025-02-12 21:24:38 -08:00
Koushik Dutta
6fd35e54e6 openvino: rollback openvino 2025-02-12 15:36:57 -08:00
Koushik Dutta
118c404525 sdk: fix and publish 2025-02-12 15:01:49 -08:00
Koushik Dutta
833ecb721f tensorflow-lite: pass through forked flag 2025-02-12 13:39:55 -08:00
Koushik Dutta
a8f1e74278 tensorflow-lite: pass through forked flag 2025-02-12 13:38:18 -08:00
apocaliss92
1075fb4491 sdk: Sensors interface (#1731)
* Sensors interface

* Sensors as mapping type

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-12 13:02:25 -08:00
Koushik Dutta
f09a797ebf core: publish with ui fixes 2025-02-12 09:55:56 -08:00
Koushik Dutta
1e0fdee7b6 Merge branch 'main' of github.com:koush/scrypted 2025-02-12 09:29:15 -08:00
Koushik Dutta
be6375e9f4 tensorflow-lite: add cluster aware 2025-02-12 09:28:06 -08:00
apocaliss92
e5ba39f886 reolink: Forward battery cams detections (#1730)
* Reolink: Forward battery cams detections

* Used right return

* log removed

* use ability to determine events source

* Reuse same branching for events

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-11 11:43:31 -08:00
Brett Jia
6841b74a26 core: exit terminal's subprocess on generator end (#1733) 2025-02-10 16:18:21 -08:00
Koushik Dutta
a3f45e2c49 predict: favor ipv4 for file downloads 2025-02-10 09:14:34 -08:00
Koushik Dutta
b664ccd24f Update install-scrypted-proxmox.sh 2025-02-09 12:00:18 -08:00
Koushik Dutta
3f244b586f install: fix broken intel runtime installer 2025-02-09 11:24:33 -08:00
Koushik Dutta
9f828739de install: update intel libs 2025-02-09 09:08:46 -08:00
Koushik Dutta
b2cef35bc0 openvino: beta with latest 2025-02-09 09:02:02 -08:00
Koushik Dutta
3e54540db7 webrtc: update werift for chrome 132 compatibility 2025-02-08 17:51:04 -08:00
Koushik Dutta
debd7f2c40 onvif: fix onvif ptz with onvif plugin cams 2025-02-08 09:43:29 -08:00
Koushik Dutta
adbc2aaed9 onvif: add text overlays 2025-02-08 09:41:48 -08:00
Koushik Dutta
6024b4ceaf reolink/hikvision: publish 2025-02-08 08:26:28 -08:00
apocaliss92
3a065febb5 hikvision: fix get/patch osd settings (#1728)
Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-08 08:23:24 -08:00
apocaliss92
1e2c3e0ca7 reolink: Add pir sensor device (#1729)
* Reolink: Add pir sensor device

* Reolink: add siren to hub cameras

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-08 08:23:07 -08:00
Koushik Dutta
61dfddeab2 Create config.yml 2025-02-07 22:02:39 -08:00
Koushik Dutta
b902873d44 hikvision: overlay support 2025-02-07 20:14:14 -08:00
Koushik Dutta
a38d803b86 reolink: overlay support 2025-02-07 13:58:25 -08:00
Koushik Dutta
9c3dab18da sdk/client/server/core/amcrest: add support for video text overlays 2025-02-07 13:07:55 -08:00
Koushik Dutta
2ceb2cd9c3 alexa: maybe fix alexa when no detection types are available 2025-02-05 12:49:04 -08:00
Koushik Dutta
a5fd1c0278 postbeta 2025-02-05 12:09:25 -08:00
Koushik Dutta
2c717cb4fc postrelease 2025-02-05 12:09:03 -08:00
Koushik Dutta
df10c4e5f2 server: fixup address, make it available on cluster manager 2025-02-05 12:08:50 -08:00
Koushik Dutta
7c51bb420e postbeta 2025-02-05 11:51:38 -08:00
Koushik Dutta
367eafff5c postrelease 2025-02-05 11:51:26 -08:00
Koushik Dutta
adcdd18497 server: add cluster worker address 2025-02-05 11:51:07 -08:00
Koushik Dutta
a95b77fe26 sdk: add cluster worker address 2025-02-05 11:49:26 -08:00
Koushik Dutta
3ff75f0fde postbeta 2025-02-05 08:01:46 -08:00
Koushik Dutta
eecd38d271 postrelease 2025-02-05 08:01:39 -08:00
Koushik Dutta
7128af20af postbeta 2025-02-04 19:23:00 -08:00
Koushik Dutta
c651c2164b server: fixup cluster worker hook 2025-02-04 19:22:49 -08:00
Koushik Dutta
6caafd73f5 postbeta 2025-02-04 19:19:38 -08:00
Koushik Dutta
05cb505783 server: hook cluster creation for electron 2025-02-04 19:19:30 -08:00
Koushik Dutta
07baddc9c3 sdk: update detection properties 2025-02-04 13:59:39 -08:00
Koushik Dutta
76ac260bf7 hikvision: fix unhandled rejection parsing camera object detection 2025-02-04 07:45:36 -08:00
Koushik Dutta
dfee7c6b09 Merge branch 'main' of github.com:koush/scrypted 2025-02-04 07:37:46 -08:00
Koushik Dutta
b3ce6a2af3 postbeta 2025-02-04 07:37:15 -08:00
Koushik Dutta
933c0cac0f postrelease 2025-02-04 07:37:02 -08:00
apocaliss92
1fb1334a00 snapshot: Sleeping cameras should not wake for periodic snapshots (#1718)
* Preserve battery on snapshots

* Don't force snapshot below 1 min

* Online interface changes

* Pr comments fix

* Interval removed

* Debounce restored

* Branching fixes

* Fix isBattery leftover

* Remove prebuffer check

* Remove comment

* Remove unused import

* Use Sleep interface

* Disable default prebuffer for Sleep devices

* Rollback default changes

* Unused import removed

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-03 10:55:58 -08:00
apocaliss92
cb45a00c25 reolink: Battery cams api fixes (#1719)
* Battery cams api fixes

* Update with new Sleep class

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-02-03 08:51:45 -08:00
Koushik Dutta
fec59af263 core: support cluster fork for terminal 2025-02-02 22:34:44 -08:00
Koushik Dutta
5d213a4c51 Merge branch 'main' of github.com:koush/scrypted 2025-02-02 22:33:28 -08:00
Koushik Dutta
d444c4ab7c sdk: update 2025-02-02 22:33:23 -08:00
Brett Jia
590f955ca9 core: terminalservice fork across cluster (#1721)
* core: terminalservice fork across cluster

* exit cluster fork on completion

* force terminate on errors

* make isClusterFork internal to prevent callers from killing core plugin

* implement forkInterface and share forks

* use correct native id

* use correct native id in primary device construction
2025-02-01 22:33:29 -08:00
Koushik Dutta
7df4bf2723 postbeta 2025-02-01 19:28:40 -08:00
Brett Jia
3416347a1f server/python: fix hash calculation (#1720) 2025-02-01 19:28:17 -08:00
Koushik Dutta
c669bb8902 snapshot: do not wake sleeping cameras for periodic snapshots 2025-02-01 10:51:46 -08:00
Koushik Dutta
ce5fd2d4fd Merge branch 'main' of github.com:koush/scrypted 2025-01-31 20:14:00 -08:00
Koushik Dutta
fa8a756059 sdk: critical alerts 2025-01-31 20:13:58 -08:00
apocaliss92
73b85e1cd0 homekit: Fix autoadd (#1716)
Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-01-31 14:49:12 -08:00
Koushik Dutta
1300073712 videoanalysis: publish audio sensor 2025-01-29 11:18:19 -08:00
Koushik Dutta
3e296e12a5 core: publish audio sensor ui 2025-01-29 11:11:19 -08:00
Koushik Dutta
bf98060a08 videoanalysis: fixup noisy startup 2025-01-29 11:02:13 -08:00
Koushik Dutta
d1cd380123 videoanalysis: initial implemnetation of audio sensor 2025-01-29 10:39:10 -08:00
Koushik Dutta
1a2aadfb52 rebroadcast: fix audio soft mute with adaptive bitrate and other downstream clients 2025-01-29 08:48:55 -08:00
Koushik Dutta
60c854a477 ha: publish beta 2025-01-27 13:08:45 -08:00
Koushik Dutta
0790b60122 postbeta 2025-01-27 13:03:14 -08:00
Koushik Dutta
a3caa09df4 server: fixup node modules search path on HA 2025-01-27 13:03:06 -08:00
Koushik Dutta
02ca8bd765 reolink: publish 2025-01-27 11:48:51 -08:00
apocaliss92
f9e1a94ab3 reolink: support additional trackmix (#1711)
* Add support for Trackmix Series W760

* settings restored

* Settings restored

---------

Co-authored-by: Gianluca Ruocco <gianluca.ruocco@xarvio.com>
2025-01-27 11:45:52 -08:00
Koushik Dutta
dd0da26df3 ha: publish 2025-01-27 11:44:57 -08:00
Koushik Dutta
890f2e8daf postbeta 2025-01-26 22:26:56 -08:00
Koushik Dutta
2c8babe3ce postrelease 2025-01-26 22:26:48 -08:00
Koushik Dutta
8e31b5f970 homekit: fixup exports, publish 2025-01-24 10:52:26 -08:00
Nick Berardi
0873a72848 homekit: moved humidity settings to common and added characteristics to expose settings Home Assistant (#1699) 2025-01-24 10:51:28 -08:00
Koushik Dutta
145c66e1c8 doorbird: publish 2025-01-24 10:15:04 -08:00
r3dDoX
2b60b45113 doorbird: update underlying doorbird api package (#1705) 2025-01-24 10:12:51 -08:00
Koushik Dutta
6f63927e2f core: publish 2025-01-23 19:34:41 -08:00
Koushik Dutta
528eabdfc0 sdk: improve StorageSettings deviceFilter 2025-01-23 19:33:42 -08:00
Koushik Dutta
e201ea1fc1 doorbird: fix build 2025-01-23 13:11:31 -08:00
Koushik Dutta
7790810b86 server: cleanup launch.json 2025-01-23 09:23:13 -08:00
Koushik Dutta
e9ec78909b core: Fix missing buttons 2025-01-22 13:46:38 -08:00
Koushik Dutta
26245e17ca core: publish button support 2025-01-22 13:22:49 -08:00
Koushik Dutta
5d87a1b2dd sdk: PressButtons 2025-01-22 12:57:27 -08:00
Koushik Dutta
e1efde3868 postbeta 2025-01-22 12:00:35 -08:00
Koushik Dutta
525eb028c6 sdk: Buttons interface 2025-01-22 10:14:42 -08:00
Koushik Dutta
520c6a62a1 Merge branch 'main' of github.com:koush/scrypted 2025-01-21 13:48:43 -08:00
Koushik Dutta
6e6898ce33 common/rebroadcast: change rtp packet size to 32000 since that is what is supported on darwin for some reason 2025-01-21 13:48:38 -08:00
Koushik Dutta
1344c9112c server: fixup potential unhandled errors in sdk fork 2025-01-21 09:50:44 -08:00
Koushik Dutta
f2148ce26a hikvision: publish 2025-01-20 19:37:37 -08:00
Koushik Dutta
81b00195d6 Merge branch 'main' of github.com:koush/scrypted 2025-01-20 19:36:58 -08:00
Koushik Dutta
8f71778f05 core: publish 2025-01-20 19:36:54 -08:00
George Talusan
2e5b8d90aa hikvision: add ERI-K104-P4 to the list of NVRs that doesn't support channel cap checks (#1698) 2025-01-19 00:32:36 -08:00
Koushik Dutta
780182b94a fix npm-install.sh 2025-01-18 15:04:59 -08:00
Brett Jia
57480f7606 actions: add Linux arm64 runner to tests (#1696) 2025-01-17 16:50:35 -08:00
Koushik Dutta
1478684120 Update install-nvidia-container-toolkit.sh 2025-01-17 14:58:45 -08:00
Koushik Dutta
223b302bed core: publish new ui with lxc-docker update fix 2025-01-16 13:28:28 -08:00
Koushik Dutta
f56cef1b50 postbeta 2025-01-16 12:04:53 -08:00
Koushik Dutta
83bfa30d4b server: improve abi/server change detection 2025-01-16 12:04:43 -08:00
Koushik Dutta
611674af46 rebroadcast: publish 2025-01-16 08:24:01 -08:00
Koushik Dutta
941ea7f346 Update bug_report.md 2025-01-16 08:06:59 -08:00
Koushik Dutta
2b9c2956d6 Update bug_report.md 2025-01-16 08:05:28 -08:00
Koushik Dutta
266d5bf8a3 Update bug_report.md 2025-01-16 07:19:41 -08:00
Koushik Dutta
d0007fc7bb postbeta 2025-01-15 14:53:20 -08:00
Koushik Dutta
75f90b78eb postrelease 2025-01-15 14:53:20 -08:00
Simon Marty
1e8959413e Fix path in comment (#1694) 2025-01-15 14:43:37 -08:00
Koushik Dutta
1301247ea3 docker: update base version 2025-01-15 14:41:56 -08:00
Koushik Dutta
2798fe4d3d server: document insane synology bug. 2025-01-15 14:40:18 -08:00
Koushik Dutta
55a76a86dc rebroadcast: fixup output args example 2025-01-14 12:51:34 -08:00
Koushik Dutta
cebd49fadb Update config.yaml 2025-01-09 03:49:40 -08:00
Koushik Dutta
90adb11f27 Update config.yaml 2025-01-08 20:37:59 -08:00
Koushik Dutta
cea5c95c82 dummy-switch: select which interfaces to implement 2025-01-08 00:21:58 -08:00
Koushik Dutta
0405e13181 videoanalysis: fix zone math 2025-01-07 23:48:14 -08:00
Koushik Dutta
5659499c16 videoanalysis: simplify normalization 2025-01-07 18:52:59 -08:00
Koushik Dutta
d272a4b86f rebroadcast: fix basic auth 2025-01-07 18:52:36 -08:00
Koushik Dutta
f8a8ed4241 videoanalysis: fix broken concave polygon math, optimize for intersect boolean rather than intersect polygon 2025-01-07 18:04:37 -08:00
Koushik Dutta
892b978065 common: stapa idr is techcnically valid, seen on tapo 2025-01-05 13:20:34 -08:00
Koushik Dutta
c81c55c12e homekit/webrtc: publish remove warnings 2025-01-05 12:35:42 -08:00
Koushik Dutta
bb9d98921b homekit: remove report message 2025-01-05 11:48:21 -08:00
Koushik Dutta
4c66efc4af sdk: tag === collapse key 2025-01-05 08:20:21 -08:00
Koushik Dutta
0547ed9a32 sdk: add collapseId to notifications 2025-01-05 00:13:31 -08:00
Koushik Dutta
b046822282 common: rtsp client generator read support 2025-01-04 20:08:28 -08:00
Koushik Dutta
b033d24451 rebroadcast: implement synthetic streams 2025-01-03 23:15:45 -08:00
Koushik Dutta
15464229ad wyze: improve default bitrates 2025-01-03 22:02:41 -08:00
Koushik Dutta
93ad50db73 Merge branch 'main' of github.com:koush/scrypted 2025-01-03 21:55:22 -08:00
Koushik Dutta
427139e8df rebroadcast: wip remove transcode extension 2025-01-03 21:55:20 -08:00
Koushik Dutta
b1100398ec server: log cluster connect errors 2025-01-03 19:32:42 -08:00
Mike Marcacci
b40a2eaf6e common: remove dead code path
While familiarizing myself with the architecture of this project I noticed that this block is unreachable and handled above. Figured I'd submit a quick fix.

Awesome project BTW.
2025-01-03 19:19:28 -08:00
Koushik Dutta
17c9440fd9 videoanalysis: fix package detection area 2025-01-03 09:15:57 -08:00
Koushik Dutta
ea63a96444 sdk: fixup call to setScryptedInterfaceDescriptors 2025-01-03 08:36:00 -08:00
Koushik Dutta
0f02f96b89 sdk: remove chalk 2025-01-03 08:26:01 -08:00
Koushik Dutta
6ce538bb23 rebroadcast: setting for default parser 2025-01-02 11:06:24 -08:00
Koushik Dutta
29ab0e79de rebroadcast: use large rtp packets with ffmpeg for efficient processing 2025-01-02 08:58:15 -08:00
Koushik Dutta
e07cd13ef3 core: fix lnk upgrade link 2025-01-02 08:17:45 -08:00
Koushik Dutta
0cbb26051c cloud: fix health check 2025-01-02 08:16:21 -08:00
Koushik Dutta
fcb8d938ee videoanalysis: fix smart motion sensor settings nre 2024-12-31 17:32:55 -08:00
Koushik Dutta
98fe1d412a openvino: do post processing inside callback rather than copy + thread post process 2024-12-31 15:03:16 -08:00
Koushik Dutta
c19ec63f98 openvino: fix ov.Tensor.data race condition 2024-12-31 12:44:38 -08:00
Koushik Dutta
a41e915f69 openvino: avoid ov.Tensor when using start_async due to thread safety? 2024-12-31 12:26:28 -08:00
Koushik Dutta
f0db59f6d2 openvino: fix thread affinity to possibly avoid async race conditions 2024-12-31 12:11:39 -08:00
Brett Jia
8e691ff2ee server: check if SCRYPTED_PYTHON*_PATH env points to valid path (#1670) 2024-12-31 06:44:28 -08:00
Koushik Dutta
42e0810bc0 postbeta 2024-12-30 21:37:23 -08:00
Koushik Dutta
68e91ad996 postrelease 2024-12-30 21:37:17 -08:00
Koushik Dutta
e163aa8153 wyze: cluster mode support 2024-12-30 21:36:52 -08:00
Koushik Dutta
268225647e postbeta 2024-12-30 21:29:24 -08:00
Koushik Dutta
93f94b0b0a server: Fixup casing 2024-12-30 21:29:15 -08:00
Koushik Dutta
db73baf4c1 postbeta 2024-12-30 21:28:28 -08:00
Koushik Dutta
404cf47d2e server: make mediaManager cluster aware 2024-12-30 21:28:06 -08:00
Koushik Dutta
b751f77b0b wyze: require linux 2024-12-30 21:01:08 -08:00
Koushik Dutta
884ce3e175 postbeta 2024-12-30 19:32:23 -08:00
Koushik Dutta
0cb0071874 postrelease 2024-12-30 19:28:35 -08:00
Koushik Dutta
d9637679bf server: verup 2024-12-30 19:27:57 -08:00
Koushik Dutta
7ea849d357 openvino: massive perf improvements via async api usage 2024-12-29 23:20:17 -08:00
Koushik Dutta
e4f01f10f4 postbeta 2024-12-29 20:02:34 -08:00
Koushik Dutta
bd61e9a5dd server: fix fs.promises. 2024-12-29 20:02:26 -08:00
Koushik Dutta
a2f8504290 postbeta 2024-12-29 19:51:15 -08:00
Koushik Dutta
928683a429 server: more cluster mode hooks 2024-12-29 19:51:05 -08:00
Koushik Dutta
4d6bd61650 postbeta 2024-12-29 14:34:29 -08:00
Koushik Dutta
9321a5e0dd Merge branch 'main' of github.com:koush/scrypted 2024-12-29 14:33:44 -08:00
Koushik Dutta
1622a0be63 server: update launch.json configs 2024-12-29 14:33:40 -08:00
Brett Jia
55cb62cb72 server: use standard-telnetlib for Python 3.13+ (#1669)
* bump portable-python to version with 3.13

* add standard-telnetlib to scrypted requirements for Python 3.13+
2024-12-29 14:22:32 -08:00
Koushik Dutta
11ea37d1c4 wyze: fix performance issues! 2024-12-28 22:22:51 -08:00
Koushik Dutta
8e1dfa8174 core: ensure lxc-docker is updated every boot 2024-12-28 20:35:44 -08:00
Koushik Dutta
0cf4802385 install: fixup missing debugpy 2024-12-28 15:39:26 -08:00
Koushik Dutta
194facb19c Revert "docker: remove pips"
This reverts commit 5f7ecc0410.
2024-12-28 15:37:46 -08:00
Koushik Dutta
6438ad1e3c tensorflow-lite: pipeline pre/post processing 2024-12-28 15:24:28 -08:00
Koushik Dutta
586f78ebc1 lxc: fix auto repair in systemd script 2024-12-28 14:50:57 -08:00
Koushik Dutta
48c5e1a5fe tensorflow-lite: quantization cleanups 2024-12-28 14:24:12 -08:00
Koushik Dutta
a6a986a8ac postbeta 2024-12-28 13:25:08 -08:00
Koushik Dutta
0b04d92131 server: use site packages in python for debugging 2024-12-28 13:24:40 -08:00
Koushik Dutta
05e9627f4a server: add debugpy to install list 2024-12-28 13:09:47 -08:00
Koushik Dutta
381c6de336 install/server: remove psutil 2024-12-28 13:08:22 -08:00
Koushik Dutta
4206ee4686 Merge branch 'main' of github.com:koush/scrypted 2024-12-27 22:40:45 -08:00
Koushik Dutta
e33a793867 tensorflow-lite: use new yolov9s model with separate outputs to fix quantization accuracy loss 2024-12-27 22:40:33 -08:00
Brett Jia
699eebaf14 docker: set default shell to bash (#1667)
* docker: change default shell to bash

* set SHELL
2024-12-26 18:50:49 -08:00
Brett Jia
45a2d5764c docker: dynamically find amdgpu deb package name (#1666) 2024-12-26 18:22:30 -08:00
Koushik Dutta
5f7ecc0410 docker: remove pips 2024-12-26 17:58:35 -08:00
Koushik Dutta
92257e41c1 webrtc: fix media conversion failure 2024-12-25 20:22:53 -08:00
Koushik Dutta
c5a703896c webrtc: improve media to signaling channel conversion 2024-12-25 19:55:16 -08:00
Koushik Dutta
51aa79956a core: publish ui updates 2024-12-25 19:29:12 -08:00
Koushik Dutta
fc1151ce8c Merge branch 'main' of github.com:koush/scrypted 2024-12-25 19:28:33 -08:00
Koushik Dutta
eaa2c37d57 tensorflow-lite: add relu models 2024-12-25 19:28:28 -08:00
Koushik Dutta
162bb7bfab proxmox: docker-compose.sh should repair dpkg first 2024-12-24 19:52:32 -08:00
Koushik Dutta
e467414704 rtp: fix leak if child process fails to spawn 2024-12-23 15:06:30 -08:00
Koushik Dutta
8ec6a25833 rebroadcast: add support for rtsp url using cluster address in case scrypted server address is not set 2024-12-23 11:16:36 -08:00
Koushik Dutta
56bc0d6a26 postbeta 2024-12-22 12:23:13 -08:00
Koushik Dutta
9098426c3b server: add rpc support for shallow serialized arrays 2024-12-22 12:16:10 -08:00
Koushik Dutta
0d9d425ef0 server: fix python search order 2024-12-22 12:05:33 -08:00
Koushik Dutta
4c6ca3b2a5 Merge branch 'main' of github.com:koush/scrypted 2024-12-22 09:01:34 -08:00
Koushik Dutta
762e058ec5 videoanalyis: reduce default confidence for smart motion sensor 2024-12-22 09:01:30 -08:00
Koushik Dutta
f02509152d docker: improve disk setup and add auto remount 2024-12-21 20:30:44 -08:00
Koushik Dutta
9d92031e4c videoanalysis: make some settings immediate 2024-12-20 11:22:02 -08:00
Koushik Dutta
6d0027d3e8 proxmox: onboot 2024-12-20 09:10:45 -08:00
Koushik Dutta
274e043c81 videoanalysis: add separate crop zone 2024-12-19 18:03:58 -08:00
Koushik Dutta
817a6f5a59 videoanalysis: fix zone normalization 2024-12-19 15:22:04 -08:00
Koushik Dutta
cbdf8873e0 Merge branch 'main' of github.com:koush/scrypted 2024-12-19 14:54:28 -08:00
Koushik Dutta
c9c9e106db videoanalaysis: fix zone persistence 2024-12-19 14:54:23 -08:00
Long Zheng
f3d7ebd2a2 Fix Windows install script NPM/Node version clash (#1662)
* Fix NPM/Node version clash

* Update install-scrypted-dependencies-win.ps1
2024-12-19 12:04:23 -08:00
Koushik Dutta
0ea6b13cb9 videoanalysis: smart occupancy sensor 2024-12-19 11:14:27 -08:00
Koushik Dutta
68cbe9a4f9 videoanalysis: smart occupancy sensor 2024-12-19 10:48:03 -08:00
Koushik Dutta
c7ab9085ff core: more ui fixes 2024-12-19 10:36:03 -08:00
Koushik Dutta
45993b3cb9 snapshot: fix nre on toImage format validaiton 2024-12-19 10:24:30 -08:00
Koushik Dutta
82ce08ab53 core: occupancy ui 2024-12-19 09:40:42 -08:00
Koushik Dutta
262fb32085 core: publish ui 2024-12-19 09:33:05 -08:00
Koushik Dutta
919d2dee85 tensorflow-lite: missing files 2024-12-18 09:40:36 -08:00
Koushik Dutta
1bb7df53c7 mqtt: publish 2024-12-18 09:40:10 -08:00
Koushik Dutta
612cf7b520 postbeta 2024-12-17 21:49:13 -08:00
Koushik Dutta
55a80f1898 server: fix env nre 2024-12-17 21:49:04 -08:00
Koushik Dutta
44ab56a888 tensorflow-lite: threshold cleanup 2024-12-17 11:38:12 -08:00
Koushik Dutta
eaae396861 tensorflow-lite: new default model 2024-12-17 09:22:25 -08:00
Koushik Dutta
cff170a508 postbeta 2024-12-16 19:55:06 -08:00
Koushik Dutta
c811109ee9 sdk/core: rebuild with cjs/es fixes 2024-12-16 19:54:04 -08:00
Koushik Dutta
c8e4502d11 sdk/server: more reliable module env detection 2024-12-16 19:51:25 -08:00
Koushik Dutta
b75c0e0ca1 sdk: ensure import.meta is undefined for webpack 2024-12-16 19:23:14 -08:00
Koushik Dutta
f64c9226a1 postbeta 2024-12-16 08:03:44 -08:00
Koushik Dutta
95dd67cd3a server: combine NODE_PATHs 2024-12-16 08:03:24 -08:00
Koushik Dutta
3ac0ca5c7a sdk: remove old node pty 2024-12-16 07:57:08 -08:00
Koushik Dutta
cd68af9796 core: remove old node pty 2024-12-16 07:54:25 -08:00
Koushik Dutta
9c1be5865b openvino: use relu face 2024-12-15 19:37:00 -08:00
Koushik Dutta
675f23235b postbeta 2024-12-15 13:12:00 -08:00
Koushik Dutta
0824136458 server: allow NODE_PATH override 2024-12-15 13:11:45 -08:00
Koushik Dutta
2b1b65d723 core: publish ui fix for extension toggling new devices 2024-12-15 12:16:26 -08:00
Koushik Dutta
16995ed9e8 core: fix aggregate device 2024-12-15 09:34:22 -08:00
Koushik Dutta
c5fb7d20a0 videoanalysis: fix motion reporting from object detector 2024-12-13 23:38:08 -08:00
Koushik Dutta
8c67f1e0ff tapo: update readme 2024-12-13 12:45:59 -08:00
Koushik Dutta
50e2ae83b4 objectdetector: fixup normalizeBox to allow scalar 2024-12-13 08:23:33 -08:00
Koushik Dutta
1eb4f6fd55 core: publish support for editing camera zones via deviceFilter param 2024-12-12 15:48:12 -08:00
Koushik Dutta
9152512679 proxmox: use restore storage for reset as well 2024-12-12 10:57:48 -08:00
Koushik Dutta
7870ed7eeb reolink: fixup probe 2024-12-12 09:11:48 -08:00
Koushik Dutta
40c0dea505 reolink: validate device info 2024-12-11 21:39:27 -08:00
Koushik Dutta
3542d327ea postbeta 2024-12-11 20:09:42 -08:00
Koushik Dutta
2ef87c21b6 server: allow cluster labels to request plugins 2024-12-11 20:09:33 -08:00
Koushik Dutta
4585f43318 openvino: disable npu for recognition with user input 2024-12-11 15:54:16 -08:00
Koushik Dutta
30da19510a openvino: disable npu for recognition 2024-12-11 15:53:40 -08:00
Koushik Dutta
5ea1c9467f proxmox: fix restore prompt install 2024-12-10 15:47:32 -08:00
Koushik Dutta
1d6eabc9e8 proxmox: restore prompt 2024-12-10 15:39:52 -08:00
Koushik Dutta
9ea4b5a29b proxmox: find a default storage device 2024-12-10 15:29:06 -08:00
Koushik Dutta
539692867b openvino: reenable npu 2024-12-10 12:22:13 -08:00
Koushik Dutta
e796404995 core: deprecate lxc 2024-12-10 10:43:37 -08:00
Koushik Dutta
54b21260d1 core: fix cluster worker rename 2024-12-10 10:23:26 -08:00
Koushik Dutta
be35fb2dc2 postbeta 2024-12-10 09:55:43 -08:00
Koushik Dutta
04065a3487 core/client: publish 2024-12-10 09:42:00 -08:00
Koushik Dutta
ac882c723a server: fix cluster dependencies 2024-12-10 09:40:16 -08:00
Koushik Dutta
02cde6382c server: revert tsconfig change 2024-12-10 09:33:04 -08:00
Koushik Dutta
f942a13e90 client: add cluster manager 2024-12-10 09:32:23 -08:00
Koushik Dutta
6299caac20 server: fix typings 2024-12-10 09:30:29 -08:00
Koushik Dutta
6f0501634f server: move cluster manager 2024-12-10 09:30:13 -08:00
Koushik Dutta
575e544c40 core: Fix nre if clusterManager does not exist 2024-12-09 21:45:24 -08:00
Koushik Dutta
ff448e9c7f core: manage cluster through ui 2024-12-09 21:19:10 -08:00
Koushik Dutta
6173d67bb0 postbeta 2024-12-09 14:18:44 -08:00
Koushik Dutta
4431158bfa server: add various controls for server node in cluster mode 2024-12-09 14:04:43 -08:00
Koushik Dutta
822054e888 videoanalysis: hide decoder option if detection provides it 2024-12-09 10:07:42 -08:00
Koushik Dutta
d7e21d1d44 mqtt: fix exports 2024-12-08 16:08:36 -08:00
Koushik Dutta
6e451a1b06 server: npm audit 2024-12-07 18:53:49 -08:00
Koushik Dutta
57eccd4ad7 Merge branch 'main' into cluster 2024-12-07 18:37:30 -08:00
Koushik Dutta
c2d45e4357 cloud: additional tunnel check 2024-12-07 18:37:16 -08:00
Koushik Dutta
698a4a4a4a postbeta 2024-12-06 12:47:06 -08:00
Koushik Dutta
01493e311d server: fix repl in cluster mode 2024-12-06 12:46:49 -08:00
Koushik Dutta
a6d62365dc postbeta 2024-12-06 11:52:53 -08:00
Koushik Dutta
9b504a280f docker: switch to noble base 2024-12-06 11:52:26 -08:00
Koushik Dutta
5df8689236 docker: update intel for legacy + latest install process. 2024-12-06 11:39:08 -08:00
Koushik Dutta
235d408f1f dockker: test noble 2024-12-06 11:27:09 -08:00
Koushik Dutta
9b4547be85 docker: prevent pip upgrade 2024-12-06 11:14:02 -08:00
Koushik Dutta
0b8bc0d0d1 docker: python3.12 2024-12-06 10:54:05 -08:00
Koushik Dutta
134d4be1b7 docker: noble base 2024-12-06 10:47:01 -08:00
Koushik Dutta
e77487ed15 docker: noble base 2024-12-06 10:46:25 -08:00
Koushik Dutta
6e60fe1c09 openvino: disable npu due to openvino bug 2024-12-06 10:07:43 -08:00
Long Zheng
a7424b3546 Update Windows install script workaround npm issue (#1654)
* Update Windows install script workaround npm issue

* Test removing RunAsAdministrator

* Revert "Test removing RunAsAdministrator"

This reverts commit 46c80964ea.

* Test removing npm fix

* Revert "Test removing npm fix"

This reverts commit 0f9adbeae6.

* Test dump daemon logs

* More test

* More tests

* More tests

* Test

* Test

* Test

* Test

* Cleanup

* Add spawn error handler

* Fix event handler

* Remove node version debug
2024-12-06 09:19:01 -08:00
Koushik Dutta
70cf3488ef openvino: add scrypted_yolov9t_relu_int8_320 2024-12-06 08:49:56 -08:00
Koushik Dutta
d74ac6fb8e server: cleanup thread peers 2024-12-05 21:00:07 -08:00
Koushik Dutta
47cad5d747 mqtt: fix break 2024-12-05 12:58:58 -08:00
Koushik Dutta
4ebb7215c0 server: fix HoL in sendStream by using a dedicated cluster connect 2024-12-05 12:24:55 -08:00
Koushik Dutta
1d55830f10 server: sendStream should also be one way 2024-12-05 11:38:40 -08:00
Koushik Dutta
0bb5c79875 postbeta 2024-12-05 11:37:54 -08:00
Koushik Dutta
e3ca09a80b server/sdk: add support for HttpResponse.sendStream 2024-12-05 11:37:27 -08:00
Koushik Dutta
ef53829ccc core: clean up device groups 2024-12-05 09:38:36 -08:00
Koushik Dutta
5f0cf6b6c2 mqtt: remove scrypted-eval fs hack 2024-12-05 09:38:00 -08:00
Koushik Dutta
59e09825ff postbeta 2024-12-05 09:24:47 -08:00
Koushik Dutta
b4aa20b4cd server: remove legacy storage event 2024-12-05 09:24:36 -08:00
Koushik Dutta
e2eba2a227 openvino: beta 2024-12-05 08:46:36 -08:00
Koushik Dutta
9370a163fd videoanalysis: improve low watermark throttling 2024-12-05 08:45:58 -08:00
Koushik Dutta
c65f38f251 postbeta 2024-12-05 08:45:13 -08:00
Koushik Dutta
83bde83a39 server: ensure cluster client service control 2024-12-05 08:45:03 -08:00
Koushik Dutta
786b4b5ed9 postbeta 2024-12-04 21:32:07 -08:00
Koushik Dutta
f9c1d7704a sdk: fix sourcemap 2024-12-04 21:31:52 -08:00
Koushik Dutta
3162d2be34 Update install-amd-graphics.sh 2024-12-04 20:48:34 -08:00
Koushik Dutta
3f0a788a6a sdk/server: add mode to workers 2024-12-04 17:51:36 -08:00
Koushik Dutta
72504286ea postbeta 2024-12-04 15:59:56 -08:00
Koushik Dutta
c664cc3b4d server/sdk: include/check sdk version for plugin forwards/backwards compat. 2024-12-04 15:59:41 -08:00
Koushik Dutta
99853906b9 postbeta 2024-12-04 11:42:23 -08:00
Koushik Dutta
ea873a527b sdk/server: clean up sdk init race conditions to allow side effect imports 2024-12-04 10:54:28 -08:00
Koushik Dutta
df0b13512a videoanalysis: fix sample history tracking to purge before measurement 2024-12-03 13:42:40 -08:00
Koushik Dutta
1651152eec videoanalysis: publish 2024-12-03 10:06:36 -08:00
Koushik Dutta
7b3ab501b2 server: remove cluster cpu tracking 2024-12-03 00:21:46 -08:00
Koushik Dutta
3a77a3398d videoanalysis: use detection fps as measurement of system load 2024-12-03 00:00:37 -08:00
Koushik Dutta
f2ece1270a openvino: update to relu+int8 models 2024-12-02 22:49:58 -08:00
Koushik Dutta
8b6d8aeae6 Merge branch 'main' into cluster 2024-12-02 22:14:01 -08:00
Koushik Dutta
578bba67f8 postbeta 2024-12-02 19:00:55 -08:00
Koushik Dutta
15fb7d86e2 postbeta 2024-12-02 18:58:00 -08:00
Koushik Dutta
9d23caa66d server: downgrade typescript 2024-12-02 18:57:51 -08:00
Koushik Dutta
c46ed2cef5 postbeta 2024-12-02 18:46:17 -08:00
Koushik Dutta
7dcfdaa98e server: prevent crash on missing cpu usage 2024-12-02 18:46:06 -08:00
Koushik Dutta
ee23c93132 postbeta 2024-12-02 15:41:50 -08:00
Koushik Dutta
b1b0dd8997 server: fix non cluster crash 2024-12-02 15:41:42 -08:00
Koushik Dutta
6cc5a0e04c postbeta 2024-12-02 15:10:52 -08:00
Koushik Dutta
a75b263141 server: cluster cpu usage monitoring 2024-12-02 15:08:56 -08:00
Koushik Dutta
d91ec68e6c sdk: find object cluster worker affinity 2024-12-02 11:02:35 -08:00
Koushik Dutta
8ccc7a6c06 postbeta 2024-12-01 20:09:18 -08:00
Koushik Dutta
a6ece48cc3 server: add cluster worker weight 2024-12-01 17:46:14 -08:00
Koushik Dutta
7398f280cc postbeta 2024-11-30 23:19:40 -08:00
Koushik Dutta
eb1d0f647a server: fix es imports on old node 2024-11-30 23:19:30 -08:00
Koushik Dutta
b5a40b27a9 postbeta 2024-11-30 22:52:37 -08:00
Koushik Dutta
84870b444c server: revert createRequire 2024-11-30 22:49:59 -08:00
Koushik Dutta
339c934dda sdk: rollup fixes 2024-11-30 22:46:12 -08:00
Koushik Dutta
4df0eec70a server: esmodule cleanups 2024-11-30 20:00:41 -08:00
Koushik Dutta
6d268ade69 server: formatting 2024-11-30 09:41:30 -08:00
Koushik Dutta
6b040954a0 esmodule: project cleanup 2024-11-30 09:38:15 -08:00
Koushik Dutta
73d2f5b408 esmodule plugins: wip 2024-11-30 09:09:38 -08:00
Koushik Dutta
71bb2ec80a postbeta 2024-11-29 14:06:02 -08:00
Koushik Dutta
92b120886c server: remove log from eval params 2024-11-29 14:05:52 -08:00
Koushik Dutta
9001d996e2 sdk: fix commonjs entry mangling debug 2024-11-28 22:13:11 -08:00
Koushik Dutta
d060a74689 docker: Update install-amd-graphics.sh 2024-11-28 20:09:51 -08:00
Koushik Dutta
8ba4c46576 docker: Update install-intel-npu.sh 2024-11-28 19:56:16 -08:00
Koushik Dutta
a77f82462d openvino: rollback openvino 2024-11-28 19:53:24 -08:00
Koushik Dutta
3a1401afbb openvino: bump openvino 2024-11-28 19:44:47 -08:00
Koushik Dutta
14ae374916 postbeta 2024-11-28 19:37:55 -08:00
Koushik Dutta
52d915cc68 server: dependency updates 2024-11-28 19:37:44 -08:00
Koushik Dutta
cb501e66c6 sdk: publush 2024-11-28 19:14:34 -08:00
Koushik Dutta
053b43128f Merge branch 'cluster' of github.com:koush/scrypted into cluster 2024-11-28 18:47:41 -08:00
Koushik Dutta
702456a40d sdk: rollup support 2024-11-28 18:25:12 -08:00
Koushik Dutta
17ebbb1656 sdk: rollup support 2024-11-28 18:24:46 -08:00
Koushik Dutta
0f79cd88ce sdk: remove dead dep 2024-11-28 12:41:07 -08:00
Koushik Dutta
76c960100c sdk: remove dead dep 2024-11-28 12:39:11 -08:00
Koushik Dutta
6d56e41651 sample: update 2024-11-28 10:56:56 -08:00
Koushik Dutta
640d66474c postbeta 2024-11-28 10:48:19 -08:00
Koushik Dutta
238c82a354 server: add cluster worker info 2024-11-28 10:42:42 -08:00
Koushik Dutta
25a369403c server: add cluster worker info 2024-11-28 10:41:04 -08:00
Koushik Dutta
b1e1f54af5 server: add hooks to get cluster worker controls 2024-11-28 10:02:08 -08:00
Koushik Dutta
8df38dbebe server: add env control 2024-11-28 09:43:22 -08:00
Koushik Dutta
229dcd3174 postbeta 2024-11-28 09:28:34 -08:00
Koushik Dutta
c3d6dcb6a2 server: pass through service control 2024-11-28 09:28:24 -08:00
Koushik Dutta
0c951519e2 postbeta 2024-11-28 08:57:46 -08:00
Koushik Dutta
1f406ae740 server: pass through service control for cluster mode 2024-11-28 08:57:23 -08:00
Koushik Dutta
8d0de7e557 postbeta 2024-11-27 18:39:51 -08:00
Koushik Dutta
e799ada9c9 sdk: fixup clusterWorkerId to be optional 2024-11-26 09:02:01 -08:00
Koushik Dutta
8e888bc6a1 Update docker-compose.yml 2024-11-23 22:05:56 -08:00
Koushik Dutta
c5053008b7 docker: use relative path for volume. 2024-11-23 22:04:33 -08:00
304 changed files with 19449 additions and 10694 deletions

View File

@@ -27,6 +27,11 @@ Created issues that do not meet these requirements or are improperly filled out
1. Delete this section and everything above it.
2. Fill out the sections below.
** Before You Submit**
- [ ] I checked that my issue isn't already filed: [Search open issues](https://github.com/koush/scrypted/issues).
- [ ] I checked the relevant camera/device and/or plugin `Log` in the `Management Console` for errors or warnings that may help identify and resolve the issue myself.
**Describe the bug**
A clear and concise description of what the bug is. The issue tracker is only for reporting bugs in Scrypted, for general support check Discord. Hardrware support requests or assistance requests will be immediately closed.
@@ -43,6 +48,9 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Include a `Log` from the device/camera in the management console (and if applicable, the affacted plugin, like HomeKit).
**Server (please complete the following information):**
- OS: [e.g. Ubuntu]
- Installation Method: [e.g. Desktop App, Docker, Local]

2
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
# disable blank issue creation
blank_issues_enabled: false

View File

@@ -8,10 +8,10 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: self-hosted
env:
NODE_VERSION: '20'
NODE_VERSION: '22'
strategy:
matrix:
BASE: ["jammy"]
BASE: ["noble"]
FLAVOR: ["full", "lite"]
steps:
- name: Check out the repo
@@ -83,7 +83,7 @@ jobs:
runs-on: self-hosted
strategy:
matrix:
BASE: ["jammy"]
BASE: ["noble"]
steps:
- name: Check out the repo
uses: actions/checkout@v3

View File

@@ -20,9 +20,10 @@ jobs:
strategy:
matrix:
BASE: [
["jammy-nvidia", ".s6"],
["jammy-full", ".s6"],
["jammy-lite", ""],
["noble-nvidia", ".s6", "noble-nvidia"],
["noble-full", ".s6", "noble-full"],
["noble-lite", "", "noble-lite"],
# ["noble-lite", ".router", "noble-router"],
]
steps:
- name: Check out the repo
@@ -94,16 +95,18 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ format('koush/scrypted:v{1}-{0}', matrix.BASE[0], github.event.inputs.publish_tag || steps.package-version.outputs.NPM_VERSION) }}
${{ matrix.BASE[0] == 'jammy-full' && format('koush/scrypted:{0}', github.event.inputs.tag) || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-nvidia' && 'koush/scrypted:nvidia' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-full' && 'koush/scrypted:full' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-lite' && 'koush/scrypted:lite' || '' }}
${{ format('koush/scrypted:v{1}-{0}', matrix.BASE[2], github.event.inputs.publish_tag || steps.package-version.outputs.NPM_VERSION) }}
${{ matrix.BASE[2] == 'noble-full' && format('koush/scrypted:{0}', github.event.inputs.tag) || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-nvidia' && 'koush/scrypted:nvidia' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-full' && 'koush/scrypted:full' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-lite' && matrix.BASE[1] == '' && 'koush/scrypted:lite' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-router' && 'koush/scrypted:router' || '' }}
${{ format('ghcr.io/koush/scrypted:v{1}-{0}', matrix.BASE[0], github.event.inputs.publish_tag || steps.package-version.outputs.NPM_VERSION) }}
${{ matrix.BASE[0] == 'jammy-full' && format('ghcr.io/koush/scrypted:{0}', github.event.inputs.tag) || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-nvidia' && 'ghcr.io/koush/scrypted:nvidia' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-full' && 'ghcr.io/koush/scrypted:full' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[0] == 'jammy-lite' && 'ghcr.io/koush/scrypted:lite' || '' }}
${{ matrix.BASE[2] == 'noble-full' && format('ghcr.io/koush/scrypted:{0}', github.event.inputs.tag) || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-nvidia' && 'ghcr.io/koush/scrypted:nvidia' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-full' && 'ghcr.io/koush/scrypted:full' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-lite' && matrix.BASE[1] == '' && 'ghcr.io/koush/scrypted:lite' || '' }}
${{ github.event.inputs.tag == 'latest' && matrix.BASE[2] == 'noble-lite' && 'ghcr.io/koush/scrypted:router' || '' }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runner: [ubuntu-latest, macos-14, macos-13, windows-latest]
runner: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-13, windows-latest]
steps:
- name: Checkout repository

3630
common/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -123,6 +123,9 @@ export function createAsyncQueue<T>() {
}
return {
[Symbol.dispose]() {
end(new Error('async queue disposed'));
},
get ended() {
return ended;
},

View File

@@ -7,7 +7,6 @@ const { systemManager } = sdk;
export abstract class AutoenableMixinProvider extends ScryptedDeviceBase {
hasEnabledMixin: { [id: string]: string } = {};
pluginsComponent: Promise<any>;
unshiftMixin = false;
constructor(nativeId?: string, public autoIncludeToken = 'v4') {
super(nativeId);
@@ -45,6 +44,10 @@ export abstract class AutoenableMixinProvider extends ScryptedDeviceBase {
return this.hasEnabledMixin[device.id] === this.autoIncludeToken;
}
shouldUnshiftMixin(device: ScryptedDevice) {
return false;
}
async maybeEnableMixin(device: ScryptedDevice) {
if (!device || device.mixins?.includes(this.id))
return;
@@ -61,7 +64,7 @@ export abstract class AutoenableMixinProvider extends ScryptedDeviceBase {
this.log.i('auto enabling mixin for ' + device.name)
const mixins = (device.mixins || []).slice();
if (this.unshiftMixin)
if (this.shouldUnshiftMixin(device))
mixins.unshift(this.id);
else
mixins.push(this.id);
@@ -77,5 +80,5 @@ export abstract class AutoenableMixinProvider extends ScryptedDeviceBase {
this.storage.setItem('hasEnabledMixin', JSON.stringify(this.hasEnabledMixin));
}
abstract canMixin(type: ScryptedDeviceType, interfaces: string[]): Promise<string[] | null | undefined | void>;
abstract canMixin(type: ScryptedDeviceType | string, interfaces: string[]): Promise<string[] | null | undefined | void>;
}

View File

@@ -63,7 +63,6 @@ export async function scryptedEval(device: ScryptedDeviceBase, script: string, e
const allParams = Object.assign({}, params, {
sdk,
fs: require('realfs'),
ScryptedDeviceBase,
MixinDeviceBase,
StorageSettings,

View File

@@ -19,7 +19,7 @@ function isPi(model: string) {
export function isRaspberryPi() {
let cpuInfo: string;
try {
cpuInfo = require('realfs').readFileSync('/proc/cpuinfo', { encoding: 'utf8' });
cpuInfo = require('fs').readFileSync('/proc/cpuinfo', { encoding: 'utf8' });
}
catch (e) {
// if this fails, this is probably not a pi
@@ -70,11 +70,7 @@ export function getH264DecoderArgs(): CodecArgs {
],
};
if (isRaspberryPi()) {
ret['Raspberry Pi'] = ['-c:v', 'h264_mmal'];
ret[V4L2] = ['-c:v', 'h264_v4l2m2m'];
}
else if (os.platform() === 'linux') {
if (os.platform() === 'linux') {
ret[V4L2] = ['-c:v', 'h264_v4l2m2m'];
}
else if (os.platform() === 'win32') {

View File

@@ -1,96 +0,0 @@
export interface RefreshPromise<T> {
promise: Promise<T>;
cacheDuration: number;
}
export function singletonPromise<T>(rp: undefined | RefreshPromise<T>, method: () => Promise<T>, cacheDuration = 0) {
if (rp?.promise)
return rp;
const promise = method();
if (!rp) {
rp = {
promise,
cacheDuration,
}
}
else {
rp.promise = promise;
}
promise.finally(() => setTimeout(() => rp.promise = undefined, rp.cacheDuration));
return rp;
}
export class TimeoutError<T> extends Error {
constructor(public promise: Promise<T>) {
super('Operation Timed Out');
}
}
export function timeoutPromise<T>(timeout: number, promise: Promise<T>): Promise<T> {
return new Promise<T>((resolve, reject) => {
const t = setTimeout(() => reject(new TimeoutError(promise)), timeout);
promise
.then(v => {
clearTimeout(t);
resolve(v);
})
.catch(e => {
clearTimeout(t);
reject(e);
});
})
}
export function timeoutFunction<T>(timeout: number, f: (isTimedOut: () => boolean) => Promise<T>): Promise<T> {
return new Promise<T>((resolve, reject) => {
let isTimedOut = false;
const promise = f(() => isTimedOut);
const t = setTimeout(() => {
isTimedOut = true;
reject(new TimeoutError(promise));
}, timeout);
promise
.then(v => {
clearTimeout(t);
resolve(v);
})
.catch(e => {
clearTimeout(t);
reject(e);
});
})
}
export function createPromiseDebouncer<T>() {
let current: Promise<T>;
return (func: () => Promise<T>): Promise<T> => {
if (!current)
current = func().finally(() => current = undefined);
return current;
}
}
export function createMapPromiseDebouncer<T>() {
const map = new Map<string, Promise<T>>();
return (key: any, debounce: number, func: () => Promise<T>): Promise<T> => {
const keyStr = JSON.stringify(key);
let value = map.get(keyStr);
if (!value) {
value = func().finally(() => {
if (!debounce) {
map.delete(keyStr);
return;
}
setTimeout(() => map.delete(keyStr), debounce);
});
map.set(keyStr, value);
}
return value;
}
}

1
common/src/promise-utils.ts Symbolic link
View File

@@ -0,0 +1 @@
../../server/src/promise-utils.ts

View File

@@ -95,6 +95,9 @@ export const H265_NAL_TYPE_SPS = 33;
export const H265_NAL_TYPE_PPS = 34;
export const H265_NAL_TYPE_IDR_N = 19;
export const H265_NAL_TYPE_IDR_W = 20;
export const H265_NAL_TYPE_FU = 49;
export const H265_NAL_TYPE_SEI_PREFIX = 39;
export const H265_NAL_TYPE_SEI_SUFFIX = 40;
export function findH264NaluType(streamChunk: StreamChunk, naluType: number) {
if (streamChunk.type !== 'h264')
@@ -161,10 +164,10 @@ export function findH265NaluTypeInNalu(nalu: Buffer, naluType: number) {
return;
}
export function getNaluTypes(streamChunk: StreamChunk) {
export function getStartedH264NaluTypes(streamChunk: StreamChunk) {
if (streamChunk.type !== 'h264')
return new Set<number>();
return getNaluTypesInNalu(streamChunk.chunks[streamChunk.chunks.length - 1].subarray(12))
return getNaluTypesInNalu(streamChunk.chunks[streamChunk.chunks.length - 1].subarray(12), true)
}
export function getNaluTypesInNalu(nalu: Buffer, fuaRequireStart = false, fuaRequireEnd = false) {
@@ -205,10 +208,10 @@ export function getNaluTypesInNalu(nalu: Buffer, fuaRequireStart = false, fuaReq
return ret;
}
export function getH265NaluTypes(streamChunk: StreamChunk) {
export function getStartedH265NaluTypes(streamChunk: StreamChunk) {
if (streamChunk.type !== 'h265')
return new Set<number>();
return getNaluTypesInH265Nalu(streamChunk.chunks[streamChunk.chunks.length - 1].subarray(12))
return getNaluTypesInH265Nalu(streamChunk.chunks[streamChunk.chunks.length - 1].subarray(12), true)
}
export function getNaluTypesInH265Nalu(nalu: Buffer, fuaRequireStart = false, fuaRequireEnd = false) {
@@ -216,7 +219,7 @@ export function getNaluTypesInH265Nalu(nalu: Buffer, fuaRequireStart = false, fu
const naluType = parseH265NaluType(nalu[0]);
if (naluType === H265_NAL_TYPE_AGG) {
ret.add(H265_NAL_TYPE_AGG);
let pos = 1;
let pos = 2;
while (pos < nalu.length) {
const naluLength = nalu.readUInt16BE(pos);
pos += 2;
@@ -225,6 +228,23 @@ export function getNaluTypesInH265Nalu(nalu: Buffer, fuaRequireStart = false, fu
pos += naluLength;
}
}
else if (naluType === H265_NAL_TYPE_FU) {
ret.add(H265_NAL_TYPE_FU);
const fuaType = nalu[2] & 0x3F; // 6 bits
if (fuaRequireStart) {
const isFuStart = !!(nalu[2] & 0x80);
if (isFuStart)
ret.add(fuaType);
}
else if (fuaRequireEnd) {
const isFuEnd = !!(nalu[2] & 0x40);
if (isFuEnd)
ret.add(fuaType);
}
else {
ret.add(fuaType);
}
}
else {
ret.add(naluType);
}
@@ -247,19 +267,21 @@ export function createRtspParser(options?: StreamParserOptions): RtspStreamParse
'tcp',
...(options?.vcodec || []),
...(options?.acodec || []),
// linux and windows seem to support 64000 but darwin is 32000?
'-pkt_size', '32000',
'-f', 'rtsp',
],
findSyncFrame(streamChunks: StreamChunk[]) {
for (let prebufferIndex = 0; prebufferIndex < streamChunks.length; prebufferIndex++) {
const streamChunk = streamChunks[prebufferIndex];
if (streamChunk.type === 'h264') {
const naluTypes = getNaluTypes(streamChunk);
const naluTypes = getStartedH264NaluTypes(streamChunk);
if (naluTypes.has(H264_NAL_TYPE_SPS) || naluTypes.has(H264_NAL_TYPE_IDR)) {
return streamChunks.slice(prebufferIndex);
}
}
else if (streamChunk.type === 'h265') {
const naluTypes = getH265NaluTypes(streamChunk);
const naluTypes = getStartedH265NaluTypes(streamChunk);
if (naluTypes.has(H265_NAL_TYPE_VPS)
|| naluTypes.has(H265_NAL_TYPE_SPS)
@@ -394,7 +416,7 @@ export class RtspClient extends RtspBase {
hasGetParameter = true;
contentBase: string;
constructor(public url: string) {
constructor(public readonly url: string) {
super();
const u = new URL(url);
const port = parseInt(u.port) || 554;
@@ -511,6 +533,42 @@ export class RtspClient extends RtspBase {
}
}
async *handleStream(): AsyncGenerator<{
rtcp: boolean,
header: Buffer,
packet: Buffer,
channel: number,
}> {
while (true) {
const header = await readLength(this.client, 4);
// can this even happen? since the RTSP request method isn't a fixed
// value like the "RTSP" in the RTSP response, I don't think so?
if (header[0] !== RTSP_FRAME_MAGIC) {
if (header.toString() !== 'RTSP')
throw this.createBadHeader(header);
this.client.unshift(header);
// do what with this?
const message = await super.readMessage();
const body = await this.readBody(parseHeaders(message));
continue;
}
const length = header.readUInt16BE(2);
const packet = await readLength(this.client, length);
const id = header.readUInt8(1);
yield {
channel: id,
rtcp: id % 2 === 1,
header,
packet,
}
}
}
async readLoop() {
const deferred = new Deferred<void>();
@@ -613,7 +671,8 @@ export class RtspClient extends RtspBase {
const { parseHTTPHeadersQuotedKeyValueSet } = await import('http-auth-utils/dist/utils');
if (this.wwwAuthenticate.includes('Basic')) {
const hash = BASIC.computeHash(url);
const parsedUrl = new URL(this.url);
const hash = BASIC.computeHash({ username: parsedUrl.username, password: parsedUrl.password });
return `Basic ${hash}`;
}

View File

@@ -359,3 +359,33 @@ export function getSpsPps(
pps: Buffer.from(pps, 'base64'),
}
}
export function getSpsPpsVps(
section: {
fmtp: {
payloadType: number;
parameters: {
[key: string]: string;
};
}[]
}
) {
const parameters = section?.fmtp?.[0]?.parameters;
if (!parameters) {
return {
sps: undefined,
pps: undefined,
vps: undefined,
};
}
const sps = parameters['sprop-sps'];
const pps = parameters['sprop-pps'];
const vps = parameters['sprop-vps'];
return {
sps: sps ? Buffer.from(sps, 'base64') : undefined,
pps: pps ? Buffer.from(pps, 'base64') : undefined,
vps: vps ? Buffer.from(vps, 'base64') : undefined,
}
}

View File

@@ -23,7 +23,9 @@ export function createService<T, V>(options: ForkOptions, create: (t: Promise<T>
currentFork = sdk.fork<T>(options);
currentFork.worker.on('exit', () => currentResult = undefined);
currentResult = create(currentFork.result);
currentResult.catch(() => currentResult = undefined);
currentResult.catch(() => {
currentResult = undefined;
});
return currentResult;
},

View File

@@ -1,6 +1,6 @@
# Home Assistant Addon Configuration
name: Scrypted
version: "v0.120.0-jammy-full"
version: "v0.130.1-noble-full"
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="20240321"
ENV SCRYPTED_BASE_VERSION="20250101"
CMD ["/bin/sh", "-c", "ulimit -c 0; exec npm --prefix /server exec scrypted-serve"]

View File

@@ -6,7 +6,7 @@
# This common file will be used by both Docker and the linux
# install script.
################################################################
ARG BASE="jammy"
ARG BASE="noble"
FROM ubuntu:${BASE} as header
ENV DEBIAN_FRONTEND=noninteractive
@@ -19,7 +19,7 @@ RUN apt-get update && apt-get -y install \
apt-get -y update && \
apt-get -y upgrade
ARG NODE_VERSION=20
ARG NODE_VERSION=22
RUN apt-get install -y ca-certificates curl gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg
@@ -51,8 +51,9 @@ RUN apt-get -y install \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install debugpy typing_extensions psutil
# ERROR: Cannot uninstall pip 24.0, RECORD file not found. Hint: The package was installed by debian.
# RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install debugpy
################################################################
# End section generated from template/Dockerfile.full.header
@@ -85,8 +86,8 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa && \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install debugpy typing_extensions psutil
# RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install debugpy
# Coral Edge TPU
# https://coral.ai/docs/accelerator/get-started/#runtime-on-linux
@@ -94,16 +95,20 @@ RUN echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" |
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
RUN apt-get -y update && apt-get -y install libedgetpu1-std
# set default shell to bash
RUN chsh -s /bin/bash
ENV SHELL="/bin/bash"
ENV SCRYPTED_INSTALL_ENVIRONMENT="docker"
ENV SCRYPTED_CAN_RESTART="true"
ENV SCRYPTED_VOLUME="/server/volume"
ENV SCRYPTED_INSTALL_PATH="/server"
RUN test -f "/usr/bin/ffmpeg" && test -f "/usr/bin/python3" && test -f "/usr/bin/python3.9" && test -f "/usr/bin/python3.10"
RUN test -f "/usr/bin/ffmpeg" && test -f "/usr/bin/python3" && test -f "/usr/bin/python3.9" && test -f "/usr/bin/python3.12"
ENV SCRYPTED_FFMPEG_PATH="/usr/bin/ffmpeg"
ENV SCRYPTED_PYTHON_PATH="/usr/bin/python3"
ENV SCRYPTED_PYTHON39_PATH="/usr/bin/python3.9"
ENV SCRYPTED_PYTHON310_PATH="/usr/bin/python3.10"
ENV SCRYPTED_PYTHON312_PATH="/usr/bin/python3.12"
ENV SCRYPTED_DOCKER_FLAVOR="full"

View File

@@ -10,7 +10,7 @@ RUN apt-get update && apt-get -y install \
apt-get -y update && \
apt-get -y upgrade
ARG NODE_VERSION=20
ARG NODE_VERSION=22
RUN apt-get install -y ca-certificates curl gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg
@@ -21,9 +21,10 @@ ENV SCRYPTED_INSTALL_ENVIRONMENT="docker"
ENV SCRYPTED_CAN_RESTART="true"
ENV SCRYPTED_VOLUME="/server/volume"
ENV SCRYPTED_INSTALL_PATH="/server"
ENV SHELL="/bin/bash"
RUN test -f "/usr/bin/python3" && test -f "/usr/bin/python3.10"
RUN test -f "/usr/bin/python3" && test -f "/usr/bin/python3.12"
ENV SCRYPTED_PYTHON_PATH="/usr/bin/python3"
ENV SCRYPTED_PYTHON310_PATH="/usr/bin/python3.10"
ENV SCRYPTED_PYTHON312_PATH="/usr/bin/python3.12"
ENV SCRYPTED_DOCKER_FLAVOR="lite"

View File

@@ -0,0 +1,50 @@
ARG BASE="noble-lite"
FROM ghcr.io/koush/scrypted-common:${BASE}
# tools
RUN apt -y update && apt -y install nano net-tools dnsutils dnsmasq vlan bridge-utils netplan.io nftables isc-dhcp-client
RUN rm -f /etc/systemd/system/multi-user.target.wants/dnsmasq.service
RUN rm -f /etc/systemd/system/sysinit.target.wants/systemd-resolved.service
# go + caddy
RUN apt -y install golang-go
RUN apt install -y debian-keyring debian-archive-keyring apt-transport-https
RUN curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
RUN curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-xcaddy.list
RUN apt -y update
RUN apt -y install xcaddy
RUN xcaddy build --with github.com/caddy-dns/cloudflare --output /usr/local/bin/caddy
# nftables
COPY ./router/scrypted-nftables.service /etc/systemd/system
RUN systemctl enable scrypted-nftables
RUN bash -c 'echo include \"/etc/nftables.d/*.conf\"\; > /etc/nftables.conf'
RUN mkdir -p /etc/nftables.d
COPY ./router/01-scrypted.conf /etc/nftables.d
# ipv6 forwarding
COPY ./router/scrypted-ip-forwarding.service /etc/systemd/system
RUN systemctl enable scrypted-ip-forwarding
# install turn server, but disable it too set it up on a per interface basis.
RUN apt -y update && apt -y install coturn && systemctl disable coturn && rm /usr/lib/systemd/system/coturn.service
# install usbmuxd for iphone tethering
# ensure the pairing info stays in persistent storage
RUN apt -y update && apt -y install usbmuxd && rm /usr/lib/systemd/system/usbmuxd.service && ln -sf /server/volume/plugins/\@scrypted/router/usbmuxd /var/lib/lockdown
WORKDIR /
# cache bust
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
ARG SCRYPTED_INSTALL_VERSION="latest"
RUN test -n "$SCRYPTED_INSTALL_VERSION"
RUN npx -y scrypted@latest install-server ${SCRYPTED_INSTALL_VERSION}
COPY ./router/scrypted-dhcp-watcher.service /etc/systemd/system/scrypted-dhcp-watcher.service
RUN systemctl enable scrypted-dhcp-watcher
COPY ./router/scrypted.service /etc/systemd/system/scrypted.service
RUN systemctl enable scrypted
WORKDIR /
CMD ["/sbin/init"]

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="20240321"
ENV SCRYPTED_BASE_VERSION="20250101"
CMD ["/bin/sh", "-c", "ulimit -c 0; exec npm --prefix /server exec scrypted-serve"]

View File

@@ -2,7 +2,7 @@
set -x
NODE_VERSION=20
NODE_VERSION=22
SCRYPTED_INSTALL_VERSION=beta
IMAGE_BASE=jammy
FLAVOR=full

View File

@@ -55,7 +55,7 @@ services:
# Scrypted NVR Storage (Part 3 of 3)
# Modify to add the additional volume for Scrypted NVR.
# The following example would mount the /mnt/sda/video path on the host
# The following example would mount the /mnt/media/video path on the host
# to the /nvr path inside the docker container.
# - /mnt/media/video:/nvr
@@ -75,7 +75,8 @@ services:
# - /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket
# Default volume for the Scrypted database. Typically should not be changed.
- ~/.scrypted/volume:/server/volume
# The volume will be placed relative to this docker-compose.yml.
- ./volume:/server/volume
# LXC usage only
# lxc - /var/run/docker.sock:/var/run/docker.sock

View File

@@ -23,13 +23,21 @@ fi
# https://amdgpu-install.readthedocs.io/en/latest/install-prereq.html#installing-the-installer-package
FILENAME="amdgpu-install_6.2.60202-1_all.deb"
FILENAME=$(curl -s -L https://repo.radeon.com/amdgpu-install/latest/ubuntu/$distro/ | grep -o 'amdgpu-install_[^ ]*' | cut -d'"' -f1)
if [ -z "$FILENAME" ]
then
echo "AMD graphics package can not be installed. Could not find the package name."
exit 1
fi
set -e
mkdir -p /tmp/amd
cd /tmp/amd
curl -O -L http://repo.radeon.com/amdgpu-install/latest/ubuntu/$distro/$FILENAME
apt -y update
apt -y install rsync
dpkg -i $FILENAME
apt -y update
amdgpu-install --usecase=opencl --no-dkms -y --accept-eula
cd /tmp
rm -rf /tmp/amd

View File

@@ -4,6 +4,25 @@ then
exit 0
fi
UBUNTU_22_04=$(lsb_release -r | grep "22.04")
UBUNTU_24_04=$(lsb_release -r | grep "24.04")
# needs either ubuntu 22.0.4 or 24.04
if [ -z "$UBUNTU_22_04" ] && [ -z "$UBUNTU_24_04" ]
then
echo "Intel graphics package can not be installed. Ubuntu version could not be detected when checking lsb-release and /etc/os-release."
exit 1
fi
if [ -n "$UBUNTU_22_04" ]
then
distro="jammy"
else
distro="noble"
fi
# no errors beyond this point
set -e
@@ -21,35 +40,72 @@ set -e
# need intel-media-va-driver-non-free, but all the other intel packages are installed from Intel github.
echo "Installing Intel graphics packages."
apt-get update && apt-get install -y gpg-agent &&
rm -f /usr/share/keyrings/intel-graphics.gpg &&
curl -L https://repositories.intel.com/graphics/intel-graphics.key | gpg --dearmor --yes --output /usr/share/keyrings/intel-graphics.gpg &&
echo 'deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/graphics/ubuntu jammy arc' | tee /etc/apt/sources.list.d/intel.gpu.jammy.list &&
apt-get -y update &&
apt-get -y install intel-media-va-driver-non-free &&
apt-get -y dist-upgrade;
# manual installation
# https://github.com/intel/compute-runtime/releases/tag/24.35.30872.22
# these debs are seemingly ubuntu 22.04 only.
if [ "$distro" == "jammy" ]
then
apt-get update && apt-get install -y gpg-agent &&
rm -f /usr/share/keyrings/intel-graphics.gpg &&
curl -L https://repositories.intel.com/graphics/intel-graphics.key | gpg --dearmor --yes --output /usr/share/keyrings/intel-graphics.gpg &&
echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/graphics/ubuntu $distro arc" | tee /etc/apt/sources.list.d/intel.gpu.$distro.list &&
apt-get -y update &&
apt-get -y install intel-media-va-driver-non-free &&
apt-get -y dist-upgrade;
else
apt-get update && apt-get install -y gpg-agent &&
rm -f /usr/share/keyrings/intel-graphics.gpg &&
curl -L https://repositories.intel.com/gpu/intel-graphics.key | gpg --dearmor --yes --output /usr/share/keyrings/intel-graphics.gpg &&
echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu $distro unified" | tee /etc/apt/sources.list.d/intel-gpu-$distro.list &&
apt-get -y update &&
apt-get -y install intel-media-va-driver-non-free &&
apt-get -y dist-upgrade;
fi
rm -rf /tmp/gpu && mkdir -p /tmp/gpu && cd /tmp/gpu
apt-get install -y ocl-icd-libopencl1
# very stupid legacy + current install process conflict.
# install 24.35.30872.22 for legacy support. Then install latest.
# https://github.com/intel/compute-runtime/issues/770#issuecomment-2515166915
# https://github.com/intel/compute-runtime/releases/tag/24.35.30872.22
curl -O -L https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.20/intel-igc-core_1.0.17537.20_amd64.deb
curl -O -L https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.20/intel-igc-opencl_1.0.17537.20_amd64.deb
#curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu-dbgsym_1.3.30872.22_amd64.ddeb
#curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu-legacy1-dbgsym_1.3.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu-dbgsym_1.3.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu-legacy1-dbgsym_1.3.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu-legacy1_1.3.30872.22_amd64.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-level-zero-gpu_1.3.30872.22_amd64.deb
#curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd-dbgsym_24.35.30872.22_amd64.ddeb
#curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd-legacy1-dbgsym_24.35.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd-dbgsym_24.35.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd-legacy1-dbgsym_24.35.30872.22_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd-legacy1_24.35.30872.22_amd64.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/intel-opencl-icd_24.35.30872.22_amd64.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/24.35.30872.22/libigdgmm12_22.5.0_amd64.deb
dpkg -i *.deb
rm -f *.deb
# https://github.com/intel/compute-runtime/releases/tag/24.45.31740.9
# note that at time of commit, IGC supports ubuntu 24.04 only possibly due to their builder being on 24.04.
IGC_BASE_VERSION=2.5.6
IGC_VERSION=2_$IGC_BASE_VERSION+18417_amd64
COMPUTE_VERSION=24.52.32224.5
ZERO_GPU_VERSION=1.6.32224.5_amd64
LIBIGDGMM_VERSION=22.5.5_amd64
curl -O -L https://github.com/intel/intel-graphics-compiler/releases/download/v$IGC_BASE_VERSION/intel-igc-core-$IGC_VERSION.deb
curl -O -L https://github.com/intel/intel-graphics-compiler/releases/download/v$IGC_BASE_VERSION/intel-igc-opencl-$IGC_VERSION.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/$COMPUTE_VERSION/intel-level-zero-gpu-dbgsym_$ZERO_GPU_VERSION.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/$COMPUTE_VERSION/intel-level-zero-gpu_$ZERO_GPU_VERSION.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/$COMPUTE_VERSION/intel-opencl-icd-dbgsym_"$COMPUTE_VERSION"_amd64.ddeb
curl -O -L https://github.com/intel/compute-runtime/releases/download/$COMPUTE_VERSION/intel-opencl-icd_"$COMPUTE_VERSION"_amd64.deb
curl -O -L https://github.com/intel/compute-runtime/releases/download/$COMPUTE_VERSION/libigdgmm12_$LIBIGDGMM_VERSION.deb
set +e
dpkg -i *.deb
set -e
# the legacy + latest process says this may be necessary but it does not seem to be in a clean environment.
apt-get install --fix-broken
cd /tmp && rm -rf /tmp/gpu

View File

@@ -38,15 +38,15 @@ set -e
rm -rf /tmp/npu && mkdir -p /tmp/npu && cd /tmp/npu
# level zero must also be installed
LEVEL_ZERO_VERSION=1.18.5
LEVEL_ZERO_VERSION=1.19.2
# https://github.com/oneapi-src/level-zero
curl -O -L https://github.com/oneapi-src/level-zero/releases/download/v"$LEVEL_ZERO_VERSION"/level-zero_"$LEVEL_ZERO_VERSION"+u$distro.deb
curl -O -L https://github.com/oneapi-src/level-zero/releases/download/v"$LEVEL_ZERO_VERSION"/level-zero-devel_"$LEVEL_ZERO_VERSION"+u$distro.deb
# npu driver
# https://github.com/intel/linux-npu-driver
NPU_VERSION=1.10.0
NPU_VERSION_DATE=20241107-11729849322
NPU_VERSION=1.13.0
NPU_VERSION_DATE=20250131-13074932693
curl -O -L https://github.com/intel/linux-npu-driver/releases/download/v"$NPU_VERSION"/intel-driver-compiler-npu_$NPU_VERSION."$NPU_VERSION_DATE"_ubuntu$distro.deb
# firmware can only be installed on host. will cause problems inside container.
if [ -n "$INTEL_FW_NPU" ]

View File

@@ -36,9 +36,8 @@ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --yes --dea
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt -y update
# is there a way to get a versioned package automatically?
apt -y install nvidia-utils-560
apt -y install cuda-drivers
apt -y install nvidia-container-toolkit
nvidia-ctk runtime configure --runtime=docker
nvidia-ctk config --set nvidia-container-cli.no-cgroups --in-place
systemctl restart docker

View File

@@ -0,0 +1,55 @@
table ip nat {
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
jump postrouting_scrypted
}
chain postrouting_scrypted {
}
chain PREROUTING {
type nat hook prerouting priority dstnat; policy accept;
jump prerouting_scrypted;
}
chain prerouting_scrypted {
}
}
table ip filter {
chain FORWARD {
type filter hook forward priority filter; policy drop;
jump forward_scrypted
}
chain forward_scrypted {
}
}
table ip6 nat {
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
jump postrouting_scrypted
}
chain postrouting_scrypted {
}
chain PREROUTING {
type nat hook prerouting priority dstnat; policy accept;
jump prerouting_scrypted;
}
chain prerouting_scrypted {
}
}
table ip6 filter {
chain FORWARD {
type filter hook forward priority filter; policy drop;
jump forward_scrypted
}
chain forward_scrypted {
}
}

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Scrypted DHCP Watcher
After=network.target
[Service]
ExecStart=/etc/dhcp/scrypted-dhcp-watcher
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,17 @@
[Unit]
Description=ipv6 forwarding
After=network.target
Conflicts=shutdown.target
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=bash -c "sysctl -w net.ipv4.ip_forward=1 && sysctl -w net.ipv6.conf.all.forwarding=1 && sysctl -w net.ipv6.conf.default.forwarding=1"
ExecReload=bash -c "sysctl -w net.ipv4.ip_forward=1 && sysctl -w net.ipv6.conf.all.forwarding=1 && sysctl -w net.ipv6.conf.default.forwarding=1"
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,18 @@
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
After=network.target
Conflicts=shutdown.target
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft -f /etc/nftables.conf
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,24 @@
[Unit]
Description=Scrypted
After=network.target
[Service]
WorkingDirectory=/server
ExecStart=/bin/sh -c "ulimit -c 0; exec npm exec scrypted-serve"
Restart=always
RestartSec=5
Environment="SCRYPTED_INSTALL_ENVIRONMENT=docker"
Environment="SCRYPTED_CAN_RESTART=true"
Environment="SCRYPTED_VOLUME=/server/volume"
Environment="SCRYPTED_INSTALL_PATH=/server"
Environment="SCRYPTED_PYTHON_PATH=/usr/bin/python3"
Environment="SCRYPTED_PYTHON312_PATH=/usr/bin/python3.12"
Environment="SCRYPTED_DOCKER_FLAVOR=lite"
Environment="DEBIAN_FRONTEND=noninteractive"
Environment="NODE_OPTIONS=--dns-result-order=ipv4first"
Environment="SCRYPTED_BASE_VERSION=20250101"
Environment="SHELL=/bin/bash"
[Install]
WantedBy=multi-user.target

View File

@@ -128,7 +128,7 @@ then
set -e
removescryptedfstab
mkdir -p /mnt/scrypted-nvr
echo "PARTLABEL=scrypted-nvr /mnt/scrypted-nvr ext4 defaults,nofail,noatime 0 0" >> /etc/fstab
echo "UUID=$UUID /mnt/scrypted-nvr ext4 defaults,nofail,noatime,x-systemd.automount 0 0" >> /etc/fstab
mount -a
systemctl daemon-reload
set +e

View File

@@ -26,8 +26,8 @@ RUN add-apt-repository -y ppa:deadsnakes/ppa && \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install debugpy typing_extensions psutil
# RUN python3.9 -m pip install --upgrade pip
RUN python3.9 -m pip install debugpy
# Coral Edge TPU
# https://coral.ai/docs/accelerator/get-started/#runtime-on-linux
@@ -35,16 +35,20 @@ RUN echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" |
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
RUN apt-get -y update && apt-get -y install libedgetpu1-std
# set default shell to bash
RUN chsh -s /bin/bash
ENV SHELL="/bin/bash"
ENV SCRYPTED_INSTALL_ENVIRONMENT="docker"
ENV SCRYPTED_CAN_RESTART="true"
ENV SCRYPTED_VOLUME="/server/volume"
ENV SCRYPTED_INSTALL_PATH="/server"
RUN test -f "/usr/bin/ffmpeg" && test -f "/usr/bin/python3" && test -f "/usr/bin/python3.9" && test -f "/usr/bin/python3.10"
RUN test -f "/usr/bin/ffmpeg" && test -f "/usr/bin/python3" && test -f "/usr/bin/python3.9" && test -f "/usr/bin/python3.12"
ENV SCRYPTED_FFMPEG_PATH="/usr/bin/ffmpeg"
ENV SCRYPTED_PYTHON_PATH="/usr/bin/python3"
ENV SCRYPTED_PYTHON39_PATH="/usr/bin/python3.9"
ENV SCRYPTED_PYTHON310_PATH="/usr/bin/python3.10"
ENV SCRYPTED_PYTHON312_PATH="/usr/bin/python3.12"
ENV SCRYPTED_DOCKER_FLAVOR="full"

View File

@@ -3,7 +3,7 @@
# This common file will be used by both Docker and the linux
# install script.
################################################################
ARG BASE="jammy"
ARG BASE="noble"
FROM ubuntu:${BASE} as header
ENV DEBIAN_FRONTEND=noninteractive
@@ -16,7 +16,7 @@ RUN apt-get update && apt-get -y install \
apt-get -y update && \
apt-get -y upgrade
ARG NODE_VERSION=20
ARG NODE_VERSION=22
RUN apt-get install -y ca-certificates curl gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg
@@ -48,8 +48,9 @@ RUN apt-get -y install \
# allow pip to install to system
RUN rm -f /usr/lib/python**/EXTERNALLY-MANAGED
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install debugpy typing_extensions psutil
# ERROR: Cannot uninstall pip 24.0, RECORD file not found. Hint: The package was installed by debian.
# RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install debugpy
################################################################
# End section generated from template/Dockerfile.full.header

View File

@@ -39,12 +39,16 @@ launchctl unload ~/Library/LaunchAgents/app.scrypted.server.plist || echo ""
echo "Installing Scrypted dependencies..."
RUN_IGNORE xcode-select --install
RUN brew update
RUN_IGNORE brew install node@20
# dlib
RUN brew install cmake
# seems to be necessary for python-codecs' pycairo dependency or something?
RUN_IGNORE gobject-introspection libffi pkg-config
# in sequoia, brew node is unusable because it is not signed and can't access local network unless run as root.
# https://developer.apple.com/forums/thread/766270
# RUN_IGNORE brew install node@20
# NODE_PATH=$(brew --prefix node@20)
# NODE_BIN_PATH=$NODE_PATH/bin
RUN_IGNORE curl -L https://nodejs.org/dist/v22.14.0/node-v22.14.0.pkg -o /tmp/node.pkg
RUN_IGNORE sudo installer -pkg /tmp/node.pkg -target /
NODE_PATH=/usr/local # used to pass var test
NODE_BIN_PATH=/usr/local/bin
# gstreamer plugins
RUN_IGNORE brew install gstreamer
@@ -69,24 +73,25 @@ then
fi
RUN python$PYTHON_VERSION -m pip install --upgrade pip
# besides debugpy, none of these dependencies are needed anymore?
# portable python includes typing and does not need typing_extensions.
# opencv-python-headless has wheels for macos.
if [ "$PYTHON_VERSION" != "3.10" ]
then
RUN python$PYTHON_VERSION -m pip install typing
fi
RUN python$PYTHON_VERSION -m pip install debugpy typing_extensions opencv-python psutil
RUN python$PYTHON_VERSION -m pip install debugpy typing_extensions opencv-python
echo "Installing Scrypted Launch Agent..."
RUN mkdir -p ~/Library/LaunchAgents
NODE_PATH=$(brew --prefix node@20)
if [ ! -d "$NODE_PATH" ]
then
echo "Unable to determine node@20 path."
exit 1
fi
NODE_BIN_PATH=$NODE_PATH/bin
if [ ! -d "$NODE_BIN_PATH" ]
then
echo "Unable to determine node@20 bin path."
@@ -152,7 +157,7 @@ cat > ~/Library/LaunchAgents/app.scrypted.server.plist <<EOT
<key>NODE_OPTIONS</key>
<string>$NODE_OPTIONS</string>
<key>PATH</key>
<string>$NODE_BIN_PATH:$PYTHON_BIN_PATH:$BREW_PREFIX/bin:$BREW_PREFIX/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
<string>$PYTHON_BIN_PATH:$NODE_BIN_PATH:$BREW_PREFIX/bin:$BREW_PREFIX/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
<key>HOME</key>
<string>/Users/$USER</string>
<key>SCRYPTED_PYTHON_PATH</key>

View File

@@ -1,3 +1,14 @@
# Check if the script is running as administrator
$IsAdmin = [System.Security.Principal.WindowsPrincipal] [System.Security.Principal.WindowsIdentity]::GetCurrent()
$AdminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
if (-not $IsAdmin.IsInRole($AdminRole)) {
# If not, relaunch the script with elevated privileges
$ScriptPath = $PSCommandPath
Start-Process powershell -ArgumentList "-File `"$ScriptPath`"" -Verb RunAs
exit
}
# Set-PSDebug -Trace 1
# stop existing service if any
@@ -8,7 +19,7 @@ sc.exe stop scrypted.exe
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
# Install node.js
choco upgrade -y nodejs-lts --version=20.11.1
choco upgrade -y nodejs-lts --version=20.18.0
# Install VC Redist, which is necessary for portable python
choco install -y vcredist140
@@ -22,11 +33,19 @@ $SCRYPTED_WINDOWS_PYTHON_VERSION="-3.9"
# Refresh environment variables for py and npx to work
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
# Workaround Windows Node no longer creating %APPDATA%\npm which causes npx to fail
# Fixed in newer versions of NPM but not the one bundled with Node 20
# https://github.com/nodejs/node/issues/53538
npm i -g npm
py $SCRYPTED_WINDOWS_PYTHON_VERSION -m pip install --upgrade pip
# besides debugpy, none of these dependencies are needed anymore?
# portable python includes typing and does not need typing_extensions.
# opencv-python-headless has wheels for windows.
py $SCRYPTED_WINDOWS_PYTHON_VERSION -m pip install debugpy typing_extensions typing opencv-python
$SCRYPTED_INSTALL_VERSION=[System.Environment]::GetEnvironmentVariable("SCRYPTED_INSTALL_VERSION","User")
if ($SCRYPTED_INSTALL_VERSION -eq $null) {
npx -y scrypted@latest install-server
} else {
@@ -41,6 +60,8 @@ npm install --prefix $SCRYPTED_HOME @koush/node-windows --save
$NPX_PATH = (Get-Command npx).Path
# The path needs double quotes to handle spaces in the directory path
$NPX_PATH_ESCAPED = '"' + $NPX_PATH.replace('\', '\\') + '"'
# On newer versions of NPM, the NPX might be a .ps1 file which doesn't work with child_process.spawn, change to .cmd
$NPX_PATH_ESCAPED = $NPX_PATH_ESCAPED.replace('.ps1', '.cmd')
$SERVICE_JS = @"
const fs = require('fs');
@@ -54,6 +75,8 @@ child_process.spawn('$NPX_PATH_ESCAPED', ['-y', 'scrypted', 'serve'], {
stdio: 'inherit',
// allow spawning .cmd https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: true,
}).on('error', (err) => {
console.error('Error spawning child process', err);
});
"@
@@ -99,6 +122,9 @@ svc.on("install", () => {
svc.on("start", () => {
console.log("Service started");
});
svc.on("error", (err) => {
console.log("Service error", err);
});
svc.install();
"@

18
install/proxmox/docker-compose.sh Normal file → Executable file
View File

@@ -4,21 +4,15 @@ cd /root/.scrypted
# always immediately upgrade everything in case there's a broken update.
# this will also be preferable for troubleshooting via lxc reboot.
export DEBIAN_FRONTEND=noninteractive
(apt -y --fix-broken install && (yes | dpkg --configure -a) && apt -y update && apt -y dist-upgrade) &
yes | dpkg --configure -a
apt -y --fix-broken install && apt -y update && apt -y dist-upgrade
# foreground pull if requested.
if [ -e "volume/.pull" ]
then
rm -rf volume/.pull
PULL="--pull"
(sleep 300 && docker container prune -f && docker image prune -a -f) &
else
# always background pull in case there's a broken image.
(sleep 300 && docker compose pull && docker container prune -f && docker image prune -a -f) &
fi
# force a pull to ensure we have the latest images.
# not using --pull always cause that fails everything on network down
docker compose pull
# do not daemonize, when it exits, systemd will restart it.
# force a recreate as .env may have changed.
# furthermore force recreate gets the container back into a known state
# which is preferable in case the user has made manual changes and then restarts.
WATCHTOWER_HTTP_API_TOKEN=$(echo $RANDOM | md5sum | head -c 32) docker compose up --force-recreate --abort-on-container-exit $PULL
WATCHTOWER_HTTP_API_TOKEN=$(echo $RANDOM | md5sum | head -c 32) docker compose up --force-recreate --abort-on-container-exit

View File

@@ -18,7 +18,7 @@ function readyn() {
}
cd /tmp
SCRYPTED_VERSION=v0.120.0
SCRYPTED_VERSION=v0.137.0
SCRYPTED_TAR_ZST=scrypted-$SCRYPTED_VERSION.tar.zst
if [ -z "$VMID" ]
then
@@ -26,8 +26,7 @@ then
fi
SCRYPTED_BACKUP_VMID=10445
if [ -n "$SCRYPTED_RESTORE" ]
then
function prepareScryptedRestore() {
pct config $VMID 2>&1 > /dev/null
if [ "$?" != "0" ]
then
@@ -43,6 +42,11 @@ then
RESTORE_VMID=$VMID
VMID=$SCRYPTED_BACKUP_VMID
pct destroy $VMID 2>&1 > /dev/null
}
if [ -n "$SCRYPTED_RESTORE" ]
then
prepareScryptedRestore
fi
echo "Downloading scrypted container backup."
@@ -71,31 +75,56 @@ then
echo ""
echo "==============================================================="
echo "Existing container $VMID found."
echo "Please choose from the following options to resolve this error."
echo "==============================================================="
echo ""
echo "1. To reinstall and reset Scrypted, run this script with --force to overwrite the existing container."
echo "THIS WILL WIPE THE EXISTING CONFIGURATION:"
echo ""
echo "VMID=$VMID bash $0 --force"
echo ""
echo "2. To reinstall Scrypted and and retain existing configuration, run this script with the environment variable SCRYPTED_RESTORE=true."
echo "This script can be used ro reinstall Scrypted and reset the container to a factory state."
echo "This preserves existing data. Creating a backup within Scrypted is highly recommended in case the reset fails."
echo "THIS WILL WIPE ADDITIONAL VOLUMES SUCH AS NVR STORAGE. NVR volumes will need to be readded after the restore:"
echo ""
echo "SCRYPTED_RESTORE=true VMID=$VMID bash $0"
echo ""
echo "3. To install and run multiple Scrypted containers, run this script with the environment variable specifying"
echo "the new VMID=<number>. For example, to create a new LXC with VMID 12345:"
echo ""
echo "VMID=12345 bash $0"
readyn "Reinstall Scrypted and and retain existing configuration?"
exit 1
if [ "$yn" != "y" ]
then
echo ""
echo "1. To reinstall and reset Scrypted, run this script with --force to overwrite the existing container."
echo "THIS WILL WIPE THE EXISTING CONFIGURATION:"
echo ""
echo "VMID=$VMID bash $0 --force"
echo ""
echo "2. To reinstall Scrypted and and retain existing configuration, run this script with the environment variable SCRYPTED_RESTORE=true."
echo "This preserves existing data. Creating a backup within Scrypted is highly recommended in case the reset fails."
echo "THIS WILL WIPE ADDITIONAL VOLUMES SUCH AS NVR STORAGE. NVR volumes will need to be readded after the restore:"
echo ""
echo "SCRYPTED_RESTORE=true VMID=$VMID bash $0"
echo ""
echo "3. To install and run multiple Scrypted containers, run this script with the environment variable specifying"
echo "the new VMID=<number>. For example, to create a new LXC with VMID 12345:"
echo ""
echo "VMID=12345 bash $0"
exit 1
fi
SCRYPTED_RESTORE=true
prepareScryptedRestore
fi
fi
if [[ ! "$@" =~ "--storage" ]]
then
HAS_LOCAL_LVM=$(pvesm status | grep local-lvm | grep active)
HAS_LOCAL_ZFS=$(pvesm status | grep local-zfs | grep active)
if [ ! -z "$HAS_LOCAL_LVM" ]
then
RESTORE_STORAGE="--storage local-lvm"
elif [ ! -z "$HAS_LOCAL_ZFS" ]
then
RESTORE_STORAGE="--storage local-zfs"
else
echo "Could not determine a valid storage device. One may need to be specified manually."
fi
fi
pct stop $VMID 2>&1 > /dev/null
pct restore $VMID $SCRYPTED_TAR_ZST $@
pct restore $VMID $SCRYPTED_TAR_ZST $RESTORE_STORAGE $@
if [ "$?" != "0" ]
then
@@ -110,7 +139,12 @@ then
echo "#############################################################################"
echo -e "\033[32mPaste the following command into this shell to install to local-lvm instead:\033[0m"
echo ""
echo "bash $0 --storage local-lvm"
if [ -n "$SCRYPTED_RESTORE" ]
then
echo "bash $0 --storage local-lvm"
else
echo "SCRYPTED_RESTORE=true bash $0 --storage local-lvm"
fi
echo "#############################################################################"
echo ""
echo ""
@@ -150,7 +184,7 @@ if [ -n "$SCRYPTED_RESTORE" ]
then
echo ""
echo ""
echo "Running this script will reset the Scrypted container to a factory state while preserving existing data."
echo "This script will reset the Scrypted container to a factory state while preserving existing data."
echo "IT IS RECOMMENDED TO CREATE A BACKUP INSIDE SCRYPTED FIRST."
readyn "Are you sure you want to continue?"
if [ "$yn" != "y" ]
@@ -220,7 +254,7 @@ then
VMID=$RESTORE_VMID
echo "Restoring with reset image..."
pct restore --force 1 $VMID *.tar $@
pct restore --force 1 $VMID *.tar $RESTORE_STORAGE $@
echo "Restoring volumes..."
move_volume $SCRYPTED_BACKUP_VMID $VMID mp0 hide-warning
@@ -233,6 +267,9 @@ then
pct destroy $SCRYPTED_BACKUP_VMID
fi
echo "Enabling startup on boot..."
pct set $VMID -onboot 1
readyn "Add udev rule for hardware acceleration? This may conflict with existing rules."
if [ "$yn" == "y" ]
then

View File

@@ -27,7 +27,7 @@ echo "external/werift > npm install"
npm install
popd
for directory in rtsp amcrest onvif hikvision reolink unifi-protect webrtc homekit
for directory in rtsp ffmpeg-camera amcrest onvif hikvision reolink unifi-protect webrtc homekit
do
echo "$directory > npm install"
pushd plugins/$directory

View File

@@ -9,23 +9,23 @@
"version": "1.3.20",
"license": "ISC",
"dependencies": {
"@scrypted/client": "^1.3.3",
"@scrypted/types": "^0.3.30",
"engine.io-client": "^6.5.3",
"@scrypted/client": "^1.3.13",
"@scrypted/types": "^0.5.9",
"engine.io-client": "^6.6.3",
"readline-sync": "^1.4.10",
"semver": "^7.5.4",
"tslib": "^2.6.2"
"semver": "^7.7.1",
"tslib": "^2.8.1"
},
"bin": {
"scrypted": "dist/packages/cli/src/main.js"
},
"devDependencies": {
"@types/node": "^20.9.4",
"@types/node": "^22.13.10",
"@types/readline-sync": "^1.4.8",
"@types/semver": "^7.5.6",
"rimraf": "^5.0.5",
"ts-node": "^10.9.1",
"typescript": "^5.3.2"
"@types/semver": "^7.5.8",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.2"
}
},
"node_modules/@cspotcode/source-map-support": {
@@ -44,6 +44,7 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -81,30 +82,24 @@
"@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",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"optional": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@scrypted/client": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@scrypted/client/-/client-1.3.3.tgz",
"integrity": "sha512-Wuy7x02TCRy1buaDNX8NOIaL1j4ZXu4dqTTJsKHlPe3+umsBvpwbylD+YyyU8ghQJC6a40Bs5UMsvnCvNa/1fg==",
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/@scrypted/client/-/client-1.3.13.tgz",
"integrity": "sha512-jxXnGCoHIwuB7PobPJyqYy9THljR2UJOILxO++HiNq/i0nqRUECYvVfU5frN/ZnP6nmQoiRKrl8ErGWVBT7ecg==",
"license": "ISC",
"dependencies": {
"@scrypted/types": "^0.3.4",
"engine.io-client": "^6.5.3",
"follow-redirects": "^1.15.4",
"rimraf": "^5.0.5"
"engine.io-client": "^6.6.3",
"follow-redirects": "^1.15.9",
"rimraf": "^6.0.1"
},
"peerDependencies": {
"@scrypted/types": "^0.5.9"
}
},
"node_modules/@scrypted/types": {
"version": "0.3.30",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.30.tgz",
"integrity": "sha512-1k+JVSR6WSNmE/5mLdqfrTmV3uRbvZp0OwKb8ikNi39ysBuC000tQGcEdXZqhYqRgWdhDTWtxXe9XsYoAZGKmA==",
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.5.9.tgz",
"integrity": "sha512-Qt/gLdzDqYwgOArpLrEErPb91mhAOmN0NFFOFwX9G/5vSV5Xvm6ixQhPWF4f+up3G9ecPVPMPtZCsWmhxAD1hA==",
"license": "ISC"
},
"node_modules/@socket.io/component-emitter": {
@@ -137,12 +132,13 @@
"dev": true
},
"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": "22.13.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
"undici-types": "~6.20.0"
}
},
"node_modules/@types/readline-sync": {
@@ -152,10 +148,11 @@
"dev": true
},
"node_modules/@types/semver": {
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true,
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.8.2",
@@ -179,9 +176,10 @@
}
},
"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==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -193,6 +191,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -209,12 +208,14 @@
"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=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -223,6 +224,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -233,7 +235,8 @@
"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=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/create-require": {
"version": "1.1.1",
@@ -242,9 +245,10 @@
"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==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -282,23 +286,26 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"license": "MIT"
},
"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=="
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"license": "MIT"
},
"node_modules/engine.io-client": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-parser": {
@@ -310,15 +317,16 @@
}
},
"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==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -329,11 +337,12 @@
}
},
"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==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.0",
"cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
@@ -344,21 +353,23 @@
}
},
"node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
"integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
"license": "ISC",
"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"
"jackspeak": "^4.0.1",
"minimatch": "^10.0.0",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=16 || 14 >=14.17"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -368,6 +379,7 @@
"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==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -375,34 +387,31 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz",
"integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": ">=14"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
"integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==",
"license": "ISC",
"engines": {
"node": ">=10"
"node": "20 || >=22"
}
},
"node_modules/make-error": {
@@ -412,23 +421,25 @@
"dev": true
},
"node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
"node": "20 || >=22"
},
"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==",
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
@@ -438,37 +449,37 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"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==",
"license": "MIT",
"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==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz",
"integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==",
"engines": {
"node": "14 || >=16.14"
}
},
"node_modules/readline-sync": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
@@ -478,29 +489,29 @@
}
},
"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==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
"integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==",
"license": "ISC",
"dependencies": {
"glob": "^10.3.7"
"glob": "^11.0.0",
"package-json-from-dist": "^1.0.0"
},
"bin": {
"rimraf": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=14"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -512,6 +523,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -523,6 +535,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -531,6 +544,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"license": "ISC",
"engines": {
"node": ">=14"
},
@@ -542,6 +556,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -559,6 +574,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -572,6 +588,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -579,12 +596,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -596,6 +615,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
@@ -611,6 +631,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -622,15 +643,17 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ts-node": {
"version": "10.9.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -670,15 +693,17 @@
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"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.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -688,10 +713,11 @@
}
},
"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
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
@@ -703,6 +729,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
@@ -717,6 +744,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -734,6 +762,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -750,6 +779,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -758,6 +788,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -771,12 +802,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -790,6 +823,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -798,15 +832,16 @@
}
},
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
@@ -818,18 +853,13 @@
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",

View File

@@ -16,19 +16,19 @@
"author": "",
"license": "ISC",
"dependencies": {
"@scrypted/client": "^1.3.3",
"@scrypted/types": "^0.3.30",
"engine.io-client": "^6.5.3",
"@scrypted/client": "^1.3.13",
"@scrypted/types": "^0.5.9",
"engine.io-client": "^6.6.3",
"readline-sync": "^1.4.10",
"semver": "^7.5.4",
"tslib": "^2.6.2"
"semver": "^7.7.1",
"tslib": "^2.8.1"
},
"devDependencies": {
"@types/node": "^20.9.4",
"@types/node": "^22.13.10",
"@types/readline-sync": "^1.4.8",
"@types/semver": "^7.5.6",
"rimraf": "^5.0.5",
"ts-node": "^10.9.1",
"typescript": "^5.3.2"
"@types/semver": "^7.5.8",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.2"
}
}

View File

@@ -166,8 +166,6 @@ async function main() {
}
}
const args = ffmpegInput.inputArguments ? [...ffmpegInput.inputArguments] : [];
if (ffmpegInput.h264FilterArguments)
args.push(...ffmpegInput.h264FilterArguments);
console.log('ffplay', ...args);
child_process.spawn('ffplay', args, {
stdio: 'inherit',

View File

@@ -7,7 +7,7 @@ export async function connectShell(sdk: ScryptedStatic, ...cmd: string[]) {
throw Error("@scrypted/core does not provide a Terminal Service");
}
const termSvcDirect = await sdk.connectRPCObject<StreamService>(termSvc);
const termSvcDirect = await sdk.connectRPCObject<StreamService<Buffer|string, Buffer>>(termSvc);
const dataQueue = createAsyncQueue<Buffer>();
const ctrlQueue = createAsyncQueue<any>();

View File

@@ -1,24 +1,27 @@
{
"name": "@scrypted/client",
"version": "1.3.6",
"version": "1.3.13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/client",
"version": "1.3.6",
"version": "1.3.13",
"license": "ISC",
"dependencies": {
"@scrypted/types": "^0.3.66",
"engine.io-client": "^6.6.1",
"engine.io-client": "^6.6.3",
"follow-redirects": "^1.15.9",
"rimraf": "^6.0.1"
},
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^22.7.4",
"@types/node": "^22.13.10",
"@types/ws": "^8.18.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
"typescript": "^5.8.2"
},
"peerDependencies": {
"@scrypted/types": "^0.5.12"
}
},
"node_modules/@cspotcode/source-map-support": {
@@ -26,6 +29,7 @@
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
@@ -37,6 +41,7 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -50,87 +55,110 @@
}
},
"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==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"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
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"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,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@scrypted/types": {
"version": "0.3.66",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.66.tgz",
"integrity": "sha512-POHpVgW6Ce8mnJRaXZRm+2RtvFuPP+ZehsDrhUqkQdxmnV81m8K2+3M6Vhrt+07kNDXmrznAijoj/OzXkdZWgw=="
"version": "0.5.12",
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.5.12.tgz",
"integrity": "sha512-nTwcMHZyH3nXThL22eNcVw7OjSyL5qoTgUay6K7y43HKz1mBnFEmIUkW8eLdyP4nbpwwA0b60MOPDKZVnssB0Q==",
"license": "ISC",
"peer": true
},
"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=="
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"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
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
"dev": true,
"license": "MIT"
},
"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
"dev": true,
"license": "MIT"
},
"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
"dev": true,
"license": "MIT"
},
"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
"dev": true,
"license": "MIT"
},
"node_modules/@types/ip": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.3.tgz",
"integrity": "sha512-64waoJgkXFTYnCYDUWgSATJ/dXEBanVkaP5d4Sbk7P6U7cTTMhxVyROTckc6JKdwCrgnAjZMn0k3177aQxtDEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "22.7.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
"integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
"version": "22.13.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
"undici-types": "~6.20.0"
}
},
"node_modules/@types/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -139,10 +167,14 @@
}
},
"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==",
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
@@ -151,6 +183,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -162,6 +195,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -173,17 +207,20 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
"dev": true,
"license": "MIT"
},
"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=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -192,6 +229,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -202,18 +240,21 @@
"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=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"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
"dev": true,
"license": "MIT"
},
"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==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -224,11 +265,12 @@
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -244,6 +286,7 @@
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
@@ -251,17 +294,20 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"license": "MIT"
},
"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=="
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"license": "MIT"
},
"node_modules/engine.io-client": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz",
"integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==",
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
@@ -271,9 +317,10 @@
}
},
"node_modules/engine.io-parser": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
@@ -288,6 +335,7 @@
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -298,11 +346,12 @@
}
},
"node_modules/foreground-child": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.0",
"cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
@@ -313,9 +362,10 @@
}
},
"node_modules/glob": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz",
"integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
"integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^4.0.1",
@@ -338,6 +388,7 @@
"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==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -345,12 +396,14 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jackspeak": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz",
"integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz",
"integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
@@ -362,9 +415,10 @@
}
},
"node_modules/lru-cache": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz",
"integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==",
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
"integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==",
"license": "ISC",
"engines": {
"node": "20 || >=22"
}
@@ -373,12 +427,14 @@
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
"dev": true,
"license": "ISC"
},
"node_modules/minimatch": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -393,24 +449,28 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"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==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -419,6 +479,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
@@ -434,6 +495,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
"integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==",
"license": "ISC",
"dependencies": {
"glob": "^11.0.0",
"package-json-from-dist": "^1.0.0"
@@ -452,6 +514,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -463,6 +526,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -471,6 +535,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"license": "ISC",
"engines": {
"node": ">=14"
},
@@ -482,6 +547,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -499,6 +565,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -512,6 +579,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -519,12 +587,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -536,6 +606,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
@@ -551,6 +622,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -562,6 +634,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -571,6 +644,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -610,10 +684,11 @@
}
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -623,21 +698,24 @@
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"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
"dev": true,
"license": "MIT"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
@@ -652,6 +730,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -669,6 +748,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -685,6 +765,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -693,6 +774,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -706,12 +788,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -725,6 +809,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -736,6 +821,7 @@
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
@@ -753,9 +839,9 @@
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
"integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
@@ -765,6 +851,7 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/client",
"version": "1.3.6",
"version": "1.3.13",
"description": "",
"main": "dist/packages/client/src/index.js",
"scripts": {
@@ -13,13 +13,16 @@
"license": "ISC",
"devDependencies": {
"@types/ip": "^1.1.3",
"@types/node": "^22.7.4",
"@types/node": "^22.13.10",
"@types/ws": "^8.18.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
"typescript": "^5.8.2"
},
"peerDependencies": {
"@scrypted/types": "^0.5.12"
},
"dependencies": {
"@scrypted/types": "^0.3.66",
"engine.io-client": "^6.6.1",
"engine.io-client": "^6.6.3",
"follow-redirects": "^1.15.9",
"rimraf": "^6.0.1"
}

View File

@@ -535,7 +535,7 @@ export async function connectScryptedClient(options: ScryptedClientOptions): Pro
check.on('message', data => {
if (data.constructor === Buffer || data.constructor === ArrayBuffer) {
serializer.onMessageBuffer(Buffer.from(data));
serializer.onMessageBuffer(Buffer.from(data as string));
}
else {
serializer.onMessageFinish(JSON.parse(data as string));
@@ -683,7 +683,7 @@ export async function connectScryptedClient(options: ScryptedClientOptions): Pro
});
socket.on('message', data => {
if (data.constructor === Buffer || data.constructor === ArrayBuffer) {
serializer.onMessageBuffer(Buffer.from(data));
serializer.onMessageBuffer(Buffer.from(data as string));
}
else {
serializer.onMessageFinish(JSON.parse(data as string));
@@ -700,6 +700,7 @@ export async function connectScryptedClient(options: ScryptedClientOptions): Pro
deviceManager,
endpointManager,
mediaManager,
clusterManager,
} = scrypted;
console.log('api attached', Date.now() - start);
@@ -859,6 +860,7 @@ export async function connectScryptedClient(options: ScryptedClientOptions): Pro
connectionType,
admin,
systemManager,
clusterManager,
deviceManager,
endpointManager,
mediaManager,

View File

@@ -1,4 +1,4 @@
{
"scrypted.debugHost": "127.0.0.1",
"scrypted.debugHost": "scrypted-server",
}

View File

@@ -1,6 +1,21 @@
<details>
<summary>Changelog</summary>
### 0.3.6
alexa: maybe fix alexa when no detection types are available
### 0.3.4
Alexa: add option to not auto enable devices (#1615)
### 0.3.3
google-home/alexa: republish with new sdk for media converter
### 0.3.2
alexa: fix syncedDevices being undefined

View File

@@ -1,11 +1,12 @@
{
"name": "@scrypted/alexa",
"version": "0.3.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/alexa",
"version": "0.3.4",
"version": "0.3.7",
"dependencies": {
"axios": "^1.3.4",
"uuid": "^9.0.0"
@@ -14,7 +15,7 @@
"@scrypted/common": "../../common",
"@scrypted/sdk": "../../sdk",
"@types/debug": "^4.1.12",
"@types/node": "^18.4.2"
"@types/node": "^22.13.11"
}
},
"../../common": {
@@ -24,35 +25,41 @@
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
},
"devDependencies": {
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.5",
"version": "0.5.10",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -64,11 +71,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"../common": {
@@ -98,10 +103,14 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.14.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz",
"integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==",
"dev": true
"version": "22.13.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz",
"integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -193,6 +202,13 @@
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
@@ -202,4 +218,4 @@
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/alexa",
"version": "0.3.4",
"version": "0.3.7",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
"prescrypted-setup-project": "scrypted-package-json",
@@ -42,6 +42,6 @@
"@scrypted/common": "../../common",
"@scrypted/sdk": "../../sdk",
"@types/debug": "^4.1.12",
"@types/node": "^18.4.2"
"@types/node": "^22.13.11"
}
}

View File

@@ -660,17 +660,26 @@ class AlexaPlugin extends ScryptedDeviceBase implements HttpRequestHandler, Mixi
const deviceHandler = alexaDeviceHandlers.get(mapName);
if (deviceHandler) {
const getDevice = () => {
const device = systemManager.getDeviceById(directive.endpoint.endpointId);
if (!device) {
response.send(deviceErrorResponse("NO_SUCH_ENDPOINT", "The device doesn't exist in Scrypted", directive));
if (!device || !device.mixins.includes(this.id)) {
response.send(deviceErrorResponse("NO_SUCH_ENDPOINT", "The device doesn't exist in Scrypted or was removed from the Alexa Plugin", directive));
this.deleteEndpoints(directive.endpoint.endpointId).catch(() => { });
return;
}
return device;
}
if (deviceHandler) {
const device = getDevice();
if (!device)
return;
await deviceHandler.apply(this, [request, response, directive, device]);
return;
} else {
this.console.error(`no handler for: ${mapName}`);
if (!getDevice())
return;
}
// it is better to send a non-specific response than an error, as the API might get rate throttled
@@ -718,6 +727,9 @@ class HttpResponseLoggingImpl implements AlexaHttpResponse {
sendSocket(socket: any, options: HttpResponseOptions): void {
this.response.sendSocket(socket, options);
}
sendStream(stream: AsyncGenerator<Buffer, void>, options?: HttpResponseOptions): void {
this.response.sendStream(stream, options);
}
}
export default AlexaPlugin;

View File

@@ -126,68 +126,69 @@ export async function getCameraCapabilities(device: ScryptedDevice): Promise<Dis
];
if (device.interfaces.includes(ScryptedInterface.ObjectDetector)) {
const detectionTypes = await (device as any as ObjectDetector).getObjectTypes();
const classNames = detectionTypes.classes.filter(t => t !== 'ring' && t !== 'motion').map(type => type.toLowerCase());
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.SmartVision.ObjectDetectionSensor",
"version": "1.0",
"properties": {
"supported": [{
"name": "objectDetectionClasses"
}],
"proactivelyReported": true,
"retrievable": true
},
"configuration": {
"objectDetectionConfiguration": classNames.map(type => ({
"imageNetClass": type
}))
}
} as DiscoveryCapability
);
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.DataController",
"instance": "Camera.SmartVisionData",
"version": "1.0",
"properties": undefined,
"configuration": {
"targetCapability": {
"name": "Alexa.SmartVision.ObjectDetectionSensor",
"version": "1.0"
const detectionTypes = await (device as any as ObjectDetector).getObjectTypes().catch(() => {}) || undefined;
const classNames = detectionTypes?.classes?.filter(t => t !== 'ring' && t !== 'motion').map(type => type.toLowerCase()).filter(c => !!c);
if (classNames?.length) {
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.SmartVision.ObjectDetectionSensor",
"version": "1.0",
"properties": {
"supported": [{
"name": "objectDetectionClasses"
}],
"proactivelyReported": true,
"retrievable": true
},
"dataRetrievalSchema": {
"type": "JSON",
"schema": "SmartVisionData"
},
"supportedAccess": ["BY_IDENTIFIER", "BY_TIMESTAMP_RANGE"]
}
} as DiscoveryCapability
);
}
if (device.interfaces.includes(ScryptedInterface.MotionSensor)) {
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.MotionSensor",
"version": "3",
"properties": {
"supported": [
{
"name": "detectionState"
}
],
"proactivelyReported": true,
"retrievable": true
}
} as DiscoveryCapability
);
"configuration": {
"objectDetectionConfiguration": classNames.map(type => ({
"imageNetClass": type
}))
}
} as DiscoveryCapability
);
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.DataController",
"instance": "Camera.SmartVisionData",
"version": "1.0",
"properties": undefined,
"configuration": {
"targetCapability": {
"name": "Alexa.SmartVision.ObjectDetectionSensor",
"version": "1.0"
},
"dataRetrievalSchema": {
"type": "JSON",
"schema": "SmartVisionData"
},
"supportedAccess": ["BY_IDENTIFIER", "BY_TIMESTAMP_RANGE"]
}
} as DiscoveryCapability
);
}
if (device.interfaces.includes(ScryptedInterface.MotionSensor)) {
capabilities.push(
{
"type": "AlexaInterface",
"interface": "Alexa.MotionSensor",
"version": "3",
"properties": {
"supported": [
{
"name": "detectionState"
}
],
"proactivelyReported": true,
"retrievable": true
}
} as DiscoveryCapability
);
}
}
return capabilities;

View File

@@ -8,7 +8,7 @@ export interface SupportedType {
setState?(device: ScryptedDevice, payload: any): Promise<Partial<Report>>;
}
export const supportedTypes = new Map<ScryptedDeviceType, SupportedType>();
export const supportedTypes = new Map<ScryptedDeviceType | string, SupportedType>();
import '../handlers';
import './camera';

View File

@@ -1,4 +1,4 @@
{
"scrypted.debugHost": "127.0.0.1",
"scrypted.debugHost": "scrypted-nvr",
}

View File

@@ -1,21 +1,23 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.164",
"version": "0.0.165",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/amcrest",
"version": "0.0.164",
"version": "0.0.165",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"content-type": "^1.0.5"
"content-type": "^1.0.5",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@types/content-type": "^1.1.8",
"@types/node": "^20.11.30"
"@types/node": "^20.11.30",
"@types/xml2js": "^0.4.14"
}
},
"../../common": {
@@ -24,34 +26,40 @@
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
},
"devDependencies": {
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.29",
"version": "0.3.114",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -63,11 +71,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"node_modules/@scrypted/common": {
@@ -93,6 +99,16 @@
"undici-types": "~5.26.4"
}
},
"node_modules/@types/xml2js": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
"integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
@@ -101,11 +117,39 @@
"node": ">= 0.6"
}
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"license": "ISC"
},
"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/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"license": "MIT",
"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==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/amcrest",
"version": "0.0.164",
"version": "0.0.165",
"description": "Amcrest Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",
@@ -39,10 +39,12 @@
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"content-type": "^1.0.5"
"content-type": "^1.0.5",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@types/content-type": "^1.1.8",
"@types/node": "^20.11.30"
"@types/node": "^20.11.30",
"@types/xml2js": "^0.4.14"
}
}

View File

@@ -1,14 +1,13 @@
import { automaticallyConfigureSettings, checkPluginNeedsAutoConfigure } from "@scrypted/common/src/autoconfigure-codecs";
import { ffmpegLogInitialOutput } from '@scrypted/common/src/media-helpers';
import { readLength } from "@scrypted/common/src/read-stream";
import sdk, { Camera, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, Lock, MediaObject, MediaStreamOptions, ObjectDetectionTypes, ObjectDetector, ObjectsDetected, Reboot, RequestPictureOptions, RequestRecordingStreamOptions, ResponseMediaStreamOptions, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, ScryptedNativeId, Setting, VideoCameraConfiguration, VideoRecorder } from "@scrypted/sdk";
import sdk, { Camera, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, Lock, MediaObject, MediaStreamOptions, ObjectDetectionTypes, ObjectDetector, ObjectsDetected, Reboot, RequestPictureOptions, RequestRecordingStreamOptions, ResponseMediaStreamOptions, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, ScryptedNativeId, Setting, VideoCameraConfiguration, VideoRecorder, VideoTextOverlay, VideoTextOverlays } from "@scrypted/sdk";
import child_process, { ChildProcess } from 'child_process';
import { PassThrough, Readable, Stream } from "stream";
import { OnvifIntercom } from "../../onvif/src/onvif-intercom";
import { createRtspMediaStreamOptions, RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
import { AmcrestCameraClient, AmcrestEvent, AmcrestEventData } from "./amcrest-api";
import { amcrestAutoConfigureSettings, autoconfigureSettings } from "./amcrest-configure";
import { group } from "console";
const { mediaManager } = sdk;
@@ -23,7 +22,7 @@ const rtspChannelSetting: Setting = {
placeholder: '1',
};
class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration, Camera, Intercom, Lock, VideoRecorder, Reboot, ObjectDetector {
class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration, Camera, Intercom, Lock, VideoRecorder, Reboot, ObjectDetector, VideoTextOverlays {
eventStream: Stream;
cp: ChildProcess;
client: AmcrestCameraClient;
@@ -43,6 +42,92 @@ class AmcrestCamera extends RtspSmartCamera implements VideoCameraConfiguration,
this.updateDeviceInfo();
}
async getVideoTextOverlays(): Promise<Record<string, VideoTextOverlay>> {
const client = this.getClient();
const response = await client.request({
method: "GET",
url: `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=getConfig&name=VideoWidget`,
responseType: "text",
headers: {
"Content-Type": "application/xml",
},
});
const body: string = response.body;
if (!body.startsWith("<")) {
const encodeBlend = '.EncodeBlend';
const config: Record<string, VideoTextOverlay> = {};
for (const line of body.split(/\r?\n/).filter(l => l.includes(encodeBlend + '='))) {
const trimmed = line.trim();
if (!trimmed) continue;
const splitIndex = trimmed.indexOf("=");
if (splitIndex === -1) continue;
// remove encodeBlend
let key = trimmed.substring(0, splitIndex);
key = key.substring(0, key.length - encodeBlend.length);
config[key] = {
readonly: true,
};
}
const textValue = '.Text';
for (const line of body.split(/\r?\n/).filter(l => l.includes(textValue + '='))) {
const trimmed = line.trim();
if (!trimmed) continue;
const splitIndex = trimmed.indexOf("=");
if (splitIndex === -1) continue;
// remove encodeBlend
let key = trimmed.substring(0, splitIndex);
key = key.substring(0, key.length - textValue.length);
const text = trimmed.substring(splitIndex + 1).trim();
const c = config[key];
if (!c)
continue;
delete c.readonly;
c.text = text;
}
return config;
} else {
throw new Error('invalid response');
// const json = await xml2js.parseStringPromise(body);
// return { json, xml: body };
}
}
async setVideoTextOverlay(id: string, value: VideoTextOverlay): Promise<void> {
// trim the table. off id
if (id.startsWith('table.'))
id = id.substring('table.'.length);
const client = this.getClient();
if (value.text) {
const enableUrl = `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=setConfig&${id}.EncodeBlend=true&${id}.PreviewBlend=true`;
await client.request({
method: "GET",
url: enableUrl,
responseType: "text",
});
const textUrl = `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=setConfig&${id}.Text=${encodeURIComponent(
value.text
)}`;
await client.request({
method: "GET",
url: textUrl,
responseType: "text",
});
}
else {
const disableUrl = `http://${this.getHttpAddress()}/cgi-bin/configManager.cgi?action=setConfig&${id}.EncodeBlend=false&${id}.PreviewBlend=false`;
await client.request({
method: "GET",
url: disableUrl,
responseType: "text",
});
}
}
async reboot() {
const client = this.getClient();
await client.reboot();
@@ -631,6 +716,7 @@ class AmcrestProvider extends RtspProvider {
ScryptedInterface.Camera,
ScryptedInterface.AudioSensor,
ScryptedInterface.MotionSensor,
ScryptedInterface.VideoTextOverlays,
];
}

View File

@@ -56,13 +56,13 @@ Scrypted Cloud automatically creates a login free tunnel for remote access.
The following steps are only necessary if you want to associate the tunnel with your existing Cloudflare account to manage it remotely.
1. Create the Tunnel in the [Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com).
2. Copy the token shown for the tunnel shown in the `install [token]` command. For example, if you see `cloudflared service install eyJhI344aA...`, then `eyJhI344aA...` is the token you need to copy.
3. Paste the token into the Cloud Plugin Advanced Settings.
4. Add a `Public Hostname` to the tunnel.
* Choose a (sub)domain.
* Service `Type` is `HTTPS` and `URL` is `localhost:port`. Replace the port with `Forward Port` from Cloud Plugin Settings.
* Expand `Additional Application Settings` -> `TLS` menus and enable `No TLS Verify`.
1. Navigate to the Cloud Plugin's Cloudflare Settings.
2. Enter the Cloudflare subdomain, e.g. `scrypted.example.org`.
3. Open the authorization link printed in the Log in a browser.
4. Log in to Cloudflare if prompted. Then open the authorization link again.
5. Select the domain for the specified the subdomain.
6. Authorization should now be complete.
5. Reload Cloud Plugin.
6. Verify Cloudflare successfully connected by observing the `Console` Logs.
::: info
Visiting the authorization link twice as directed in the above instructions may be necessary. Cloudflare will not prompt a with a list of domains unless the browser session is already logged in.
:::

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@
]
},
"dependencies": {
"@eneris/push-receiver": "^4.2.0",
"@eneris/push-receiver": "^4.3.0",
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"bpmux": "^8.2.1",
@@ -48,10 +48,9 @@
},
"devDependencies": {
"@types/http-proxy": "^1.17.15",
"@types/ip": "^1.1.3",
"@types/nat-upnp": "^1.1.5",
"@types/node": "^22.5.2",
"@types/node": "^22.10.1",
"ts-node": "^10.9.2"
},
"version": "0.2.47"
"version": "0.2.49"
}

View File

@@ -183,6 +183,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings,
this.storageSettings.values.cloudflaredTunnelCredentials = undefined;
this.doCloudflaredLogin(nv);
},
console: true,
},
cloudflaredTunnelLoginUrl: {
group: 'Cloudflare',
@@ -1045,24 +1046,27 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings,
args['--url'] = tunnelUrl;
}
// if error messages are detected after 10 minutes from tunnel attempt start,
// kill the tunnel.
const tenMinutesMs = 10 * 60 * 1000;
const tunnelStart = Date.now();
const deferred = new Deferred<string>();
const cloudflareTunnel = cloudflared.tunnel(args);
deferred.resolvePromise(cloudflareTunnel.url);
const processData = (string: string) => {
this.console.error(string);
const lines = string.split('\n');
for (const line of lines) {
if ((line.includes('Unregistered tunnel connection')
|| line.includes('Connection terminated error')
|| line.includes('Register tunnel error')
|| line.includes('Failed to serve tunnel')
|| line.includes('Failed to get tunnel'))
&& deferred.finished) {
this.console.warn('Cloudflare registration failed after tunnel started. The old tunnel may be invalid. Terminating.');
&& (deferred.finished || Date.now() - tunnelStart > tenMinutesMs)) {
this.console.warn('Cloudflare registration failure detected. Terminating.');
cloudflareTunnel.child.kill();
}
if (line.includes('hostname'))
this.console.log(line);
const match = /config=(".*?}")/gm.exec(line)
if (match) {
const json = match[1];
@@ -1107,7 +1111,10 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings,
throw e;
}
this.console.log(`cloudflare url mapped ${this.cloudflareTunnel} to ${tunnelUrl}`);
return cloudflareTunnel;
return {
url: deferred.promise,
child: cloudflareTunnel.child,
};
}, {
startingDelay: 60000,
timeMultiple: 1.2,

View File

@@ -1,3 +1,3 @@
{
"scrypted.debugHost": "127.0.0.1",
"scrypted.debugHost": "scrypted-nvr",
}

View File

@@ -0,0 +1 @@
../../../../install/proxmox/docker-compose.sh

View File

@@ -1,22 +0,0 @@
[Unit]
Description=Scrypted service
After=network.target
[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/bin/npx -y scrypted serve
Restart=always
RestartSec=3
Environment="NODE_OPTIONS=--dns-result-order=ipv4first"
Environment="SCRYPTED_PYTHON_PATH=/usr/bin/python3"
Environment="SCRYPTED_PYTHON39_PATH=/usr/bin/python3.9"
Environment="SCRYPTED_PYTHON310_PATH=/usr/bin/python3.10"
Environment="SCRYPTED_FFMPEG_PATH=/usr/bin/ffmpeg"
Environment="SCRYPTED_INSTALL_ENVIRONMENT=lxc"
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/core",
"version": "0.3.86",
"version": "0.3.120",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/core",
"version": "0.3.86",
"version": "0.3.120",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",
@@ -88,21 +88,28 @@
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.63",
"version": "0.3.100",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.24.7",
"adm-zip": "^0.5.14",
"axios": "^1.7.3",
"babel-loader": "^9.1.3",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"typescript": "^5.5.4",
"webpack": "^5.93.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
@@ -115,11 +122,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^22.1.0",
"@types/stringify-object": "^4.0.5",
"stringify-object": "^3.3.0",
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.5"
"typedoc": "^0.26.11"
}
},
"node_modules/@scrypted/common": {
@@ -281,23 +286,28 @@
"@scrypted/sdk": {
"version": "file:../../sdk",
"requires": {
"@babel/preset-typescript": "^7.24.7",
"@types/node": "^22.1.0",
"@types/stringify-object": "^4.0.5",
"adm-zip": "^0.5.14",
"axios": "^1.7.3",
"babel-loader": "^9.1.3",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"@types/node": "^22.10.1",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^6.0.1",
"stringify-object": "^3.3.0",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.5",
"typescript": "^5.5.4",
"webpack": "^5.93.0",
"tslib": "^2.8.1",
"typedoc": "^0.26.11",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/core",
"version": "0.3.86",
"version": "0.3.120",
"description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.",
"author": "Scrypted",
"license": "Apache-2.0",
@@ -33,10 +33,6 @@
"ScryptedSettings",
"SystemSettings",
"Settings"
],
"pluginDependencies": [
"@scrypted/snapshot",
"@scrypted/webrtc"
]
},
"dependencies": {

View File

@@ -1,5 +1,5 @@
import sdk, { Device, DeviceCreator, DeviceCreatorSettings, DeviceProvider, Readme, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, Setting } from '@scrypted/sdk';
import { AggregateDevice, createAggregateDevice } from './aggregate';
import { AggregateDevice } from './aggregate';
const { deviceManager } = sdk;
export const AggregateCoreNativeId = 'aggregatecore';
@@ -13,24 +13,6 @@ export class AggregateCore extends ScryptedDeviceBase implements DeviceProvider,
this.systemDevice = {
deviceCreator: 'Device Group',
};
for (const nativeId of deviceManager.getNativeIds()) {
if (nativeId?.startsWith('aggregate:')) {
const aggregate = createAggregateDevice(nativeId);
this.aggregate.set(nativeId, aggregate);
this.reportAggregate(nativeId, aggregate.computeInterfaces(), aggregate.providedName);
}
}
sdk.systemManager.listen((eventSource, eventDetails, eventData) => {
if (eventDetails.eventInterface === 'Storage') {
const ids = [...this.aggregate.values()].map(a => a.id);
if (ids.includes(eventSource.id)) {
const aggregate = [...this.aggregate.values()].find(a => a.id === eventSource.id);
this.reportAggregate(aggregate.nativeId, aggregate.computeInterfaces(), aggregate.providedName);
}
}
});
}
async getReadmeMarkdown(): Promise<string> {
@@ -51,7 +33,8 @@ export class AggregateCore extends ScryptedDeviceBase implements DeviceProvider,
const { name } = settings;
const nativeId = `aggregate:${Math.random()}`;
await this.reportAggregate(nativeId, [], name?.toString());
const aggregate = createAggregateDevice(nativeId);
const aggregate = new AggregateDevice(this, nativeId);
aggregate.computeInterfaces();
this.aggregate.set(nativeId, aggregate);
return nativeId;
}
@@ -68,9 +51,17 @@ export class AggregateCore extends ScryptedDeviceBase implements DeviceProvider,
}
async getDevice(nativeId: string) {
return this.aggregate.get(nativeId);
let device = this.aggregate.get(nativeId);
if (device)
return device;
device = new AggregateDevice(this, nativeId);
device.computeInterfaces();
this.aggregate.set(nativeId, device);
return device;
}
async releaseDevice(id: string, nativeId: string): Promise<void> {
const device = this.aggregate.get(nativeId);
device?.release();
}
}

View File

@@ -1,11 +1,8 @@
import sdk, { EventListener, EventListenerRegister, FFmpegInput, LockState, MediaStreamDestination, RequestMediaStreamOptions, ResponseMediaStreamOptions, ScryptedDevice, ScryptedDeviceBase, ScryptedInterface, ScryptedInterfaceDescriptors, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera } from "@scrypted/sdk";
import { StorageSettings } from "@scrypted/sdk/storage-settings";
import type { AggregateCore } from "./aggregate-core";
const { systemManager, mediaManager, deviceManager } = sdk;
export interface AggregateDevice extends ScryptedDeviceBase {
computeInterfaces(): string[];
}
interface Aggregator<T> {
(values: T[]): T;
}
@@ -75,7 +72,6 @@ function createVideoCamera(devices: VideoCamera[], console: Console): VideoCamer
container: 'rawvideo',
mediaStreamOptions: (await createVideoStreamOptions())?.[0],
inputArguments: [],
h264FilterArguments: [],
};
for (let i = 0; i < inputs.length; i++) {
@@ -105,7 +101,7 @@ function createVideoCamera(devices: VideoCamera[], console: Console): VideoCamer
let i = dim * dim - 1;
filter.push(`[${prev}][pos${i}] overlay=shortest=1:x=${curx % 1920}:y=${cury % 1080}`);
ffmpegInput.h264FilterArguments.push(
ffmpegInput.inputArguments.push(
'-filter_complex',
filter.join(' '),
);
@@ -141,143 +137,144 @@ function createVideoCamera(devices: VideoCamera[], console: Console): VideoCamer
}
}
export function createAggregateDevice(nativeId: string): AggregateDevice {
class AggregateDeviceImpl extends ScryptedDeviceBase implements Settings {
listeners: EventListenerRegister[] = [];
storageSettings = new StorageSettings(this, {
deviceInterfaces: {
title: 'Selected Device Interfaces',
description: 'The components of other devices to combine into this device group.',
type: 'interface',
multiple: true,
deviceFilter: `id !== '${this.id}' && deviceInterface !== '${ScryptedInterface.Settings}'`,
export class AggregateDevice extends ScryptedDeviceBase implements Settings {
listeners: EventListenerRegister[] = [];
storageSettings = new StorageSettings(this, {
deviceInterfaces: {
title: 'Selected Device Interfaces',
description: 'The components of other devices to combine into this device group.',
type: 'interface',
multiple: true,
deviceFilter: `id !== '${this.id}' && deviceInterface !== '${ScryptedInterface.Settings}'`,
onPut: () => {
this.core.reportAggregate(this.nativeId, this.computeInterfaces(), this.providedName);
}
})
constructor() {
super(nativeId);
try {
const data = this.storage.getItem('data');
if (data) {
const { deviceInterfaces } = JSON.parse(data);
this.storageSettings.values.deviceInterfaces = deviceInterfaces;
}
}
catch (e) {
}
this.storage.removeItem('data');
}
})
getSettings(): Promise<Setting[]> {
return this.storageSettings.getSettings();
constructor(public core: AggregateCore, nativeId: string) {
super(nativeId);
try {
const data = this.storage.getItem('data');
if (data) {
const { deviceInterfaces } = JSON.parse(data);
this.storageSettings.values.deviceInterfaces = deviceInterfaces;
}
}
putSetting(key: string, value: SettingValue): Promise<void> {
return this.storageSettings.putSetting(key, value);
catch (e) {
}
this.storage.removeItem('data');
}
makeListener(iface: string, devices: ScryptedDevice[]) {
const aggregator = aggregators.get(iface);
if (!aggregator) {
const ds = deviceManager.getDeviceState(this.nativeId);
// if this device can't be aggregated for whatever reason, pass property through.
for (const device of devices) {
const register = device.listen({
event: iface,
watch: true,
}, (source, details, data) => {
if (details.property)
ds[details.property] = data;
});
this.listeners.push(register);
}
return;
}
const property = ScryptedInterfaceDescriptors[iface]?.properties?.[0];
if (!property) {
this.console.warn('aggregating interface with no property?', iface);
return;
}
const runAggregator = () => {
const values = devices.map(device => device[property]);
(this as any)[property] = aggregator(values);
}
const listener: EventListener = () => runAggregator();
getSettings(): Promise<Setting[]> {
return this.storageSettings.getSettings();
}
putSetting(key: string, value: SettingValue): Promise<void> {
return this.storageSettings.putSetting(key, value);
}
makeListener(iface: string, devices: ScryptedDevice[]) {
const aggregator = aggregators.get(iface);
if (!aggregator) {
const ds = deviceManager.getDeviceState(this.nativeId);
// if this device can't be aggregated for whatever reason, pass property through.
for (const device of devices) {
const register = device.listen({
event: iface,
watch: true,
}, listener);
}, (source, details, data) => {
if (details.property)
ds[details.property] = data;
});
this.listeners.push(register);
}
return runAggregator;
return;
}
computeInterfaces(): string[] {
this.listeners.forEach(listener => listener.removeListener());
this.listeners = [];
try {
const interfaces = new Map<string, string[]>();
for (const deviceInterface of this.storageSettings.values.deviceInterfaces as string[]) {
const parts = deviceInterface.split('#');
const id = parts[0];
const iface = parts[1];
if (!interfaces.has(iface))
interfaces.set(iface, []);
interfaces.get(iface).push(id);
}
for (const [iface, ids] of interfaces.entries()) {
const devices = ids.map(id => systemManager.getDeviceById(id));
const runAggregator = this.makeListener(iface, devices);
runAggregator?.();
}
for (const [iface, ids] of interfaces.entries()) {
const devices = ids.map(id => systemManager.getDeviceById(id));
const descriptor = ScryptedInterfaceDescriptors[iface];
if (!descriptor) {
this.console.warn(`descriptor not found for ${iface}, skipping method generation`);
continue;
}
if (iface === ScryptedInterface.VideoCamera) {
const camera = createVideoCamera(devices as any, this.console);
for (const method of descriptor.methods) {
AggregateDeviceImpl.prototype[method] = (...args: any[]) => camera[method](...args);
}
continue;
}
for (const method of descriptor.methods) {
AggregateDeviceImpl.prototype[method] = async function (...args: any[]) {
const ret: Promise<any>[] = [];
for (const device of devices) {
ret.push(device[method](...args));
}
const results = await Promise.all(ret);
return results[0];
}
}
}
return [...interfaces.keys()];
}
catch (e) {
// this.console.error('error loading aggregate device', e);
return [];
}
const property = ScryptedInterfaceDescriptors[iface]?.properties?.[0];
if (!property) {
this.console.warn('aggregating interface with no property?', iface);
return;
}
const runAggregator = () => {
const values = devices.map(device => device[property]);
(this as any)[property] = aggregator(values);
}
const listener: EventListener = () => runAggregator();
for (const device of devices) {
const register = device.listen({
event: iface,
watch: true,
}, listener);
this.listeners.push(register);
}
return runAggregator;
}
const ret = new AggregateDeviceImpl();
ret.computeInterfaces();
return new AggregateDeviceImpl();
}
release() {
this.listeners.forEach(listener => listener.removeListener());
this.listeners = [];
}
computeInterfaces(): string[] {
this.release();
try {
const interfaces = new Map<string, string[]>();
for (const deviceInterface of this.storageSettings.values.deviceInterfaces as string[]) {
const parts = deviceInterface.split('#');
const id = parts[0];
const iface = parts[1];
if (!interfaces.has(iface))
interfaces.set(iface, []);
interfaces.get(iface).push(id);
}
for (const [iface, ids] of interfaces.entries()) {
const devices = ids.map(id => systemManager.getDeviceById(id));
const runAggregator = this.makeListener(iface, devices);
runAggregator?.();
}
for (const [iface, ids] of interfaces.entries()) {
const devices = ids.map(id => systemManager.getDeviceById(id));
const descriptor = ScryptedInterfaceDescriptors[iface];
if (!descriptor) {
this.console.warn(`descriptor not found for ${iface}, skipping method generation`);
continue;
}
if (iface === ScryptedInterface.VideoCamera) {
const camera = createVideoCamera(devices as any, this.console);
for (const method of descriptor.methods) {
this[method] = (...args: any[]) => camera[method](...args);
}
continue;
}
for (const method of descriptor.methods) {
this[method] = async function (...args: any[]) {
const ret: Promise<any>[] = [];
for (const device of devices) {
ret.push(device[method](...args));
}
const results = await Promise.all(ret);
return results[0];
}
}
}
return [...interfaces.keys()];
}
catch (e) {
// this.console.error('error loading aggregate device', e);
return [];
}
}
}

162
plugins/core/src/cluster.ts Normal file
View File

@@ -0,0 +1,162 @@
import { createAsyncQueue } from "@scrypted/common/src/async-queue";
import sdk, { Readme, ScryptedDeviceBase, ScryptedInterface, ScryptedSettings, Setting, Settings } from "@scrypted/sdk";
export const ClusterCoreNativeId = 'clustercore';
export class ClusterCore extends ScryptedDeviceBase implements Settings, Readme, ScryptedSettings {
writeQueue = createAsyncQueue<() => Promise<void>>();
constructor(nativeId: string) {
super(nativeId);
(async () => {
for await (const write of this.writeQueue.queue) {
try {
await write();
}
catch (e) {
this.console.error('error writing settings', e);
}
finally {
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
}
}
})();
}
async getSettings(): Promise<Setting[]> {
const mode = sdk.clusterManager?.getClusterMode?.();
if (!mode)
return [];
const workers = await sdk.clusterManager.getClusterWorkers();
const ret: Setting[] = [];
const clientWorkers = Object.values(workers);
const clusterFork = await sdk.systemManager.getComponent('cluster-fork');
for (const worker of clientWorkers) {
const group = `Worker: ${worker.name}`;
const name: Setting = {
key: `${worker.id}:name`,
group,
title: 'Name',
description: 'The friendly name of the worker.',
value: worker.name,
};
ret.push(name);
const mode: Setting = {
key: `${worker.id}:mode`,
group,
title: 'Mode',
description: 'The mode of the worker.',
value: worker.mode,
readonly: true,
};
ret.push(mode);
const envControl = await clusterFork.getEnvControl(worker.id);
// catch in case env is coming from vscode launch.json and no .env actually exists.
const dotEnv: string = await envControl.getDotEnv().catch(() => {});
const dotEnvLines = dotEnv?.split('\n') || worker.labels;
const dotEnvParsed = dotEnvLines.map(line => {
const trimmed = line.trim();
if (trimmed.startsWith('#')) {
return { line };
}
const [key, ...value] = trimmed.split('=');
return { key, value: value.join('='), line };
});
const workerLabels = dotEnvParsed.find(line => line.key === 'SCRYPTED_CLUSTER_LABELS')?.value?.split(',') || [];
const labelChoices = new Set<string>([
...workerLabels,
'storage',
'compute',
'compute.preferred',
'@scrypted/coreml',
'@scrypted/openvino',
'@scrypted/onnx',
'@scrypted/tensorflow-lite',
]);
const labels: Setting = {
key: `${worker.id}:labels`,
group,
title: 'Labels',
description: 'The labels to apply to this worker. Modifying the labels will restart the worker. Some labels, such as the host OS and architecture, cannot be changed.',
multiple: true,
combobox: true,
choices: [...labelChoices],
value: workerLabels,
};
ret.push(labels);
}
return ret;
}
async putSetting(key: string, value: any) {
await this.writeQueue.enqueue(async () => {
const split = key.split(':');
const [workerId, setting] = split;
const workers = await sdk.clusterManager.getClusterWorkers();
const worker = workers[workerId];
if (!worker)
return;
switch (setting) {
case 'name':
case 'labels':
break;
default:
return;
}
const clusterFork = await sdk.systemManager.getComponent('cluster-fork');
const envControl = await clusterFork.getEnvControl(worker.id);
const dotEnv: string = await envControl.getDotEnv().catch(() => {});
const dotEnvLines = dotEnv?.split('\n') || worker.labels;
const dotEnvParsed = dotEnvLines.map(line => {
const trimmed = line.trim();
if (trimmed.startsWith('#')) {
return { line };
}
const [key, ...value] = trimmed.split('=');
return { key, value: value.join('='), line };
});
const updateDotEnv = async (key: string, newValue: string) => {
let entry = dotEnvParsed.find(line => line.key === key);
if (!entry) {
entry = { key, value: '', line: '' };
dotEnvParsed.push(entry);
}
entry.line = `${key}=${newValue}`;
await envControl.setDotEnv(dotEnvParsed.filter(line => line).map(line => line.line).join('\n'));
};
if (setting === 'labels') {
await updateDotEnv('SCRYPTED_CLUSTER_LABELS', value.join(','));
} else if (setting === 'name') {
await updateDotEnv('SCRYPTED_CLUSTER_WORKER_NAME', value);
}
setTimeout(async () => {
const serviceControl = await clusterFork.getServiceControl(worker.id);
await serviceControl.restart().catch(() => { });
}, 10000);
});
}
async getReadmeMarkdown(): Promise<string> {
return `Manage Scrypted's cluster mode. Run storage devices and compute services on separate servers.
[Read Documentation](https://docs.scrypted.app/maintenance/cluster.html).`;
}
}

View File

@@ -10,11 +10,12 @@ import { AggregateCore, AggregateCoreNativeId } from './aggregate-core';
import { AutomationCore, AutomationCoreNativeId } from './automations-core';
import { LauncherMixin } from './launcher-mixin';
import { MediaCore } from './media-core';
import { checkLxcDependencies } from './platform/lxc';
import { checkLegacyLxc, checkLxc } from './platform/lxc';
import { ConsoleServiceNativeId, PluginSocketService, ReplServiceNativeId } from './plugin-socket-service';
import { ScriptCore, ScriptCoreNativeId, newScript } from './script-core';
import { TerminalService, TerminalServiceNativeId } from './terminal-service';
import { TerminalService, TerminalServiceNativeId, newTerminalService } from './terminal-service';
import { UsersCore, UsersNativeId } from './user';
import { ClusterCore, ClusterCoreNativeId } from './cluster';
const { deviceManager, endpointManager } = sdk;
@@ -27,6 +28,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
publicRouter: any = Router();
mediaCore: MediaCore;
scriptCore: ScriptCore;
clusterCore: ClusterCore;
aggregateCore: AggregateCore;
automationCore: AutomationCore;
users: UsersCore;
@@ -96,19 +98,30 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
settings: "General",
}
checkLxcDependencies();
checkLegacyLxc();
checkLxc();
this.storageSettings.settings.releaseChannel.hide = process.env.SCRYPTED_INSTALL_ENVIRONMENT !== 'lxc-docker';
this.indexHtml = readFileAsString('dist/index.html');
(async () => {
await deviceManager.onDeviceDiscovered(
{
name: 'Cluster Manager',
nativeId: ClusterCoreNativeId,
interfaces: [ScryptedInterface.Settings, ScryptedInterface.Readme, ScryptedInterface.ScryptedSettings],
type: ScryptedDeviceType.Builtin,
},
);
})();
(async () => {
await deviceManager.onDeviceDiscovered(
{
name: 'Media Core',
nativeId: 'mediacore',
interfaces: [ScryptedInterface.DeviceProvider, ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -118,7 +131,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
name: 'Scripts',
nativeId: ScriptCoreNativeId,
interfaces: [ScryptedInterface.ScryptedSystemDevice, ScryptedInterface.ScryptedDeviceCreator, ScryptedInterface.DeviceProvider, ScryptedInterface.DeviceCreator, ScryptedInterface.Readme],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -127,8 +140,8 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
{
name: 'Terminal Service',
nativeId: TerminalServiceNativeId,
interfaces: [ScryptedInterface.StreamService, ScryptedInterface.TTY],
type: ScryptedDeviceType.Builtin,
interfaces: [ScryptedInterface.StreamService, ScryptedInterface.TTY, ScryptedInterface.ClusterForkInterface],
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -138,7 +151,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
name: 'REPL Service',
nativeId: ReplServiceNativeId,
interfaces: [ScryptedInterface.StreamService],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -148,7 +161,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
name: 'Console Service',
nativeId: ConsoleServiceNativeId,
interfaces: [ScryptedInterface.StreamService],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -159,7 +172,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
name: 'Automations',
nativeId: AutomationCoreNativeId,
interfaces: [ScryptedInterface.ScryptedSystemDevice, ScryptedInterface.ScryptedDeviceCreator, ScryptedInterface.DeviceProvider, ScryptedInterface.DeviceCreator, ScryptedInterface.Readme],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -172,7 +185,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
ScryptedInterface.MixinProvider,
ScryptedInterface.Readme,
],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
});
(async () => {
@@ -193,7 +206,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
name: 'Scrypted Users',
nativeId: UsersNativeId,
interfaces: [ScryptedInterface.ScryptedSystemDevice, ScryptedInterface.ScryptedDeviceCreator, ScryptedInterface.DeviceProvider, ScryptedInterface.DeviceCreator, ScryptedInterface.Readme],
type: ScryptedDeviceType.Builtin,
type: ScryptedDeviceType.Internal,
},
);
})();
@@ -214,6 +227,8 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
}
async getDevice(nativeId: string) {
if (nativeId === ClusterCoreNativeId)
return this.clusterCore ||= new ClusterCore(ClusterCoreNativeId);
if (nativeId === 'launcher')
return new LauncherMixin('launcher');
if (nativeId === 'mediacore')
@@ -227,7 +242,7 @@ class ScryptedCore extends ScryptedDeviceBase implements HttpRequestHandler, Dev
if (nativeId === UsersNativeId)
return this.users ||= new UsersCore();
if (nativeId === TerminalServiceNativeId)
return this.terminalService ||= new TerminalService();
return this.terminalService ||= new TerminalService(TerminalServiceNativeId, false);
if (nativeId === ReplServiceNativeId)
return this.replService ||= new PluginSocketService(ReplServiceNativeId, 'repl');
if (nativeId === ConsoleServiceNativeId)
@@ -316,5 +331,6 @@ export async function fork() {
return {
tsCompile,
newScript,
newTerminalService,
}
}

View File

@@ -1,121 +1,35 @@
import sdk from '@scrypted/sdk';
import child_process from 'child_process';
import { once } from 'events';
import fs from 'fs';
import os from 'os';
import sdk from '@scrypted/sdk';
export const SCRYPTED_INSTALL_ENVIRONMENT_LXC = 'lxc';
export const SCRYPTED_INSTALL_ENVIRONMENT_LXC_DOCKER = 'lxc-docker';
export async function checkLxcDependencies() {
export async function checkLegacyLxc() {
if (process.env.SCRYPTED_INSTALL_ENVIRONMENT !== SCRYPTED_INSTALL_ENVIRONMENT_LXC)
return;
let needRestart = false;
if (!process.version.startsWith('v20.')) {
const cp = child_process.spawn('sh', ['-c', 'apt update -y && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt install -y nodejs']);
const [exitCode] = await once(cp, 'exit');
if (exitCode !== 0)
sdk.log.a('Failed to install Node.js 20.x.');
else
needRestart = true;
}
if (!fs.existsSync('/var/run/avahi-daemon/socket')) {
const cp = child_process.spawn('sh', ['-c', 'apt update -y && apt install -y avahi-daemon && apt upgrade -y']);
const [exitCode] = await once(cp, 'exit');
if (exitCode !== 0)
sdk.log.a('Failed to install avahi-daemon.');
else
needRestart = true;
}
const scryptedService = fs.readFileSync('lxc/scrypted.service').toString();
const installedScryptedService = fs.readFileSync('/etc/systemd/system/scrypted.service').toString();
if (installedScryptedService !== scryptedService) {
fs.writeFileSync('/etc/systemd/system/scrypted.service', scryptedService);
needRestart = true;
const cp = child_process.spawn('systemctl', ['daemon-reload']);
const [exitCode] = await once(cp, 'exit');
if (exitCode !== 0)
sdk.log.a('Failed to daemon-reload systemd.');
}
try {
const output = await new Promise<string>((r, f) => child_process.exec("sh -c 'apt list --installed | grep level-zero/'", (err, stdout, stderr) => {
if (err && !stdout && !stderr)
f(err);
else
r(stdout + '\n' + stderr);
}));
const cpuModel = os.cpus()[0].model;
if (cpuModel.includes('Core') && cpuModel.includes('Ultra')) {
if (
// apt
!output.includes('level-zero/')
) {
const cp = child_process.spawn('sh', ['-c', 'curl https://raw.githubusercontent.com/koush/scrypted/main/install/docker/install-intel-npu.sh | bash']);
const [exitCode] = await once(cp, 'exit');
if (exitCode !== 0)
sdk.log.a('Failed to install intel-driver-compiler-npu.');
else
needRestart = true;
}
}
else {
// level-zero crashes openvino on older CPU due to illegal instruction.
// so ensure it is not installed if this is not a core ultra system with npu.
if (
// apt
output.includes('level-zero/')
) {
const cp = child_process.spawn('apt', ['-y', 'remove', 'level-zero']);
const [exitCode] = await once(cp, 'exit');
console.log('level-zero removed', exitCode);
needRestart = true;
}
}
}
catch (e) {
sdk.log.a('Failed to verify/install intel-driver-compiler-npu.');
}
try {
// intel opencl icd is broken from their official apt repos on kernel versions 6.8, which ships with ubuntu 24.04 and proxmox 8.2.
// the intel apt repo has not been updated yet.
// the current workaround is to install the release manually.
// https://github.com/intel/compute-runtime/releases/tag/24.13.29138.7
const output = await new Promise<string>((r, f) => child_process.exec("sh -c 'apt show versions intel-opencl-icd'", (err, stdout, stderr) => {
if (err && !stdout && !stderr)
f(err);
else
r(stdout + '\n' + stderr);
}));
if (
// apt
output.includes('Version: 23')
// was installed via script at some point
|| output.includes('Version: 24.13.29138.7')
|| output.includes('Version: 24.26.30049.6')
|| output.includes('Version: 24.31.30508.7')
// current script version: 24.35.30872.22
) {
const cp = child_process.spawn('sh', ['-c', 'curl https://raw.githubusercontent.com/koush/scrypted/main/install/docker/install-intel-graphics.sh | bash']);
const [exitCode] = await once(cp, 'exit');
if (exitCode !== 0)
sdk.log.a('Failed to install intel-opencl-icd.');
else
needRestart = true;
}
}
catch (e) {
sdk.log.a('Failed to verify/install intel-opencl-icd version.');
}
if (needRestart)
sdk.log.a('A system update is pending. Please restart Scrypted to apply changes.');
sdk.log.a('This system is currently running the legacy LXC installation method and must be migrated to the new LXC manually: https://docs.scrypted.app/install/proxmox-ve.html#proxmox-ve-container-reset');
}
const DOCKER_COMPOSE_SH_PATH = '/root/.scrypted/docker-compose.sh';
const LXC_DOCKER_COMPOSE_SH_PATH = 'lxc/docker-compose.sh';
export async function checkLxc() {
if (process.env.SCRYPTED_INSTALL_ENVIRONMENT !== SCRYPTED_INSTALL_ENVIRONMENT_LXC_DOCKER)
return;
const foundDockerComposeSh = await fs.promises.readFile(DOCKER_COMPOSE_SH_PATH, 'utf8');
const dockerComposeSh = await fs.promises.readFile(LXC_DOCKER_COMPOSE_SH_PATH, 'utf8');
if (foundDockerComposeSh === dockerComposeSh) {
// check if the file is executable
const stats = await fs.promises.stat(DOCKER_COMPOSE_SH_PATH);
if (stats.mode & 0o111)
return;
await fs.promises.chmod(DOCKER_COMPOSE_SH_PATH, 0o755);
return;
}
await fs.promises.copyFile(LXC_DOCKER_COMPOSE_SH_PATH, DOCKER_COMPOSE_SH_PATH);
await fs.promises.chmod(DOCKER_COMPOSE_SH_PATH, 0o755);
}

View File

@@ -93,7 +93,7 @@ export class ScriptCore extends ScryptedDeviceBase implements DeviceProvider, De
let script = new Script(nativeId);
let worker: ForkWorker;
const triggerDeviceDiscover = async (name: string, type: ScryptedDeviceType, interfaces: string[]) => {
const triggerDeviceDiscover = async (name: string, type: ScryptedDeviceType | string, interfaces: string[]) => {
const e = this.scripts.get(nativeId);
if (e?.script == script)
e.script = undefined;

View File

@@ -7,7 +7,7 @@ import { ScriptCoreNativeId } from "./script-core";
const { deviceManager } = sdk;
export class Script extends ScryptedDeviceBase implements Scriptable, Program, ScriptDeviceImpl {
constructor(nativeId: string, public triggerDeviceDiscover?: (name: string, type: ScryptedDeviceType, interfaces: string[]) => Promise<string>) {
constructor(nativeId: string, public triggerDeviceDiscover?: (name: string, type: ScryptedDeviceType | string, interfaces: string[]) => Promise<string>) {
super(nativeId);
}

View File

@@ -1,4 +1,4 @@
import sdk, { ScryptedDeviceBase, ScryptedInterface, ScryptedNativeId, StreamService, TTYSettings } from "@scrypted/sdk";
import sdk, { ClusterForkInterface, ClusterForkInterfaceOptions, ScryptedDeviceBase, ScryptedInterface, ScryptedNativeId, StreamService, TTYSettings } from "@scrypted/sdk";
import type { IPty, spawn as ptySpawn } from 'node-pty';
import { createAsyncQueue } from '@scrypted/common/src/async-queue'
import { ChildProcess, spawn as childSpawn } from "child_process";
@@ -111,8 +111,11 @@ class NoninteractiveTerminal {
}
export class TerminalService extends ScryptedDeviceBase implements StreamService<Buffer | string, Buffer> {
constructor(nativeId?: ScryptedNativeId) {
export class TerminalService extends ScryptedDeviceBase implements StreamService<Buffer | string, Buffer>, ClusterForkInterface {
private forks: { [clusterWorkerId: string]: TerminalService } = {};
private forkClients: 0;
constructor(nativeId?: ScryptedNativeId, private isFork: boolean = false) {
super(nativeId);
}
@@ -134,6 +137,42 @@ export class TerminalService extends ScryptedDeviceBase implements StreamService
return extraPaths;
}
async forkInterface<StreamService>(forkInterface: ScryptedInterface, options?: ClusterForkInterfaceOptions): Promise<StreamService> {
if (forkInterface !== ScryptedInterface.StreamService) {
throw new Error('can only fork StreamService');
}
if (!options?.clusterWorkerId) {
throw new Error('clusterWorkerId required');
}
if (this.isFork) {
throw new Error('cannot fork a fork');
}
const clusterWorkerId = options.clusterWorkerId;
if (this.forks[clusterWorkerId]) {
return this.forks[clusterWorkerId] as StreamService;
}
const fork = sdk.fork<{
newTerminalService: typeof newTerminalService,
}>({ clusterWorkerId });
try {
const result = await fork.result;
const terminalService = await result.newTerminalService();
this.forks[clusterWorkerId] = terminalService;
fork.worker.on('exit', () => {
delete this.forks[clusterWorkerId];
});
return terminalService as StreamService;
}
catch (e) {
fork.worker.terminate();
throw e;
}
}
/*
* The input to this stream can send buffers for normal terminal data and strings
* for control messages. Control messages are JSON-formatted.
@@ -149,6 +188,19 @@ export class TerminalService extends ScryptedDeviceBase implements StreamService
const queue = createAsyncQueue<Buffer>();
const extraPaths = await this.getExtraPaths();
if (this.isFork) {
this.forkClients++;
}
queue.endPromise.then(() => {
if (this.isFork) {
this.forkClients--;
if (this.forkClients === 0) {
process.exit();
}
}
});
function registerChildListeners() {
cp.onExit(() => queue.end());
@@ -206,14 +258,7 @@ export class TerminalService extends ScryptedDeviceBase implements StreamService
if (parsed.interactive) {
let spawn: typeof ptySpawn;
try {
try {
spawn = require('node-pty-prebuilt-multiarch').spawn as typeof ptySpawn;
if (!spawn)
throw new Error();
}
catch (e) {
spawn = require('@scrypted/node-pty').spawn as typeof ptySpawn;
}
spawn = require('@scrypted/node-pty').spawn as typeof ptySpawn;
cp = new InteractiveTerminal(cmd, extraPaths, spawn);
}
catch (e) {
@@ -233,10 +278,16 @@ export class TerminalService extends ScryptedDeviceBase implements StreamService
}
catch (e) {
this.console.log(e);
}
finally {
cp?.kill();
}
})();
return generator();
}
}
export async function newTerminalService(): Promise<TerminalService> {
return new TerminalService(TerminalServiceNativeId, true);
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/coreml",
"version": "0.1.76",
"version": "0.1.77",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/coreml",
"version": "0.1.76",
"version": "0.1.77",
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
}

View File

@@ -48,5 +48,5 @@
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
},
"version": "0.1.76"
"version": "0.1.77"
}

View File

@@ -1,19 +1,19 @@
{
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"dependencies": {
"doorbird": "^2.1.2"
"doorbird": "2.6.0"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.15.11",
"@types/node": "^22.10.10",
"cross-env": "^7.0.3"
}
},
@@ -24,36 +24,41 @@
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"node-fetch-commonjs": "^3.1.1",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
},
"devDependencies": {
"@types/node": "^20.10.8",
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.4",
"version": "0.3.108",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -65,11 +70,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"node_modules/@scrypted/common": {
@@ -81,10 +84,14 @@
"link": 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": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -92,11 +99,12 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.4",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -145,10 +153,11 @@
}
},
"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==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -167,25 +176,29 @@
}
},
"node_modules/doorbird": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/doorbird/-/doorbird-2.1.2.tgz",
"integrity": "sha512-ivwwsS/nOslDnuLg3UB60Axo76w5LQuZ67mCPEeWFr5+HbGYRL7PCY3iLjWYaIakh5+IvZyFPHKR4yHAvAc1WQ==",
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/doorbird/-/doorbird-2.6.0.tgz",
"integrity": "sha512-HZBI5uFhwEVF8JFULQlpzXXvjSHmtQMJUNWfogq6vHe3kv7mCSmg0g/TDbeV5fVvisi8w7GxKD0/PpZCrtcGOg==",
"dependencies": {
"axios": "^1.2.1",
"axios": "^1.6.2",
"chacha-js": "^2.1.1",
"libsodium-wrappers-sumo": "^0.7.11"
"libsodium-wrappers-sumo": "^0.7.13"
},
"engines": {
"node": ">=16.0.0"
}
},
"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==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -225,16 +238,16 @@
"dev": true
},
"node_modules/libsodium-sumo": {
"version": "0.7.11",
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.11.tgz",
"integrity": "sha512-bY+7ph7xpk51Ez2GbE10lXAQ5sJma6NghcIDaSPbM/G9elfrjLa0COHl/7P6Wb/JizQzl5UQontOOP1z0VwbLA=="
"version": "0.7.15",
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.15.tgz",
"integrity": "sha512-5tPmqPmq8T8Nikpm1Nqj0hBHvsLFCXvdhBFV7SGOitQPZAA6jso8XoL0r4L7vmfKXr486fiQInvErHtEvizFMw=="
},
"node_modules/libsodium-wrappers-sumo": {
"version": "0.7.11",
"resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.11.tgz",
"integrity": "sha512-DGypHOmJbB1nZn89KIfGOAkDgfv5N6SBGC3Qvmy/On0P0WD1JQvNRS/e3UL3aFF+xC0m+MYz5M+MnRnK2HMrKQ==",
"version": "0.7.15",
"resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.15.tgz",
"integrity": "sha512-aSWY8wKDZh5TC7rMvEdTHoyppVq/1dTSAeAR7H6pzd6QRT3vQWcT5pGwCotLcpPEOLXX6VvqihSPkpEhYAjANA==",
"dependencies": {
"libsodium-sumo": "^0.7.11"
"libsodium-sumo": "^0.7.15"
}
},
"node_modules/mime-db": {
@@ -307,6 +320,13 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/doorbird",
"version": "0.0.2",
"version": "0.0.4",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",
"prescrypted-setup-project": "scrypted-package-json",
@@ -33,12 +33,12 @@
]
},
"dependencies": {
"doorbird": "^2.1.2"
"doorbird": "2.6.0"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@types/node": "^18.15.11",
"@types/node": "^22.10.10",
"cross-env": "^7.0.3"
}
}

View File

@@ -1,13 +1,13 @@
import { listenZero } from '@scrypted/common/src/listen-cluster';
import sdk, { BinarySensor, Camera, DeviceProvider, DeviceCreator, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, MediaObject, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, VideoCamera, MotionSensor } from '@scrypted/sdk';
import child_process, { ChildProcess } from 'child_process';
import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
import net from 'net';
import { randomBytes } from 'crypto';
import { PassThrough, Readable } from "stream";
import { readLength } from "@scrypted/common/src/read-stream";
import { authHttpFetch } from "@scrypted/common/src/http-auth-fetch";
import { ApiRingEvent, ApiMotionEvent, DoorbirdAPI } from "./doorbird-api";
import { listenZero } from '@scrypted/common/src/listen-cluster';
import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
import { readLength } from "@scrypted/common/src/read-stream";
import sdk, { BinarySensor, Camera, DeviceCreator, DeviceCreatorSettings, DeviceInformation, DeviceProvider, FFmpegInput, Intercom, MediaObject, MotionSensor, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, VideoCamera } from '@scrypted/sdk';
import child_process, { ChildProcess } from 'child_process';
import { randomBytes } from 'crypto';
import net from 'net';
import { PassThrough, Readable } from "stream";
import { ApiMotionEvent, ApiRingEvent, DoorbirdAPI } from "./doorbird-api";
const { deviceManager, mediaManager } = sdk;
@@ -384,7 +384,7 @@ class DoorbirdCamera extends ScryptedDeviceBase implements Intercom, Camera, Vid
this.console.log('Doorbird: timed out waiting for tcp client from ffmpeg');
server.close();
}, 30000);
const port = await listenZero(server);
const port = await listenZero(server, '127.0.0.1');
return port;
}

View File

@@ -1,5 +1,6 @@
{
"compilerOptions": {
"module": "Node16",
"target": "esnext",
"moduleResolution": "Node16",
"esModuleInterop": true,

View File

@@ -1,4 +1,4 @@
{
"scrypted.debugHost": "127.0.0.1",
"scrypted.debugHost": "scrypted-nvr",
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/dummy-switch",
"version": "0.0.24",
"version": "0.0.25",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/dummy-switch",
"version": "0.0.24",
"version": "0.0.25",
"dependencies": {
"@types/node": "^16.6.1",
"axios": "^1.3.6"
@@ -23,35 +23,41 @@
"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.5.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.97",
"version": "0.3.106",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -63,11 +69,9 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"../sdk": {
@@ -92,11 +96,11 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.6.tgz",
"integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==",
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"dependencies": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -121,9 +125,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.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
@@ -182,35 +186,39 @@
"version": "file:../../common",
"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",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2",
"typescript": "^5.5.3"
}
},
"@scrypted/sdk": {
"version": "file:../../sdk",
"requires": {
"@babel/preset-typescript": "^7.18.6",
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"@types/node": "^22.10.1",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"stringify-object": "^3.3.0",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typedoc": "^0.26.11",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
}
},
"@types/node": {
@@ -224,11 +232,11 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.6.tgz",
"integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==",
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"requires": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -247,9 +255,9 @@
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"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.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
},
"form-data": {
"version": "4.0.0",

View File

@@ -40,5 +40,5 @@
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk"
},
"version": "0.0.24"
"version": "0.0.25"
}

View File

@@ -2,11 +2,60 @@ import { BinarySensor, DeviceCreator, DeviceCreatorSettings, DeviceProvider, Loc
import sdk from '@scrypted/sdk';
import { ReplaceMotionSensor, ReplaceMotionSensorNativeId } from './replace-motion-sensor';
import { ReplaceBinarySensor, ReplaceBinarySensorNativeId } from './replace-binary-sensor';
import { StorageSettings } from '@scrypted/sdk/storage-settings';
const { log, deviceManager } = sdk;
class DummyDevice extends ScryptedDeviceBase implements OnOff, Lock, StartStop, OccupancySensor, MotionSensor, BinarySensor, Settings {
timeout: NodeJS.Timeout;
storageSettings = new StorageSettings(this, {
reset: {
title: 'Reset Sensor',
description: 'Reset the motion sensor and binary sensor after the given seconds. Enter 0 to never reset.',
defaultValue: 10,
type: 'number',
placeholder: '10',
onPut: () => {
clearTimeout(this.timeout);
}
},
actionTypes: {
title: 'Action Types',
description: 'Select the action types to expose.',
defaultValue: [
ScryptedInterface.OnOff,
ScryptedInterface.StartStop,
ScryptedInterface.Lock,
],
multiple: true,
choices: [
ScryptedInterface.OnOff,
ScryptedInterface.StartStop,
ScryptedInterface.Lock,
],
onPut: () => {
this.reportInterfaces();
},
},
sensorTypes: {
title: 'Sensor Types',
description: 'Select the sensor types to expose.',
defaultValue: [
ScryptedInterface.MotionSensor,
ScryptedInterface.BinarySensor,
ScryptedInterface.OccupancySensor,
],
multiple: true,
choices: [
ScryptedInterface.MotionSensor,
ScryptedInterface.BinarySensor,
ScryptedInterface.OccupancySensor,
],
onPut: () => {
this.reportInterfaces();
},
}
});
constructor(nativeId: string) {
super(nativeId);
@@ -19,6 +68,22 @@ class DummyDevice extends ScryptedDeviceBase implements OnOff, Lock, StartStop,
this.occupied = false;
}
async reportInterfaces() {
const interfaces: ScryptedInterface[] = this.storageSettings.values.sensorTypes || [];
if (!interfaces.length)
interfaces.push(ScryptedInterface.MotionSensor, ScryptedInterface.BinarySensor, ScryptedInterface.OccupancySensor);
const actionTyoes = this.storageSettings.values.actionTypes || [];
if (!actionTyoes.length)
actionTyoes.push(ScryptedInterface.OnOff, ScryptedInterface.StartStop, ScryptedInterface.Lock);
await sdk.deviceManager.onDeviceDiscovered({
nativeId: this.nativeId,
interfaces: [...interfaces, ...actionTyoes, ScryptedInterface.Settings],
type: ScryptedDeviceType.Switch,
name: this.providedName,
});
}
lock(): Promise<void> {
return this.turnOff();
}
@@ -31,20 +96,12 @@ class DummyDevice extends ScryptedDeviceBase implements OnOff, Lock, StartStop,
stop(): Promise<void> {
return this.turnOff();
}
async getSettings(): Promise<Setting[]> {
return [
{
key: 'reset',
title: 'Reset Sensor',
description: 'Reset the motion sensor and binary sensor after the given seconds. Enter 0 to never reset.',
value: this.storage.getItem('reset') || '10',
placeholder: '10',
}
]
return this.storageSettings.getSettings();
}
async putSetting(key: string, value: SettingValue): Promise<void> {
this.storage.setItem(key, value.toString());
clearTimeout(this.timeout);
return this.storageSettings.putSetting(key, value);
}
// note that turnOff locks the lock
@@ -131,12 +188,6 @@ class DummyDeviceProvider extends ScryptedDeviceBase implements DeviceProvider,
const nativeId = 'shell:' + Math.random().toString();
const name = settings.name?.toString();
await this.onDiscovered(nativeId, name);
return nativeId;
}
async onDiscovered(nativeId: string, name: string) {
await deviceManager.onDeviceDiscovered({
nativeId,
name,
@@ -151,6 +202,8 @@ class DummyDeviceProvider extends ScryptedDeviceBase implements DeviceProvider,
],
type: ScryptedDeviceType.Switch,
});
return nativeId;
}
async getDevice(nativeId: string) {
@@ -163,11 +216,6 @@ class DummyDeviceProvider extends ScryptedDeviceBase implements DeviceProvider,
if (!ret) {
ret = new DummyDevice(nativeId);
// remove legacy scriptable interface
if (ret.interfaces.includes(ScryptedInterface.Scriptable)) {
setTimeout(() => this.onDiscovered(ret.nativeId, ret.providedName), 2000);
}
if (ret)
this.devices.set(nativeId, ret);
}

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"module": "commonjs",
"module": "Node16",
"target": "ES2021",
"resolveJsonModule": true,
"moduleResolution": "Node16",

View File

@@ -21,6 +21,7 @@
"@scrypted/sdk": "file:../../sdk",
"@types/debug": "^4.1.5",
"@types/lodash": "^4.14.168",
"@types/node": "^22.13.11",
"@types/url-parse": "^1.4.3"
}
},
@@ -31,51 +32,55 @@
"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.5.3"
},
"devDependencies": {
"@types/node": "^16.9.0"
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.2.53",
"version": "0.5.10",
"dev": true,
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
"scrypted-debug": "bin/scrypted-debug.js",
"scrypted-deploy": "bin/scrypted-deploy.js",
"scrypted-deploy-debug": "bin/scrypted-deploy-debug.js",
"scrypted-package-json": "bin/scrypted-package-json.js",
"scrypted-readme": "bin/scrypted-readme.js",
"scrypted-setup-project": "bin/scrypted-setup-project.js",
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"../sdk": {
@@ -182,9 +187,13 @@
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
},
"node_modules/@types/node": {
"version": "14.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
"integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ=="
"version": "22.13.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz",
"integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/@types/qs": {
"version": "6.9.6",
@@ -712,6 +721,12 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT"
},
"node_modules/url-parse": {
"version": "1.5.9",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.9.tgz",
@@ -778,35 +793,39 @@
"version": "file:../../common",
"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",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2",
"typescript": "^5.5.3"
}
},
"@scrypted/sdk": {
"version": "file:../../sdk",
"requires": {
"@babel/preset-typescript": "^7.18.6",
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^0.21.4",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"@types/node": "^22.10.1",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"stringify-object": "^3.3.0",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typedoc": "^0.26.11",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
}
},
"@types/aws-lambda": {
@@ -877,9 +896,12 @@
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
},
"@types/node": {
"version": "14.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
"integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ=="
"version": "22.13.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz",
"integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==",
"requires": {
"undici-types": "~6.20.0"
}
},
"@types/qs": {
"version": "6.9.6",
@@ -1259,6 +1281,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
},
"url-parse": {
"version": "1.5.9",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.9.tgz",

View File

@@ -47,6 +47,7 @@
"@scrypted/sdk": "file:../../sdk",
"@types/debug": "^4.1.5",
"@types/lodash": "^4.14.168",
"@types/node": "^22.13.11",
"@types/url-parse": "^1.4.3"
},
"version": "0.0.61"

View File

@@ -7,7 +7,7 @@ const { systemManager } = sdk;
export interface DummyDevice {
interfaces?: string[];
type?: ScryptedDeviceType;
type?: ScryptedDeviceType | string;
}
interface SupportedType {

View File

@@ -1,24 +1,25 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.200",
"name": "@vityevato/hikvision-doorbell",
"version": "1.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.200",
"name": "@vityevato/hikvision-doorbell",
"version": "1.0.1",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@scrypted/server": "file:../../server",
"@types/xml2js": "^0.4.11",
"http-auth-client": "^0.4.1",
"ip": "^1.1.8",
"lodash": "^4.17.21",
"sip": "git+https://github.com/kirm/sip.js.git",
"xml2js": "^0.6.0"
},
"devDependencies": {
"@scrypted/common": "file:../../common",
"@scrypted/sdk": "file:../../sdk",
"@scrypted/server": "file:../../server",
"@types/ip": "^1.1.3",
"@types/node": "^18.15.11"
}
@@ -26,39 +27,43 @@
"../../common": {
"name": "@scrypted/common",
"version": "1.0.1",
"dev": true,
"license": "ISC",
"dependencies": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"http-auth-utils": "^5.0.1",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
},
"devDependencies": {
"@types/node": "^20.11.0",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2"
}
},
"../../sdk": {
"name": "@scrypted/sdk",
"version": "0.3.5",
"dev": true,
"version": "0.3.118",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.18.6",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
},
"bin": {
"scrypted-changelog": "bin/scrypted-changelog.js",
@@ -70,67 +75,61 @@
"scrypted-webpack": "bin/scrypted-webpack.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"stringify-object": "^3.3.0",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21"
"@types/node": "^22.10.1",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11"
}
},
"../../server": {
"name": "@scrypted/server",
"version": "0.94.0",
"dev": true,
"version": "0.138.1",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
"@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",
"engine.io": "^6.5.4",
"express": "^4.18.2",
"ffmpeg-static": "^5.2.0",
"follow-redirects": "^1.15.5",
"@scrypted/ffmpeg-static": "^6.1.0-build3",
"@scrypted/node-pty": "^1.0.22",
"@scrypted/types": "^0.3.108",
"adm-zip": "^0.5.16",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.5",
"engine.io": "^6.6.2",
"express": "^4.21.1",
"follow-redirects": "^1.15.9",
"http-auth": "^4.2.0",
"ip": "^1.1.8",
"level": "^8.0.0",
"level": "^8.0.1",
"lodash": "^4.17.21",
"nan": "^2.18.0",
"node-dijkstra": "^2.5.0",
"node-forge": "^1.3.1",
"node-gyp": "^10.0.1",
"router": "^1.3.8",
"semver": "^7.5.4",
"sharp": "^0.33.2",
"node-gyp": "^10.2.0",
"py": "npm:@bjia56/portable-python@^0.1.112",
"semver": "^7.6.3",
"sharp": "^0.33.5",
"source-map-support": "^0.5.21",
"tar": "^6.2.0",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"tar": "^7.4.3",
"tslib": "^2.8.1",
"typescript": "^5.5.4",
"whatwg-mimetype": "^4.0.0",
"ws": "^8.16.0"
"ws": "^8.18.0"
},
"bin": {
"scrypted-serve": "bin/scrypted-serve"
},
"devDependencies": {
"@types/adm-zip": "^0.5.5",
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.21",
"@types/adm-zip": "^0.5.7",
"@types/cookie-parser": "^1.4.8",
"@types/express": "^5.0.0",
"@types/follow-redirects": "^1.14.4",
"@types/http-auth": "^4.1.4",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.14.202",
"@types/lodash": "^4.17.13",
"@types/node": "^22.10.1",
"@types/node-dijkstra": "^2.5.6",
"@types/node-forge": "^1.3.11",
"@types/semver": "^7.5.6",
"@types/semver": "^7.5.8",
"@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"
"@types/ws": "^8.5.13",
"rimraf": "^6.0.1"
}
},
"../sdk": {
@@ -193,6 +192,37 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"node_modules/sip": {
"version": "0.0.6",
"resolved": "git+ssh://git@github.com/kirm/sip.js.git#fd7e0c2389507b00811feb51bc5c0f6595bac53d",
"dependencies": {
"ws": "^7.4.6"
},
"engines": {
"node": ">=0.2.2"
}
},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xml2js": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",
@@ -219,81 +249,83 @@
"version": "file:../../common",
"requires": {
"@scrypted/sdk": "file:../sdk",
"@scrypted/server": "file:../server",
"@types/node": "^20.11.0",
"http-auth-utils": "^5.0.1",
"monaco-editor": "^0.50.0",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
"typescript": "^5.5.3"
}
},
"@scrypted/sdk": {
"version": "file:../../sdk",
"requires": {
"@babel/preset-typescript": "^7.18.6",
"@types/node": "^18.11.18",
"@types/stringify-object": "^4.0.0",
"adm-zip": "^0.4.13",
"axios": "^1.6.5",
"babel-loader": "^9.1.0",
"babel-plugin-const-enum": "^1.1.0",
"esbuild": "^0.15.9",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@rollup/plugin-virtual": "^3.0.2",
"@types/node": "^22.10.1",
"adm-zip": "^0.5.16",
"axios": "^1.7.8",
"babel-loader": "^9.2.1",
"babel-plugin-const-enum": "^1.2.0",
"ncp": "^2.0.0",
"raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
"stringify-object": "^3.3.0",
"tmp": "^0.2.1",
"ts-loader": "^9.4.2",
"ts-node": "^10.4.0",
"typedoc": "^0.23.21",
"typescript": "^4.9.4",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.5.0"
"rimraf": "^6.0.1",
"rollup": "^4.27.4",
"tmp": "^0.2.3",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typedoc": "^0.26.11",
"typescript": "^5.6.3",
"webpack": "^5.96.1",
"webpack-bundle-analyzer": "^4.10.2"
}
},
"@scrypted/server": {
"version": "file:../../server",
"requires": {
"@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/express": "^4.17.21",
"@scrypted/ffmpeg-static": "^6.1.0-build3",
"@scrypted/node-pty": "^1.0.22",
"@scrypted/types": "^0.3.108",
"@types/adm-zip": "^0.5.7",
"@types/cookie-parser": "^1.4.8",
"@types/express": "^5.0.0",
"@types/follow-redirects": "^1.14.4",
"@types/http-auth": "^4.1.4",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.14.202",
"@types/lodash": "^4.17.13",
"@types/node": "^22.10.1",
"@types/node-dijkstra": "^2.5.6",
"@types/node-forge": "^1.3.11",
"@types/semver": "^7.5.6",
"@types/semver": "^7.5.8",
"@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",
"engine.io": "^6.5.4",
"express": "^4.18.2",
"ffmpeg-static": "^5.2.0",
"follow-redirects": "^1.15.5",
"@types/ws": "^8.5.13",
"adm-zip": "^0.5.16",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.5",
"engine.io": "^6.6.2",
"express": "^4.21.1",
"follow-redirects": "^1.15.9",
"http-auth": "^4.2.0",
"ip": "^1.1.8",
"level": "^8.0.0",
"level": "^8.0.1",
"lodash": "^4.17.21",
"nan": "^2.18.0",
"node-dijkstra": "^2.5.0",
"node-forge": "^1.3.1",
"node-gyp": "^10.0.1",
"node-pty-prebuilt-multiarch": "^0.10.1-pre.5",
"router": "^1.3.8",
"semver": "^7.5.4",
"sharp": "^0.33.2",
"node-gyp": "^10.2.0",
"py": "npm:@bjia56/portable-python@^0.1.112",
"rimraf": "^6.0.1",
"semver": "^7.6.3",
"sharp": "^0.33.5",
"source-map-support": "^0.5.21",
"tar": "^6.2.0",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"tar": "^7.4.3",
"tslib": "^2.8.1",
"typescript": "^5.5.4",
"whatwg-mimetype": "^4.0.0",
"ws": "^8.16.0"
"ws": "^8.18.0"
}
},
"@types/ip": {
@@ -338,6 +370,19 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"sip": {
"version": "git+ssh://git@github.com/kirm/sip.js.git#fd7e0c2389507b00811feb51bc5c0f6595bac53d",
"from": "sip@git+https://github.com/kirm/sip.js.git",
"requires": {
"ws": "^7.4.6"
}
},
"ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"requires": {}
},
"xml2js": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"module": "commonjs",
"module": "Node16",
"target": "ES2021",
"resolveJsonModule": true,
"moduleResolution": "Node16",

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,4 +1,4 @@
{
"scrypted.debugHost": "127.0.0.1",
"scrypted.debugHost": "scrypted-nvr",
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.165",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.165",
"license": "Apache",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/hikvision",
"version": "0.0.160",
"version": "0.0.165",
"description": "Hikvision Plugin for Scrypted",
"author": "Scrypted",
"license": "Apache",

View File

@@ -0,0 +1,57 @@
import { OnOff, Readme, ScryptedDeviceBase } from "@scrypted/sdk";
import type { HikvisionCamera } from "./main";
export class HikvisionAlarmSwitch extends ScryptedDeviceBase implements OnOff, Readme {
on: boolean = false;
constructor(public camera: HikvisionCamera, nativeId: string) {
super(nativeId);
this.on = false;
}
async turnOn() {
this.on = true;
await this.setAlarm(true);
}
async turnOff() {
this.on = false;
await this.setAlarm(false);
}
private async setAlarm(state: boolean): Promise<void> {
const api = this.camera.getClient();
await api.setAlarm(state);
}
async getReadmeMarkdown(): Promise<string> {
return `
## **Alarm Switch**
This switch triggers the camera's alarm input.
### **Enabling Alarm Linkages**
To link the alarm to the camera's equipped features like strobe light, or audio alarm:
1. Log in to the cameras web interface.
2. Go to *Configuration > Event > Event and Detection (or Basic Event)*.
3. Select Alarm Input.
4. Edit under Operation(pencil icon) (or Linkage Method).
4. Set Linkage Actions
- Audible Warning (siren)
- Alarm (strobe light)
When the alarm is switched on, the linkages will activate.
### **Strobe Light and Audio Alarm Settings**
To configure the strobe light and audio alarm:
1. Log in to the cameras web interface.
2. Navigate to *Configuration > Event > Alarm Setting (or Basic Event)*.
3. **For Strobe Light**:
- Select 'Flashing Alarm Light Output'.
**For Audio Alarm**:
- Select 'Audible Alarm Output'.
`;
}
}

View File

@@ -399,3 +399,140 @@ export interface AudioCompressionType {
export interface GeneratedType35 {
opt: string
}
export interface PtzCapabilitiesRoot {
PTZChanelCap: PTZChanelCap;
}
export interface PTZChanelCap {
AbsolutePanTiltPositionSpace: AbsolutePanTiltPositionSpaceClass;
AbsoluteZoomPositionSpace: AbsoluteZoomPositionSpaceClass;
ContinuousPanTiltSpace: AbsolutePanTiltPositionSpaceClass;
ContinuousZoomSpace: AbsoluteZoomPositionSpaceClass;
maxPresetNum: string;
maxPatrolNum: string;
maxPatternNum: string;
maxLimitesNum: string;
maxTimeTaskNum: string;
controlProtocol: ControlProtocol;
controlAddress: string;
PTZRs485Para: PTZRs485Para;
PresetNameCap: PresetNameCap;
wiperStatusSupport: string;
isSupportPosition3D: string;
manualControlSpeed: ManualControlSpeed;
isSpportPtzlimiteds: string;
oneKeyParkAction: string;
oneKeyMenu: string;
ParkAction: ParkAction;
TimeTaskList: TimeTaskList;
TrackInitPosition: TrackInitPosition;
LockPT: string;
LFPositionCap: LFPositionCap;
isSupportManualWiper: string;
_xmlns: string;
_version: string;
}
export interface AbsolutePanTiltPositionSpaceClass {
XRange: Range;
YRange: Range;
}
export interface Range {
Min: string;
Max: string;
}
export interface AbsoluteZoomPositionSpaceClass {
ZRange: Range;
}
export interface LFPositionCap {
elevation: AbsoluteZoom;
azimuth: AbsoluteZoom;
absoluteZoom: AbsoluteZoom;
}
export interface AbsoluteZoom {
_min: string;
_max: string;
__text: string;
}
export interface PTZRs485Para {
baudRate: ControlProtocol;
dataBits: ControlProtocol;
parityType: ControlProtocol;
stopBits: ControlProtocol;
flowCtrl: ControlProtocol;
_xmlns: string;
_version: string;
}
export interface ControlProtocol {
_opt: string;
__text: string;
}
export interface ParkAction {
enabled: ControlProtocol;
Parktime: AbsoluteZoom;
Action: Action;
_xmlns: string;
_version: string;
}
export interface Action {
ActionType: ControlProtocol;
ActionNum: AbsoluteZoom;
}
export interface PresetNameCap {
presetNameSupport: string;
maxPresetNameLen: MaxPresetNameLen;
specialNo: ManualControlSpeed;
_xmlns: string;
_version: string;
}
export interface MaxPresetNameLen {
_max: string;
}
export interface ManualControlSpeed {
_opt: string;
}
export interface TimeTaskList {
enabled: ControlProtocol;
TimeTaskBlock: TimeTaskBlock[];
_xmlns: string;
_version: string;
}
export interface TimeTaskBlock {
dayOfWeek: AbsoluteZoom;
TimeTaskRange: TimeTaskRange[];
_xmlns: string;
_version: string;
}
export interface TimeTaskRange {
TaskID: AbsoluteZoom;
Task: Task;
}
export interface Task {
TaskType: ControlProtocol;
presetTaskNum: AbsoluteZoom;
}
export interface TrackInitPosition {
slaveCameraID: SlaveCameraID;
}
export interface SlaveCameraID {
_min: string;
_max: string;
}

View File

@@ -1,7 +1,10 @@
import { HttpFetchOptions } from '@scrypted/common/src/http-auth-fetch';
import { MediaStreamConfiguration, MediaStreamOptions } from '@scrypted/sdk';
import { MediaStreamConfiguration, MediaStreamOptions, PanTiltZoomCommand } from '@scrypted/sdk';
import { Readable } from 'stream';
import { Destroyable } from '../../rtsp/src/rtsp';
import { PtzPresetsRoot, TextOverlayRoot, VideoOverlayRoot } from './hikvision-overlay';
import { SupplementLightRoot } from './hikvision-xml-types';
import { PtzCapabilitiesRoot } from './hikvision-api-capabilities';
export interface HikvisionCameraStreamSetup {
videoCodecType: string;
@@ -16,10 +19,33 @@ export interface HikvisionAPI {
checkTwoWayAudio(): Promise<boolean>;
checkDeviceModel(): Promise<string>;
checkIsOldModel(): Promise<boolean>;
checkStreamSetup(channel: string, isOld: boolean): Promise<HikvisionCameraStreamSetup>;
jpegSnapshot(channel: string, timeout: number): Promise<Buffer>;
listenEvents(): Promise<Destroyable>;
putVcaResource(channel: string, resource: 'smart' | 'facesnap' | 'close'): Promise<boolean>;
getCodecs(camNumber: string): Promise<MediaStreamOptions[]>;
configureCodecs(camNumber: string, channelNumber: string, options: MediaStreamOptions): Promise<MediaStreamConfiguration>;
getOverlay(): Promise<{
json: VideoOverlayRoot;
xml: any;
}>;
getOverlayText(overlayId: string): Promise<{
json: TextOverlayRoot;
xml: any;
}>;
updateOverlayText(overlayId: string, entry: TextOverlayRoot): Promise<void>;
getSupplementLight(): Promise<{json: SupplementLightRoot; xml: any }>;
setSupplementLight(params: { on?: boolean, brightness?: number, mode?: 'auto' | 'manual' }): Promise<void>;
getAlarmCapabilities(): Promise<{ json: any; xml: string }>;
getAlarm(port: string): Promise<{ json: any; xml: string }>;
setAlarm(isOn: boolean): Promise<{ json: any; xml: string }>;
getPtzCapabilities(): Promise<{ json: PtzCapabilitiesRoot; xml: string }>;
ptzCommand(command: PanTiltZoomCommand): Promise<any>;
getPresets(): Promise<{
json: PtzPresetsRoot;
xml: any;
}>;
}

View File

@@ -1,16 +1,18 @@
import { AuthFetchCredentialState, HttpFetchOptions, authHttpFetch } from '@scrypted/common/src/http-auth-fetch';
import { readLine } from '@scrypted/common/src/read-stream';
import { parseHeaders, readBody, readMessage } from '@scrypted/common/src/rtsp-server';
import { MediaStreamConfiguration, MediaStreamOptions } from "@scrypted/sdk";
import { MediaStreamConfiguration, MediaStreamOptions, PanTiltZoomCommand } from "@scrypted/sdk";
import contentType from 'content-type';
import { IncomingMessage } from 'http';
import { EventEmitter, Readable } from 'stream';
import xml2js from 'xml2js';
import { Destroyable } from '../../rtsp/src/rtsp';
import { CapabiltiesResponse } from './hikvision-api-capabilities';
import { CapabiltiesResponse, PtzCapabilitiesRoot } from './hikvision-api-capabilities';
import { HikvisionAPI, HikvisionCameraStreamSetup } from "./hikvision-api-channels";
import { ChannelResponse, ChannelsResponse } from './hikvision-xml-types';
import { ChannelResponse, ChannelsResponse, SupplementLightRoot } from './hikvision-xml-types';
import { getDeviceInfo } from './probe';
import { PtzPresetsRoot, TextOverlayRoot, VideoOverlayRoot } from './hikvision-overlay';
import { sleep } from '@scrypted/common/src/sleep';
export const detectionMap = {
human: 'person',
@@ -116,36 +118,15 @@ export class HikvisionCameraAPI implements HikvisionAPI {
}
async checkIsOldModel() {
// The old Hikvision DS-7608NI-E2 doesn't support channel capability checks, and the requests cause errors
// The old Hikvision NVRs don't support channel capability checks, and the requests cause errors
const oldModels = [
/DS-76098NI-E2/,
/ERI-K104-P4/
];
const model = await this.checkDeviceModel();
if (!model)
return;
return !!model?.match(/DS-7608NI-E2/);
}
async checkStreamSetup(channel: string, isOld: boolean): Promise<HikvisionCameraStreamSetup> {
if (isOld) {
this.console.error('NVR is old version. Defaulting camera capabilities to H.264/AAC');
return {
videoCodecType: "H.264",
audioCodecType: "AAC",
}
}
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.body.match(/>(.*?)<\/videoCodecType>/);
const acodec = response.body.match(/>(.*?)<\/audioCompressionType>/);
return {
videoCodecType: vcodec?.[1],
audioCodecType: acodec?.[1],
}
return !!oldModels.find(oldModel => model?.match(oldModel));
}
async jpegSnapshot(channel: string, timeout = 10000): Promise<Buffer> {
@@ -478,4 +459,257 @@ export class HikvisionCameraAPI implements HikvisionAPI {
return [...defaultMap.values()];
}
}
}
async getOverlay() {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/System/Video/inputs/channels/1/overlays`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const json = await xml2js.parseStringPromise(response.body) as VideoOverlayRoot;
return { json, xml: response.body };
}
async getOverlayText(overlayId: string) {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}//ISAPI/System/Video/inputs/channels/1/overlays/text/${overlayId}`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const json = await xml2js.parseStringPromise(response.body) as TextOverlayRoot;
return { json, xml: response.body };
}
async updateOverlayText(overlayId: string, entry: TextOverlayRoot) {
const builder = new xml2js.Builder();
const xml = builder.buildObject(entry);
await this.request({
method: 'PUT',
url: `http://${this.ip}//ISAPI/System/Video/inputs/channels/1/overlays/text/${overlayId}`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
body: xml
});
}
async getSupplementLight(): Promise<{ json: SupplementLightRoot | any; xml: string }> {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/Image/channels/1/supplementLight/capabilities`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const xml = response.body;
const json = await xml2js.parseStringPromise(xml, {
explicitArray: false,
mergeAttrs: true,
});
return { json, xml };
}
async setSupplementLight(params: { on?: boolean, brightness?: number, mode?: 'auto' | 'manual' }): Promise<void> {
const { json } = await this.getSupplementLight();
if (json.ResponseStatus) {
throw new Error("Supplemental light is not supported on this device.");
}
const supp: any = json.SupplementLight;
if (!supp) {
throw new Error("Supplemental light configuration not available.");
}
if (supp.supplementLightMode && supp.supplementLightMode.opt) {
const availableModes = supp.supplementLightMode.opt.split(',').map(s => s.trim());
const selectedMode = params.on
? (availableModes.find(mode => mode.toLowerCase() !== 'close') || 'close')
: 'close';
supp.supplementLightMode = [selectedMode];
}
if (params.mode) {
supp.mixedLightBrightnessRegulatMode = [params.mode];
} else if (params.on !== undefined) {
supp.mixedLightBrightnessRegulatMode = [params.on ? "manual" : "auto"];
}
if (params.brightness !== undefined) {
let brightness = Math.max(0, Math.min(100, params.brightness));
supp.whiteLightBrightness = [brightness.toString()];
}
const builder = new xml2js.Builder({
headless: true,
renderOpts: { pretty: false },
});
const newXml = builder.buildObject({ SupplementLight: supp });
await this.request({
method: 'PUT',
url: `http://${this.ip}/ISAPI/Image/channels/1/supplementLight`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
body: newXml,
});
}
async getAlarmCapabilities(): Promise<{ json: any; xml: string }> {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/System/IO/inputs`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const xml = response.body;
const json = await xml2js.parseStringPromise(xml, {
explicitArray: false,
mergeAttrs: true,
});
return { json, xml };
}
async getAlarm(port: string): Promise<{ json: any; xml: string }> {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/Event/triggers/IO-${port}`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const xml = response.body;
const parsed = await xml2js.parseStringPromise(xml, { explicitArray: true });
return { json: parsed.EventTrigger, xml };
}
async setAlarm(isOn: boolean): Promise<{ json: any; xml: string }> {
const data = `<IOPortData>
<enabled>${isOn ? 'true' : 'false'}</enabled>
<triggering>${isOn ? 'low' : 'high'}</triggering>
</IOPortData>`;
const response = await this.request({
method: 'PUT',
url: `http://${this.ip}/ISAPI/System/IO/inputs/1`,
responseType: 'text',
headers: { 'Content-Type': 'application/xml' },
body: data
});
const xml = response.body;
let json = {};
try {
json = await xml2js.parseStringPromise(xml);
} catch (error) {
console.error("Failed to parse XML response for setAlarmInput:", error);
}
return { json, xml };
}
async getPtzCapabilities(): Promise<{ json: PtzCapabilitiesRoot; xml: string }> {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/PTZCtrl/channels/1/capabilities`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const xml = response.body;
const json = await xml2js.parseStringPromise(xml, {
explicitArray: false,
mergeAttrs: true,
});
return { json, xml };
}
async setPtzPreset(presetId: string) {
try {
await this.request({
method: 'PUT',
url: `http://${this.ip}/ISAPI/PTZCtrl/channels/1/presets/${presetId}/goto`,
responseType: 'text',
headers: { 'Content-Type': 'application/xml' },
});
} catch (e) {
this.console.error('Error during setPtzPreset', e);
}
}
async ptzCommand(command: PanTiltZoomCommand) {
let startCommandData: string;
let endCommandData: string;
const movement = 40;
if (command.preset) {
await this.setPtzPreset(command.preset);
} else if (command.pan < 0 || command.pan > 0) {
startCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><pan>${command.pan > 0 ? movement : -movement}</pan><tilt>0</tilt></PTZData>`;
endCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><pan>0</pan><tilt>0</tilt></PTZData>`;
} else if (command.tilt < 0 || command.tilt > 0) {
startCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><pan>0</pan><tilt>${command.tilt > 0 ? movement : -movement}</tilt></PTZData>`;
endCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><pan>0</pan><tilt>0</tilt></PTZData>`;
} else if (command.zoom < 0 || command.zoom > 0) {
startCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><zoom>${command.zoom > 0 ? movement : -movement}</zoom></PTZData>`;
endCommandData = `<?xml version: "1.0" encoding="UTF-8"?><PTZData><zoom>0</zoom></PTZData>`;
}
if (!startCommandData || !endCommandData) {
return;
}
try {
await this.request({
method: 'PUT',
url: `http://${this.ip}/ISAPI/PTZCtrl/channels/1/continuous`,
responseType: 'text',
headers: { 'Content-Type': 'application/xml' },
body: startCommandData
});
await sleep(500);
await this.request({
method: 'PUT',
url: `http://${this.ip}/ISAPI/PTZCtrl/channels/1/continuous`,
responseType: 'text',
headers: { 'Content-Type': 'application/xml' },
body: endCommandData
});
} catch (e) {
this.console.error('Error during PTZ command', e);
}
}
async getPresets() {
const response = await this.request({
method: 'GET',
url: `http://${this.ip}/ISAPI/PTZCtrl/channels/1/presets`,
responseType: 'text',
headers: {
'Content-Type': 'application/xml',
},
});
const json = await xml2js.parseStringPromise(response.body) as PtzPresetsRoot;
return { json, xml: response.body };
}
}

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