mirror of
https://github.com/koush/scrypted.git
synced 2026-02-05 23:22:13 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab00ade016 | ||
|
|
6cfc3db05c | ||
|
|
95aa58ce38 | ||
|
|
0d88b4746b | ||
|
|
8c4beeb3a0 | ||
|
|
4846cfaddf | ||
|
|
4e14f7fd6f | ||
|
|
266be72606 | ||
|
|
6a1970c075 | ||
|
|
0575d98424 | ||
|
|
cdf42fc1a2 | ||
|
|
fc1fabc49e | ||
|
|
4e08daecb2 | ||
|
|
58b27805ba | ||
|
|
b37c6bbd06 | ||
|
|
8eca02d819 | ||
|
|
0efdb34114 | ||
|
|
1a25100de2 | ||
|
|
51e0a8836d | ||
|
|
562d0839b7 | ||
|
|
e3df6accea | ||
|
|
03d159a89c | ||
|
|
4ead4726a9 | ||
|
|
b06ef623b3 | ||
|
|
8edb157e2a | ||
|
|
155a1ceb38 | ||
|
|
1cb6212fc6 |
@@ -93,8 +93,12 @@ export const H265_NAL_TYPE_AGG = 48;
|
||||
export const H265_NAL_TYPE_VPS = 32;
|
||||
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_BLA_W_LP = 16;
|
||||
export const H265_NAL_TYPE_BLA_W_RADL = 17;
|
||||
export const H265_NAL_TYPE_BLA_N_LP = 18;
|
||||
export const H265_NAL_TYPE_IDR_W_RADL = 19;
|
||||
export const H265_NAL_TYPE_IDR_N_LP = 20;
|
||||
export const H265_NAL_TYPE_CRA_NUT = 21;
|
||||
export const H265_NAL_TYPE_FU = 49;
|
||||
export const H265_NAL_TYPE_SEI_PREFIX = 39;
|
||||
export const H265_NAL_TYPE_SEI_SUFFIX = 40;
|
||||
@@ -252,6 +256,26 @@ export function getNaluTypesInH265Nalu(nalu: Buffer, fuaRequireStart = false, fu
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function isH265KeyFrameRelatedInSet(naluTypes: Set<number>, allowCodecInfo = true) {
|
||||
if (naluTypes.has(H265_NAL_TYPE_IDR_N_LP)
|
||||
|| naluTypes.has(H265_NAL_TYPE_IDR_W_RADL)
|
||||
|| naluTypes.has(H265_NAL_TYPE_CRA_NUT)
|
||||
|| naluTypes.has(H265_NAL_TYPE_BLA_N_LP)
|
||||
|| naluTypes.has(H265_NAL_TYPE_BLA_W_LP)
|
||||
|| naluTypes.has(H265_NAL_TYPE_BLA_W_RADL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (allowCodecInfo) {
|
||||
if (naluTypes.has(H265_NAL_TYPE_VPS)
|
||||
|| naluTypes.has(H265_NAL_TYPE_SPS)
|
||||
|| naluTypes.has(H265_NAL_TYPE_PPS))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
export function createRtspParser(options?: StreamParserOptions): RtspStreamParser {
|
||||
let resolve: any;
|
||||
|
||||
@@ -283,12 +307,7 @@ export function createRtspParser(options?: StreamParserOptions): RtspStreamParse
|
||||
else if (streamChunk.type === 'h265') {
|
||||
const naluTypes = getStartedH265NaluTypes(streamChunk);
|
||||
|
||||
if (naluTypes.has(H265_NAL_TYPE_VPS)
|
||||
|| naluTypes.has(H265_NAL_TYPE_SPS)
|
||||
|| naluTypes.has(H265_NAL_TYPE_PPS)
|
||||
|| naluTypes.has(H265_NAL_TYPE_IDR_N)
|
||||
|| naluTypes.has(H265_NAL_TYPE_IDR_W)
|
||||
) {
|
||||
if (isH265KeyFrameRelatedInSet(naluTypes)) {
|
||||
return streamChunks.slice(prebufferIndex);
|
||||
}
|
||||
}
|
||||
@@ -670,9 +689,12 @@ export class RtspClient extends RtspBase {
|
||||
// @ts-ignore
|
||||
const { parseHTTPHeadersQuotedKeyValueSet } = await import('http-auth-utils/dist/utils');
|
||||
|
||||
const authedUrl = new URL(this.url);
|
||||
const username = decodeURIComponent(authedUrl.username);
|
||||
const password = decodeURIComponent(authedUrl.password);
|
||||
|
||||
if (this.wwwAuthenticate.includes('Basic')) {
|
||||
const parsedUrl = new URL(this.url);
|
||||
const hash = BASIC.computeHash({ username: parsedUrl.username, password: parsedUrl.password });
|
||||
const hash = BASIC.computeHash({ username, password });
|
||||
return `Basic ${hash}`;
|
||||
}
|
||||
|
||||
@@ -692,10 +714,6 @@ export class RtspClient extends RtspBase {
|
||||
REQUIRED_WWW_AUTHENTICATE_KEYS,
|
||||
) as DigestWWWAuthenticateData;
|
||||
|
||||
const authedUrl = new URL(this.url);
|
||||
const username = decodeURIComponent(authedUrl.username);
|
||||
const password = decodeURIComponent(authedUrl.password);
|
||||
|
||||
const strippedUrl = new URL(url.toString());
|
||||
strippedUrl.username = '';
|
||||
strippedUrl.password = '';
|
||||
|
||||
@@ -175,6 +175,8 @@ export type RTPMap = ReturnType<typeof parseRtpMap>;
|
||||
export function parseRtpMap(mline: ReturnType<typeof parseMLine>, rtpmap: string) {
|
||||
const mlineType = mline.type;
|
||||
const match = rtpmap?.match(/a=rtpmap:([\d]+) (.*?)\/([\d]+)(\/([\d]+))?/);
|
||||
let channels = parseInt(match?.[5]) || undefined;
|
||||
let payloadType = parseInt(match?.[1]);
|
||||
|
||||
rtpmap = rtpmap?.toLowerCase();
|
||||
|
||||
@@ -222,14 +224,20 @@ export function parseRtpMap(mline: ReturnType<typeof parseMLine>, rtpmap: string
|
||||
if (mline.payloadTypes?.includes(0)) {
|
||||
codec = 'pcm_mulaw';
|
||||
ffmpegEncoder = 'pcm_mulaw';
|
||||
payloadType = 0;
|
||||
channels = 1;
|
||||
}
|
||||
else if (mline.payloadTypes?.includes(8)) {
|
||||
codec = 'pcm_alaw';
|
||||
ffmpegEncoder = 'pcm_alaw';
|
||||
payloadType = 8;
|
||||
channels = 1;
|
||||
}
|
||||
else if (mline.payloadTypes?.includes(14)) {
|
||||
codec = 'mp3';
|
||||
ffmpegEncoder = 'mp3';
|
||||
payloadType = 14;
|
||||
channels = 2;
|
||||
}
|
||||
else {
|
||||
// ffmpeg seems to omit the rtpmap type for pcm alaw when creating sdp?
|
||||
@@ -239,17 +247,29 @@ export function parseRtpMap(mline: ReturnType<typeof parseMLine>, rtpmap: string
|
||||
// https://en.wikipedia.org/wiki/RTP_payload_formats
|
||||
codec = 'pcm_alaw';
|
||||
ffmpegEncoder = 'pcm_alaw';
|
||||
payloadType = 8;
|
||||
channels = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// assigned payload types do not need to provide a clock, there is a default.
|
||||
let clock = parseInt(match?.[3]);
|
||||
if (!clock) {
|
||||
clock = undefined;
|
||||
if (codec === 'pcm_mulaw' || codec === 'pcm_alaw')
|
||||
clock = 8000;
|
||||
else if (codec === 'pcm_s16be')
|
||||
clock = 16000;
|
||||
}
|
||||
|
||||
return {
|
||||
line: rtpmap,
|
||||
codec,
|
||||
ffmpegEncoder,
|
||||
rawCodec: match?.[2],
|
||||
clock: parseInt(match?.[3]),
|
||||
channels: parseInt(match?.[5]) || undefined,
|
||||
payloadType: parseInt(match?.[1]),
|
||||
clock,
|
||||
channels,
|
||||
payloadType,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,6 @@ RUN brew update
|
||||
|
||||
# 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
|
||||
@@ -88,13 +85,13 @@ RUN mkdir -p ~/Library/LaunchAgents
|
||||
|
||||
if [ ! -d "$NODE_PATH" ]
|
||||
then
|
||||
echo "Unable to determine node@20 path."
|
||||
echo "Unable to determine node path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$NODE_BIN_PATH" ]
|
||||
then
|
||||
echo "Unable to determine node@20 bin path."
|
||||
echo "Unable to determine node bin path."
|
||||
echo "$NODE_BIN_PATH does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -19,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.18.0
|
||||
choco upgrade -y nodejs-lts --version=22.15.0
|
||||
|
||||
# Install VC Redist, which is necessary for portable python
|
||||
choco install -y vcredist140
|
||||
@@ -34,7 +34,7 @@ $SCRYPTED_WINDOWS_PYTHON_VERSION="-3.9"
|
||||
$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
|
||||
# Fixed in newer versions of NPM but not the one bundled with Node 2x
|
||||
# https://github.com/nodejs/node/issues/53538
|
||||
npm i -g npm
|
||||
|
||||
|
||||
4
packages/rpc/package-lock.json
generated
4
packages/rpc/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/rpc",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/rpc",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/rpc",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -25,9 +25,6 @@ def cosine_similarity(vector_a, vector_b):
|
||||
similarity = dot_product / (norm_a * norm_b)
|
||||
return similarity
|
||||
|
||||
|
||||
predictExecutor = concurrent.futures.ThreadPoolExecutor(8, "Vision-Predict")
|
||||
|
||||
class CoreMLFaceRecognition(FaceRecognizeDetection):
|
||||
def __init__(self, plugin, nativeId: str):
|
||||
super().__init__(plugin, nativeId)
|
||||
|
||||
2
plugins/ncnn/.vscode/settings.json
vendored
2
plugins/ncnn/.vscode/settings.json
vendored
@@ -1,6 +1,6 @@
|
||||
|
||||
{
|
||||
"scrypted.debugHost": "scrypted-nvr",
|
||||
"scrypted.debugHost": "scrypted-amd",
|
||||
"python.analysis.extraPaths": [
|
||||
"./node_modules/@scrypted/sdk/types/scrypted_python"
|
||||
]
|
||||
|
||||
48
plugins/ncnn/package-lock.json
generated
48
plugins/ncnn/package-lock.json
generated
@@ -1,34 +1,41 @@
|
||||
{
|
||||
"name": "@scrypted/coreml",
|
||||
"version": "0.1.77",
|
||||
"name": "@scrypted/ncnn",
|
||||
"version": "0.1.82",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/coreml",
|
||||
"version": "0.1.77",
|
||||
"name": "@scrypted/ncnn",
|
||||
"version": "0.1.82",
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
}
|
||||
},
|
||||
"../../sdk": {
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.3.77",
|
||||
"version": "0.5.12",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@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.7",
|
||||
"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.95.0",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.6.3",
|
||||
"webpack": "^5.96.1",
|
||||
"webpack-bundle-analyzer": "^4.10.2"
|
||||
},
|
||||
"bin": {
|
||||
@@ -41,11 +48,9 @@
|
||||
"scrypted-webpack": "bin/scrypted-webpack.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/stringify-object": "^4.0.5",
|
||||
"stringify-object": "^3.3.0",
|
||||
"@types/node": "^22.10.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typedoc": "^0.26.10"
|
||||
"typedoc": "^0.26.11"
|
||||
}
|
||||
},
|
||||
"../sdk": {
|
||||
@@ -61,22 +66,27 @@
|
||||
"version": "file:../../sdk",
|
||||
"requires": {
|
||||
"@babel/preset-typescript": "^7.26.0",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/stringify-object": "^4.0.5",
|
||||
"@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.7",
|
||||
"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.10",
|
||||
"typescript": "^5.5.4",
|
||||
"webpack": "^5.95.0",
|
||||
"tslib": "^2.8.1",
|
||||
"typedoc": "^0.26.11",
|
||||
"typescript": "^5.6.3",
|
||||
"webpack": "^5.96.1",
|
||||
"webpack-bundle-analyzer": "^4.10.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,15 @@
|
||||
"ClusterForkInterface",
|
||||
"ObjectDetection",
|
||||
"ObjectDetectionPreview"
|
||||
]
|
||||
|
||||
],
|
||||
"labels": {
|
||||
"require": [
|
||||
"@scrypted/ncnn"
|
||||
]
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
},
|
||||
"version": "0.1.77"
|
||||
"version": "0.1.82"
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ from __future__ import annotations
|
||||
import ast
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
import traceback
|
||||
from typing import Any, List, Tuple
|
||||
|
||||
@@ -18,11 +16,11 @@ import ncnn
|
||||
from common import yolo
|
||||
|
||||
try:
|
||||
from ncnn.face_recognition import NCNNFaceRecognition
|
||||
from nc.face_recognition import NCNNFaceRecognition
|
||||
except:
|
||||
NCNNFaceRecognition = None
|
||||
try:
|
||||
from ncnn.text_recognition import NCNNTextRecognition
|
||||
from nc.text_recognition import NCNNTextRecognition
|
||||
except:
|
||||
NCNNTextRecognition = None
|
||||
from predict import Prediction, PredictPlugin
|
||||
@@ -33,18 +31,14 @@ prepareExecutor = concurrent.futures.ThreadPoolExecutor(1, "NCNN-Prepare")
|
||||
|
||||
availableModels = [
|
||||
"Default",
|
||||
"scrypted_yolov10m_320",
|
||||
"scrypted_yolov10n_320",
|
||||
"scrypted_yolo_nas_s_320",
|
||||
"scrypted_yolov9e_320",
|
||||
"scrypted_yolov9c_relu_320",
|
||||
"scrypted_yolov9m_relu_320",
|
||||
"scrypted_yolov9s_relu_320",
|
||||
"scrypted_yolov9t_relu_320",
|
||||
"scrypted_yolov9c_320",
|
||||
"scrypted_yolov9m_320",
|
||||
"scrypted_yolov9s_320",
|
||||
"scrypted_yolov9t_320",
|
||||
"scrypted_yolov6n_320",
|
||||
"scrypted_yolov6s_320",
|
||||
"scrypted_yolov8n_320",
|
||||
"ssdlite_mobilenet_v2",
|
||||
"yolov4-tiny",
|
||||
]
|
||||
|
||||
|
||||
@@ -106,7 +100,7 @@ class NCNNPlugin(
|
||||
}
|
||||
files = [
|
||||
f"{model}/best_converted.ncnn.bin",
|
||||
f"{model}//best_converted.ncnn.param",
|
||||
f"{model}/best_converted.ncnn.param",
|
||||
]
|
||||
|
||||
for f in files:
|
||||
@@ -123,14 +117,10 @@ class NCNNPlugin(
|
||||
|
||||
|
||||
self.net = ncnn.Net()
|
||||
# self.net.opt.use_vulkan_compute = True
|
||||
# self.net.opt.use_winograd_convolution = False
|
||||
# self.net.opt.use_sgemm_convolution = False
|
||||
# self.net.opt.use_fp16_packed = False
|
||||
# self.net.opt.use_fp16_storage = False
|
||||
# self.net.opt.use_fp16_arithmetic = False
|
||||
# self.net.opt.use_int8_storage = False
|
||||
# self.net.opt.use_int8_arithmetic = False
|
||||
self.net.opt.use_vulkan_compute = True
|
||||
self.net.opt.use_fp16_packed = False
|
||||
self.net.opt.use_fp16_storage = False
|
||||
self.net.opt.use_fp16_arithmetic = False
|
||||
|
||||
self.net.load_param(paramFile)
|
||||
self.net.load_model(binFile)
|
||||
@@ -153,55 +143,55 @@ class NCNNPlugin(
|
||||
# self.loop = asyncio.get_event_loop()
|
||||
# self.minThreshold = 0.2
|
||||
|
||||
# self.faceDevice = None
|
||||
# self.textDevice = None
|
||||
self.faceDevice = None
|
||||
self.textDevice = None
|
||||
|
||||
# if not self.forked:
|
||||
# asyncio.ensure_future(self.prepareRecognitionModels(), loop=self.loop)
|
||||
if not self.forked:
|
||||
asyncio.ensure_future(self.prepareRecognitionModels(), loop=self.loop)
|
||||
|
||||
# async def prepareRecognitionModels(self):
|
||||
# try:
|
||||
# devices = [
|
||||
# {
|
||||
# "nativeId": "facerecognition",
|
||||
# "type": scrypted_sdk.ScryptedDeviceType.Builtin.value,
|
||||
# "interfaces": [
|
||||
# scrypted_sdk.ScryptedInterface.ClusterForkInterface.value,
|
||||
# scrypted_sdk.ScryptedInterface.ObjectDetection.value,
|
||||
# ],
|
||||
# "name": "NCNN Face Recognition",
|
||||
# },
|
||||
# ]
|
||||
async def prepareRecognitionModels(self):
|
||||
try:
|
||||
devices = [
|
||||
{
|
||||
"nativeId": "facerecognition",
|
||||
"type": scrypted_sdk.ScryptedDeviceType.Builtin.value,
|
||||
"interfaces": [
|
||||
scrypted_sdk.ScryptedInterface.ClusterForkInterface.value,
|
||||
scrypted_sdk.ScryptedInterface.ObjectDetection.value,
|
||||
],
|
||||
"name": "NCNN Face Recognition",
|
||||
},
|
||||
]
|
||||
|
||||
# if NCNNTextRecognition:
|
||||
# devices.append(
|
||||
# {
|
||||
# "nativeId": "textrecognition",
|
||||
# "type": scrypted_sdk.ScryptedDeviceType.Builtin.value,
|
||||
# "interfaces": [
|
||||
# scrypted_sdk.ScryptedInterface.ClusterForkInterface.value,
|
||||
# scrypted_sdk.ScryptedInterface.ObjectDetection.value,
|
||||
# ],
|
||||
# "name": "NCNN Text Recognition",
|
||||
# },
|
||||
# )
|
||||
if NCNNTextRecognition:
|
||||
devices.append(
|
||||
{
|
||||
"nativeId": "textrecognition",
|
||||
"type": scrypted_sdk.ScryptedDeviceType.Builtin.value,
|
||||
"interfaces": [
|
||||
scrypted_sdk.ScryptedInterface.ClusterForkInterface.value,
|
||||
scrypted_sdk.ScryptedInterface.ObjectDetection.value,
|
||||
],
|
||||
"name": "NCNN Text Recognition",
|
||||
},
|
||||
)
|
||||
|
||||
# await scrypted_sdk.deviceManager.onDevicesChanged(
|
||||
# {
|
||||
# "devices": devices,
|
||||
# }
|
||||
# )
|
||||
# except:
|
||||
# pass
|
||||
await scrypted_sdk.deviceManager.onDevicesChanged(
|
||||
{
|
||||
"devices": devices,
|
||||
}
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
# async def getDevice(self, nativeId: str) -> Any:
|
||||
# if nativeId == "facerecognition":
|
||||
# self.faceDevice = self.faceDevice or NCNNFaceRecognition(self, nativeId)
|
||||
# return self.faceDevice
|
||||
# if nativeId == "textrecognition":
|
||||
# self.textDevice = self.textDevice or NCNNTextRecognition(self, nativeId)
|
||||
# return self.textDevice
|
||||
# raise Exception("unknown device")
|
||||
async def getDevice(self, nativeId: str) -> Any:
|
||||
if nativeId == "facerecognition":
|
||||
self.faceDevice = self.faceDevice or NCNNFaceRecognition(self, nativeId)
|
||||
return self.faceDevice
|
||||
if nativeId == "textrecognition":
|
||||
self.textDevice = self.textDevice or NCNNTextRecognition(self, nativeId)
|
||||
return self.textDevice
|
||||
raise Exception("unknown device")
|
||||
|
||||
async def getSettings(self) -> list[Setting]:
|
||||
model = self.storage.getItem("model") or "Default"
|
||||
@@ -239,6 +229,8 @@ class NCNNPlugin(
|
||||
im = np.expand_dims(input, axis=0)
|
||||
im = im.transpose((0, 3, 1, 2)) # BHWC to BCHW, (n, 3, h, w)
|
||||
im = im.astype(np.float32) / 255.0
|
||||
# no batch? https://github.com/Tencent/ncnn/issues/5990#issuecomment-2832927105
|
||||
im = im.reshape((1, 3, 320, 320)).squeeze(0)
|
||||
im = np.ascontiguousarray(im) # contiguous
|
||||
return im
|
||||
|
||||
|
||||
1
plugins/ncnn/src/nc/async_infer.py
Symbolic link
1
plugins/ncnn/src/nc/async_infer.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../openvino/src/ov/async_infer.py
|
||||
111
plugins/ncnn/src/nc/face_recognition.py
Normal file
111
plugins/ncnn/src/nc/face_recognition.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
import ncnn
|
||||
from nc import async_infer
|
||||
from predict.face_recognize import FaceRecognizeDetection
|
||||
|
||||
faceDetectPrepare, faceDetectPredict = async_infer.create_executors("FaceDetect")
|
||||
faceRecognizePrepare, faceRecognizePredict = async_infer.create_executors(
|
||||
"FaceRecognize"
|
||||
)
|
||||
|
||||
|
||||
class NCNNFaceRecognition(FaceRecognizeDetection):
|
||||
def __init__(self, plugin, nativeId: str):
|
||||
super().__init__(plugin=plugin, nativeId=nativeId)
|
||||
self.prefer_relu = True
|
||||
|
||||
def downloadModel(self, model: str):
|
||||
scrypted_yolov9 = "scrypted_yolov9" in model
|
||||
ncnnmodel = "best_converted" if scrypted_yolov9 else model
|
||||
model_version = "v1"
|
||||
files = [
|
||||
f"{model}/{ncnnmodel}.ncnn.bin",
|
||||
f"{model}/{ncnnmodel}.ncnn.param",
|
||||
]
|
||||
|
||||
for f in files:
|
||||
p = self.downloadFile(
|
||||
f"https://github.com/koush/ncnn-models/raw/main/{f}",
|
||||
f"{model_version}/{f}",
|
||||
)
|
||||
if ".bin" in p:
|
||||
binFile = p
|
||||
if ".param" in p:
|
||||
paramFile = p
|
||||
|
||||
|
||||
net = ncnn.Net()
|
||||
net.opt.use_vulkan_compute = True
|
||||
net.opt.use_fp16_packed = False
|
||||
net.opt.use_fp16_storage = False
|
||||
net.opt.use_fp16_arithmetic = False
|
||||
|
||||
net.load_param(paramFile)
|
||||
net.load_model(binFile)
|
||||
|
||||
input_name = net.input_names()[0]
|
||||
|
||||
return [net, input_name]
|
||||
|
||||
async def predictDetectModel(self, input: Image.Image):
|
||||
def prepare():
|
||||
im = np.array(input)
|
||||
im = np.expand_dims(input, axis=0)
|
||||
im = im.transpose((0, 3, 1, 2)) # BHWC to BCHW, (n, 3, h, w)
|
||||
im = im.astype(np.float32) / 255.0
|
||||
# no batch? https://github.com/Tencent/ncnn/issues/5990#issuecomment-2832927105
|
||||
im = im.reshape((1, 3, 320, 320)).squeeze(0)
|
||||
im = np.ascontiguousarray(im) # contiguous
|
||||
return im
|
||||
|
||||
def predict(input_tensor):
|
||||
net, input_name = self.detectModel
|
||||
input_ncnn = ncnn.Mat(input_tensor)
|
||||
ex = net.create_extractor()
|
||||
ex.input(input_name, input_ncnn)
|
||||
|
||||
output_ncnn = ncnn.Mat()
|
||||
ex.extract("out0", output_ncnn)
|
||||
|
||||
output_tensors = np.array(output_ncnn)
|
||||
return output_tensors
|
||||
|
||||
input_tensor = await asyncio.get_event_loop().run_in_executor(
|
||||
faceDetectPrepare, lambda: prepare()
|
||||
)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
faceDetectPredict, lambda: predict(input_tensor)
|
||||
)
|
||||
|
||||
|
||||
async def predictFaceModel(self, input: np.ndarray):
|
||||
def prepare():
|
||||
# no batch? https://github.com/Tencent/ncnn/issues/5990#issuecomment-2832927105
|
||||
im = input.squeeze(0)
|
||||
im = np.ascontiguousarray(im) # contiguous
|
||||
return im
|
||||
|
||||
def predict(input_tensor):
|
||||
net, input_name = self.faceModel
|
||||
input_ncnn = ncnn.Mat(input_tensor)
|
||||
ex = net.create_extractor()
|
||||
ex.input(input_name, input_ncnn)
|
||||
|
||||
output_ncnn = ncnn.Mat()
|
||||
ex.extract("out0", output_ncnn)
|
||||
|
||||
output_tensors = np.array(output_ncnn)
|
||||
return output_tensors
|
||||
|
||||
input_tensor = await asyncio.get_event_loop().run_in_executor(
|
||||
faceDetectPrepare, lambda: prepare()
|
||||
)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
faceDetectPredict, lambda: predict(input_tensor)
|
||||
)
|
||||
105
plugins/ncnn/src/nc/text_recognition.py
Normal file
105
plugins/ncnn/src/nc/text_recognition.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import numpy as np
|
||||
|
||||
import ncnn
|
||||
from nc import async_infer
|
||||
from predict.text_recognize import TextRecognition
|
||||
|
||||
textDetectPrepare, textDetectPredict = async_infer.create_executors("TextDetect")
|
||||
textRecognizePrepare, textRecognizePredict = async_infer.create_executors(
|
||||
"TextRecognize"
|
||||
)
|
||||
|
||||
|
||||
class NCNNTextRecognition(TextRecognition):
|
||||
def downloadModel(self, model: str):
|
||||
model_version = "v1"
|
||||
files = [
|
||||
f"{model}/{model}.ncnn.bin",
|
||||
f"{model}/{model}.ncnn.param",
|
||||
]
|
||||
|
||||
for f in files:
|
||||
p = self.downloadFile(
|
||||
f"https://github.com/koush/ncnn-models/raw/main/{f}",
|
||||
f"{model_version}/{f}",
|
||||
)
|
||||
if ".bin" in p:
|
||||
binFile = p
|
||||
if ".param" in p:
|
||||
paramFile = p
|
||||
|
||||
|
||||
net = ncnn.Net()
|
||||
net.opt.use_vulkan_compute = True
|
||||
net.opt.use_fp16_packed = False
|
||||
net.opt.use_fp16_storage = False
|
||||
net.opt.use_fp16_arithmetic = False
|
||||
|
||||
net.load_param(paramFile)
|
||||
net.load_model(binFile)
|
||||
|
||||
input_name = net.input_names()[0]
|
||||
|
||||
return [net, input_name]
|
||||
|
||||
|
||||
async def predictDetectModel(self, input: np.ndarray):
|
||||
def prepare():
|
||||
# no batch? https://github.com/Tencent/ncnn/issues/5990#issuecomment-2832927105
|
||||
im = input.squeeze(0)
|
||||
im = np.ascontiguousarray(im) # contiguous
|
||||
return im
|
||||
|
||||
def predict(input_tensor):
|
||||
net, input_name = self.detectModel
|
||||
input_ncnn = ncnn.Mat(input_tensor)
|
||||
ex = net.create_extractor()
|
||||
ex.input(input_name, input_ncnn)
|
||||
|
||||
output_ncnn = ncnn.Mat()
|
||||
ex.extract("out0", output_ncnn)
|
||||
|
||||
output_tensors = np.array(output_ncnn)
|
||||
output_tensors = output_tensors.transpose((1, 2, 0))
|
||||
# readd a batch dimension
|
||||
output_tensors = np.expand_dims(output_tensors, axis=0)
|
||||
return output_tensors
|
||||
|
||||
input_tensor = await asyncio.get_event_loop().run_in_executor(
|
||||
textDetectPrepare, lambda: prepare()
|
||||
)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
textDetectPredict, lambda: predict(input_tensor)
|
||||
)
|
||||
|
||||
async def predictTextModel(self, input: np.ndarray):
|
||||
def prepare():
|
||||
# no batch? https://github.com/Tencent/ncnn/issues/5990#issuecomment-2832927105
|
||||
im = input.squeeze(0)
|
||||
im = np.ascontiguousarray(im) # contiguous
|
||||
return im
|
||||
|
||||
def predict(input_tensor):
|
||||
net, input_name = self.textModel
|
||||
input_ncnn = ncnn.Mat(input_tensor)
|
||||
ex = net.create_extractor()
|
||||
ex.input(input_name, input_ncnn)
|
||||
|
||||
output_ncnn = ncnn.Mat()
|
||||
ex.extract("out0", output_ncnn)
|
||||
|
||||
output_tensors = np.array(output_ncnn)
|
||||
# readd a batch dimension
|
||||
output_tensors = np.expand_dims(output_tensors, axis=0)
|
||||
return output_tensors
|
||||
|
||||
input_tensor = await asyncio.get_event_loop().run_in_executor(
|
||||
textRecognizePrepare, lambda: prepare()
|
||||
)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
textRecognizePredict, lambda: predict(input_tensor)
|
||||
)
|
||||
4
plugins/objectdetector/package-lock.json
generated
4
plugins/objectdetector/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.1.68",
|
||||
"version": "0.1.72",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.1.68",
|
||||
"version": "0.1.72",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.1.68",
|
||||
"version": "0.1.72",
|
||||
"description": "Scrypted Video Analysis Plugin. Installed alongside a detection service like OpenCV or TensorFlow.",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -138,7 +138,6 @@ export class FFmpegVideoFrameGenerator extends ScryptedDeviceBase implements Vid
|
||||
|
||||
try {
|
||||
reader();
|
||||
const flush = async () => { };
|
||||
|
||||
while (!finished) {
|
||||
frameDeferred = new Deferred();
|
||||
@@ -151,9 +150,7 @@ export class FFmpegVideoFrameGenerator extends ScryptedDeviceBase implements Vid
|
||||
yield {
|
||||
__json_copy_serialize_children: true,
|
||||
timestamp: 0,
|
||||
queued: 0,
|
||||
image,
|
||||
flush,
|
||||
};
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -85,7 +85,8 @@ export class SmartMotionSensor extends ScryptedDeviceBase implements Settings, R
|
||||
|
||||
this.storageSettings.settings.detections.onGet = async () => {
|
||||
const objectDetector: ObjectDetector = this.storageSettings.values.objectDetector;
|
||||
const choices = (await objectDetector?.getObjectTypes?.())?.classes || [];
|
||||
const classes = (await objectDetector?.getObjectTypes?.())?.classes || [];
|
||||
const choices = [...new Set(classes)];
|
||||
return {
|
||||
hide: !objectDetector,
|
||||
choices,
|
||||
|
||||
@@ -104,7 +104,8 @@ export class SmartOccupancySensor extends ScryptedDeviceBase implements Settings
|
||||
|
||||
this.storageSettings.settings.detections.onGet = async () => {
|
||||
const objectDetection: ObjectDetection = this.storageSettings.values.objectDetection;
|
||||
const choices = (await objectDetection?.getDetectionModel())?.classes || [];
|
||||
const classes = (await objectDetection?.getDetectionModel())?.classes || []
|
||||
const choices = [...new Set(classes)];
|
||||
return {
|
||||
hide: !objectDetection,
|
||||
choices,
|
||||
|
||||
@@ -2,6 +2,6 @@ import concurrent.futures
|
||||
|
||||
|
||||
def create_executors(name: str):
|
||||
prepare = concurrent.futures.ThreadPoolExecutor(1, f"OpenVINO-{name}Prepare")
|
||||
predict = concurrent.futures.ThreadPoolExecutor(1, f"OpenVINO-{name}Predict")
|
||||
prepare = concurrent.futures.ThreadPoolExecutor(1, f"{name}Prepare")
|
||||
predict = concurrent.futures.ThreadPoolExecutor(1, f"{name}Predict")
|
||||
return prepare, predict
|
||||
|
||||
817
plugins/prebuffer-mixin/package-lock.json
generated
817
plugins/prebuffer-mixin/package-lock.json
generated
@@ -1,24 +1,22 @@
|
||||
{
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.10.58",
|
||||
"version": "0.10.59",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.10.58",
|
||||
"version": "0.10.59",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/libav": "^1.0.199",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"h264-sps-parser": "^0.2.1",
|
||||
"semver": "^7.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/semver": "^7.3.12",
|
||||
"prebuild-install": "npm:@scrypted/prebuild-install@^7.1.9"
|
||||
"@types/semver": "^7.3.12"
|
||||
}
|
||||
},
|
||||
"../../common": {
|
||||
@@ -80,34 +78,10 @@
|
||||
"../sdk": {
|
||||
"extraneous": true
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@scrypted/common": {
|
||||
"resolved": "../../common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@scrypted/libav": {
|
||||
"version": "1.0.199",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/libav/-/libav-1.0.199.tgz",
|
||||
"integrity": "sha512-sIrTRwa5CSZgnbCzPEB/laBNJ6RoZ3BKkVrgMCX/GE7oYCBcxIYtgFq942DVckXA6+A6NfXBR1lLt8a52SPpyQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3",
|
||||
"follow-redirects": "^1.15.9",
|
||||
"node-addon-api": "^8.3.1",
|
||||
"tar": "^7.4.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@scrypted/sdk": {
|
||||
"resolved": "../../sdk",
|
||||
"link": true
|
||||
@@ -128,369 +102,11 @@
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"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"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/h264-sps-parser": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/h264-sps-parser/-/h264-sps-parser-0.2.1.tgz",
|
||||
"integrity": "sha512-1OCliBfrgCe2fu6eRRqN0xvhp9tFH/UVa1zdVmX/WcQAZrEB6xm/2RJ13F4h2OtQUMJqWv31fZakmTgrvbyIDA=="
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"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/minizlib": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.74.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
||||
"integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
|
||||
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"name": "@scrypted/prebuild-install",
|
||||
"version": "7.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/prebuild-install/-/prebuild-install-7.1.9.tgz",
|
||||
"integrity": "sha512-lKKX7TMlwToQIH2UX8p0JwFbp0Y2dwedEqgkpcTmRvaA9DOfhau7m40i4+Qo7F1ISMHo/NK1XntURrFlSm4ibg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"follow-redirects": "^1.15.6",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^1.0.1",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuild-install": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
@@ -503,133 +119,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"minizlib": "^3.0.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"yallist": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
|
||||
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs/node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"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/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||
"requires": {
|
||||
"minipass": "^7.0.4"
|
||||
}
|
||||
},
|
||||
"@scrypted/common": {
|
||||
"version": "file:../../common",
|
||||
"requires": {
|
||||
@@ -641,17 +139,6 @@
|
||||
"typescript": "^5.5.3"
|
||||
}
|
||||
},
|
||||
"@scrypted/libav": {
|
||||
"version": "1.0.199",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/libav/-/libav-1.0.199.tgz",
|
||||
"integrity": "sha512-sIrTRwa5CSZgnbCzPEB/laBNJ6RoZ3BKkVrgMCX/GE7oYCBcxIYtgFq942DVckXA6+A6NfXBR1lLt8a52SPpyQ==",
|
||||
"requires": {
|
||||
"detect-libc": "^2.0.3",
|
||||
"follow-redirects": "^1.15.9",
|
||||
"node-addon-api": "^8.3.1",
|
||||
"tar": "^7.4.3"
|
||||
}
|
||||
},
|
||||
"@scrypted/sdk": {
|
||||
"version": "file:../../sdk",
|
||||
"requires": {
|
||||
@@ -695,319 +182,21 @@
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
|
||||
"dev": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true
|
||||
},
|
||||
"github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"dev": true
|
||||
},
|
||||
"h264-sps-parser": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/h264-sps-parser/-/h264-sps-parser-0.2.1.tgz",
|
||||
"integrity": "sha512-1OCliBfrgCe2fu6eRRqN0xvhp9tFH/UVa1zdVmX/WcQAZrEB6xm/2RJ13F4h2OtQUMJqWv31fZakmTgrvbyIDA=="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dev": true
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||
"requires": {
|
||||
"minipass": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="
|
||||
},
|
||||
"mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"dev": true
|
||||
},
|
||||
"napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
|
||||
"dev": true
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "3.74.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
||||
"integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^7.3.5"
|
||||
}
|
||||
},
|
||||
"node-addon-api": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
|
||||
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"prebuild-install": {
|
||||
"version": "npm:@scrypted/prebuild-install@7.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/prebuild-install/-/prebuild-install-7.1.9.tgz",
|
||||
"integrity": "sha512-lKKX7TMlwToQIH2UX8p0JwFbp0Y2dwedEqgkpcTmRvaA9DOfhau7m40i4+Qo7F1ISMHo/NK1XntURrFlSm4ibg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"follow-redirects": "^1.15.6",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^1.0.1",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"requires": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"minizlib": "^3.0.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"yallist": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"tar-fs": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
|
||||
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"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
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.10.58",
|
||||
"version": "0.10.59",
|
||||
"description": "Video Stream Rebroadcast, Prebuffer, and Management Plugin for Scrypted.",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache-2.0",
|
||||
@@ -38,14 +38,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/libav": "^1.0.199",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"h264-sps-parser": "^0.2.1",
|
||||
"semver": "^7.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/semver": "^7.3.12",
|
||||
"prebuild-install": "npm:@scrypted/prebuild-install@^7.1.9"
|
||||
"@types/semver": "^7.3.12"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
import { Deferred } from "@scrypted/common/src/deferred";
|
||||
import { parseSdp } from "@scrypted/common/src/sdp-utils";
|
||||
import { sleep } from "@scrypted/common/src/sleep";
|
||||
import { StreamChunk } from "@scrypted/common/src/stream-parser";
|
||||
import { AVFormatContext, createAVFormatContext } from '@scrypted/libav';
|
||||
import { ResponseMediaStreamOptions } from "@scrypted/sdk";
|
||||
import { once } from 'events';
|
||||
import net from 'net';
|
||||
import { EventEmitter } from "stream";
|
||||
import tls from 'tls';
|
||||
import { RTSP_FRAME_MAGIC } from "../../../common/src/rtsp-server";
|
||||
import { ParserSession, setupActivityTimer } from "./ffmpeg-session";
|
||||
import { installLibavAddon } from "./libav-setup";
|
||||
import { negotiateMediaStream } from "./rfc4571";
|
||||
|
||||
let installPromise: Promise<void>;
|
||||
|
||||
export async function startLibavSession(console: Console, url: string, mediaStreamOptions: ResponseMediaStreamOptions, options: {
|
||||
useUdp: boolean,
|
||||
audioSoftMuted: boolean,
|
||||
activityTimeout: number,
|
||||
}): Promise<ParserSession<"rtsp">> {
|
||||
installPromise ||= installLibavAddon();
|
||||
await installPromise;
|
||||
|
||||
const formatContext = createAVFormatContext();
|
||||
try {
|
||||
return await startLibavSessionWrapped(formatContext, console, url, mediaStreamOptions, options);
|
||||
}
|
||||
catch (e) {
|
||||
await formatContext.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function startLibavSessionWrapped(formatContext: AVFormatContext, console: Console, url: string, mediaStreamOptions: ResponseMediaStreamOptions, options: {
|
||||
useUdp: boolean,
|
||||
audioSoftMuted: boolean,
|
||||
activityTimeout: number,
|
||||
}): Promise<ParserSession<"rtsp">> {
|
||||
const events = new EventEmitter();
|
||||
|
||||
let tlsProxy: net.Server;
|
||||
try {
|
||||
if (url.startsWith('rtsps:') || url.startsWith('https:')) {
|
||||
let { hostname, port } = new URL(url);
|
||||
if (!port) {
|
||||
if (url.startsWith('rtsps:'))
|
||||
port = '322';
|
||||
else
|
||||
port = '443';
|
||||
}
|
||||
|
||||
const portNumber = parseInt(port);
|
||||
if (!portNumber)
|
||||
throw new Error('invalid port number');
|
||||
|
||||
tlsProxy = net.createServer(async socket => {
|
||||
try {
|
||||
const tlsSocket = tls.connect({
|
||||
host: hostname,
|
||||
port: portNumber,
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
await once(tlsSocket, 'secureConnect');
|
||||
socket.pipe(tlsSocket).pipe(socket);
|
||||
}
|
||||
catch (e) {
|
||||
console.error('tls proxy error', e);
|
||||
socket.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
tlsProxy.listen(0, '127.0.0.1');
|
||||
await once(tlsProxy, 'listening');
|
||||
const localPort = (tlsProxy.address() as net.AddressInfo).port;
|
||||
// rewrite the url to use the local port
|
||||
const u = new URL(url);
|
||||
u.protocol = u.protocol.replace('s:', ':');
|
||||
u.hostname = '127.0.0.1';
|
||||
u.port = localPort.toString();
|
||||
url = u.toString();
|
||||
}
|
||||
|
||||
await formatContext.open(url, {
|
||||
rtsp_transport: options.useUdp ? 'udp' : 'tcp',
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
tlsProxy?.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
let sdp = formatContext.createSDP();
|
||||
const parsedSdp = parseSdp(sdp);
|
||||
// sdp may contain multiple audio/video sections. take only the first video section.
|
||||
sdp = [...parsedSdp.header.lines, ...parsedSdp.msections.map(msection => msection.lines).flat()].join('\r\n');
|
||||
|
||||
const killDeferred = new Deferred<void>();
|
||||
const startDeferred = new Deferred<void>();
|
||||
killDeferred.promise.catch(e => {
|
||||
events.emit('killed');
|
||||
events.emit('error', e);
|
||||
tlsProxy?.close();
|
||||
});
|
||||
|
||||
const kill = (e?: Error) => {
|
||||
killDeferred.reject(e || new Error('killed'));
|
||||
startDeferred.reject(e || new Error('killed'));
|
||||
}
|
||||
|
||||
const { resetActivityTimer } = setupActivityTimer('rtsp', kill, events, options?.activityTimeout);
|
||||
|
||||
(async () => {
|
||||
const pipelines: {
|
||||
streamIndex: number,
|
||||
writeFormatContext: AVFormatContext,
|
||||
}[] = [];
|
||||
|
||||
try {
|
||||
await startDeferred.promise;
|
||||
formatContext.streams.forEach(stream => {
|
||||
if (options.audioSoftMuted && stream.type === 'audio')
|
||||
return;
|
||||
if (stream.type !== 'video' && stream.type !== 'audio')
|
||||
return;
|
||||
|
||||
const { codec } = stream;
|
||||
const rtp = createAVFormatContext();
|
||||
rtp.create('rtp', rtp => {
|
||||
const prefix = Buffer.alloc(4);
|
||||
prefix.writeUInt8(RTSP_FRAME_MAGIC, 0);
|
||||
prefix.writeUInt8(stream.index, 1);
|
||||
prefix.writeUInt16BE(rtp.length, 2);
|
||||
|
||||
const chunk: StreamChunk = {
|
||||
chunks: [prefix, rtp],
|
||||
type: codec === 'hevc' ? 'h265' : codec,
|
||||
};
|
||||
|
||||
events.emit('rtsp', chunk);
|
||||
});
|
||||
rtp.newStream({
|
||||
formatContext,
|
||||
streamIndex: stream.index,
|
||||
});
|
||||
|
||||
pipelines.push({
|
||||
streamIndex: stream.index,
|
||||
writeFormatContext: rtp,
|
||||
});
|
||||
});
|
||||
|
||||
while (!killDeferred.finished) {
|
||||
using result = await formatContext.receiveFrame(pipelines);
|
||||
if (result)
|
||||
resetActivityTimer();
|
||||
if (killDeferred.finished)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
kill(e);
|
||||
}
|
||||
finally {
|
||||
kill(new Error('rtsp read loop exited'));
|
||||
|
||||
await sleep(1000);
|
||||
await Promise.allSettled(pipelines.map(pipeline => pipeline.writeFormatContext.close()));
|
||||
await sleep(1000);
|
||||
await formatContext.close();
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
start: () => {
|
||||
startDeferred.resolve();
|
||||
},
|
||||
sdp: Promise.resolve(sdp),
|
||||
get isActive() { return !killDeferred.finished },
|
||||
kill(error?: Error) {
|
||||
kill(error);
|
||||
},
|
||||
killed: killDeferred.promise,
|
||||
resetActivityTimer,
|
||||
negotiateMediaStream: (requestMediaStream, inputVideoCodec, inputAudioCodec) => {
|
||||
return negotiateMediaStream(sdp, mediaStreamOptions, inputVideoCodec, inputAudioCodec, requestMediaStream);
|
||||
},
|
||||
emit(container: 'rtsp', chunk: StreamChunk) {
|
||||
events.emit(container, chunk);
|
||||
return this;
|
||||
},
|
||||
on(event: string, cb: any) {
|
||||
events.on(event, cb);
|
||||
return this;
|
||||
},
|
||||
once(event: any, cb: any) {
|
||||
events.once(event, cb);
|
||||
return this;
|
||||
},
|
||||
removeListener(event, cb) {
|
||||
events.removeListener(event, cb);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import * as libav from '@scrypted/libav';
|
||||
import path from 'path';
|
||||
|
||||
function getAddonInstallPath() {
|
||||
if (process.versions.electron)
|
||||
process.env.npm_config_runtime = 'electron';
|
||||
const binaryUrl = libav.getBinaryUrl();
|
||||
const u = new URL(binaryUrl);
|
||||
const withoutExtension = path.basename(u.pathname).replace(/\.tar.gz$/, '');
|
||||
return path.join(process.env.SCRYPTED_PLUGIN_VOLUME, libav.version, withoutExtension);
|
||||
}
|
||||
|
||||
export async function installLibavAddon(installOnly = false) {
|
||||
const nr = installOnly
|
||||
? null
|
||||
// @ts-expect-error
|
||||
: __non_webpack_require__;
|
||||
await libav.install(getAddonInstallPath(), nr);
|
||||
}
|
||||
@@ -14,9 +14,8 @@ import { parse as h264SpsParse } from "h264-sps-parser";
|
||||
import net, { AddressInfo } from 'net';
|
||||
import path from 'path';
|
||||
import { Duplex } from 'stream';
|
||||
import { ParserOptions, ParserSession, startParserSession } from './ffmpeg-session';
|
||||
import { ParserOptions, ParserSession, startParserSession } from './ffmpeg-rebroadcast';
|
||||
import { FileRtspServer } from './file-rtsp-server';
|
||||
import { startLibavSession } from './libav-parser';
|
||||
import { getUrlLocalAdresses } from './local-addresses';
|
||||
import { REBROADCAST_MIXIN_INTERFACE_TOKEN } from './rebroadcast-mixin-token';
|
||||
import { connectRFC4571Parser, startRFC4571Parser } from './rfc4571';
|
||||
@@ -33,8 +32,6 @@ const SCRYPTED_PARSER_TCP = 'Scrypted (TCP)';
|
||||
const SCRYPTED_PARSER_UDP = 'Scrypted (UDP)';
|
||||
const FFMPEG_PARSER_TCP = 'FFmpeg (TCP)';
|
||||
const FFMPEG_PARSER_UDP = 'FFmpeg (UDP)';
|
||||
const LIBAV_PARSER_TCP = 'Scrypted libav (TCP)';
|
||||
const LIBAV_PARSER_UDP = 'Scrypted libav (UDP)';
|
||||
const STRING_DEFAULT = 'Default';
|
||||
|
||||
interface PrebufferStreamChunk extends StreamChunk {
|
||||
@@ -62,6 +59,7 @@ class PrebufferSession {
|
||||
rtspPrebuffer: PrebufferStreamChunk[] = []
|
||||
parsers: { [container: string]: StreamParser };
|
||||
sdp: Promise<string>;
|
||||
usingScryptedParser = false;
|
||||
usingScryptedUdpParser = false;
|
||||
|
||||
mixinDevice: VideoCamera;
|
||||
@@ -238,8 +236,6 @@ class PrebufferSession {
|
||||
rtspParser = localStorage.getItem('defaultRtspParser');
|
||||
}
|
||||
switch (rtspParser) {
|
||||
case LIBAV_PARSER_TCP:
|
||||
case LIBAV_PARSER_UDP:
|
||||
case FFMPEG_PARSER_TCP:
|
||||
case FFMPEG_PARSER_UDP:
|
||||
case SCRYPTED_PARSER_TCP:
|
||||
@@ -396,8 +392,6 @@ class PrebufferSession {
|
||||
SCRYPTED_PARSER_UDP,
|
||||
FFMPEG_PARSER_TCP,
|
||||
FFMPEG_PARSER_UDP,
|
||||
LIBAV_PARSER_TCP,
|
||||
LIBAV_PARSER_UDP,
|
||||
],
|
||||
}
|
||||
);
|
||||
@@ -548,11 +542,12 @@ class PrebufferSession {
|
||||
// before launching the parser session, clear out the last detected codec.
|
||||
// an erroneous cached codec could cause ffmpeg to fail to start.
|
||||
this.storage.removeItem(this.lastDetectedAudioCodecKey);
|
||||
let usingScryptedParser = false;
|
||||
this.usingScryptedParser = false;
|
||||
|
||||
const h264Oddities = this.getLastH264Oddities();
|
||||
|
||||
if (isRfc4571) {
|
||||
usingScryptedParser = true;
|
||||
this.usingScryptedParser = true;
|
||||
this.console.log('bypassing ffmpeg: using scrypted rfc4571 parser')
|
||||
const json = await mediaManager.convertMediaObjectToJSON<any>(mo, 'x-scrypted/x-rfc4571');
|
||||
let { url, sdp, mediaStreamOptions } = json;
|
||||
@@ -571,22 +566,21 @@ class PrebufferSession {
|
||||
sessionMso = ffmpegInput.mediaStreamOptions || this.advertisedMediaStreamOptions;
|
||||
|
||||
let { parser, isDefault } = this.getParser(sessionMso);
|
||||
usingScryptedParser = parser === SCRYPTED_PARSER_TCP || parser === SCRYPTED_PARSER_UDP;
|
||||
const usingLibavParser = parser === LIBAV_PARSER_TCP || parser === LIBAV_PARSER_UDP;
|
||||
this.usingScryptedParser = parser === SCRYPTED_PARSER_TCP || parser === SCRYPTED_PARSER_UDP;
|
||||
this.usingScryptedUdpParser = parser === SCRYPTED_PARSER_UDP;
|
||||
|
||||
// prefer ffmpeg if this is a prebuffered stream.
|
||||
if (isDefault
|
||||
&& usingScryptedParser
|
||||
&& this.usingScryptedParser
|
||||
&& h264Oddities
|
||||
&& !this.stopInactive
|
||||
&& sessionMso.tool !== 'scrypted') {
|
||||
this.console.warn('H264 oddities were detected in prebuffered video stream, the Default Scrypted RTSP Parser will not be used. Falling back to FFmpeg. This can be overriden by setting the RTSP Parser to Scrypted.');
|
||||
usingScryptedParser = false;
|
||||
this.usingScryptedParser = false;
|
||||
parser = FFMPEG_PARSER_TCP;
|
||||
}
|
||||
|
||||
if (usingScryptedParser) {
|
||||
if (this.usingScryptedParser) {
|
||||
const rtspParser = createRtspParser();
|
||||
rbo.parsers.rtsp = rtspParser;
|
||||
|
||||
@@ -596,16 +590,6 @@ class PrebufferSession {
|
||||
rtspRequestTimeout: 10000,
|
||||
});
|
||||
}
|
||||
else if (usingLibavParser) {
|
||||
const rtspParser = createRtspParser();
|
||||
rbo.parsers.rtsp = rtspParser;
|
||||
|
||||
session = await startLibavSession(this.console, ffmpegInput.url, ffmpegInput.mediaStreamOptions, {
|
||||
useUdp: parser === LIBAV_PARSER_UDP,
|
||||
audioSoftMuted,
|
||||
activityTimeout: 10000,
|
||||
});
|
||||
}
|
||||
else {
|
||||
let acodec: string[];
|
||||
|
||||
@@ -662,7 +646,7 @@ class PrebufferSession {
|
||||
console.error('rebroadcast error', e)
|
||||
});
|
||||
|
||||
if (usingScryptedParser && !isRfc4571) {
|
||||
if (this.usingScryptedParser && !isRfc4571) {
|
||||
// watch the stream for 10 seconds to see if an weird nalu is encountered.
|
||||
// if one is found and using scrypted parser as default, will need to restart rebroadcast to prevent
|
||||
// downstream issues.
|
||||
@@ -1022,6 +1006,10 @@ class PrebufferSession {
|
||||
const codecInfo = await this.parseCodecs(true);
|
||||
const mediaStreamOptions: ResponseMediaStreamOptions = session.negotiateMediaStream(options, codecInfo.inputVideoCodec, codecInfo.inputAudioCodec);
|
||||
let sdp = await this.sdp;
|
||||
if (!mediaStreamOptions.video?.h264Info && this.usingScryptedParser) {
|
||||
mediaStreamOptions.video ||= {};
|
||||
mediaStreamOptions.video.h264Info = this.getLastH264Probe();
|
||||
}
|
||||
|
||||
if (this.mixin.streamSettings.storageSettings.values.noAudio)
|
||||
mediaStreamOptions.audio = null;
|
||||
@@ -1635,8 +1623,6 @@ export class RebroadcastPlugin extends AutoenableMixinProvider implements MixinP
|
||||
SCRYPTED_PARSER_UDP,
|
||||
FFMPEG_PARSER_TCP,
|
||||
FFMPEG_PARSER_UDP,
|
||||
LIBAV_PARSER_TCP,
|
||||
LIBAV_PARSER_UDP,
|
||||
],
|
||||
onPut: () => {
|
||||
this.log.a('Rebroadcast Plugin will restart momentarily.');
|
||||
@@ -1769,9 +1755,7 @@ export class RebroadcastPlugin extends AutoenableMixinProvider implements MixinP
|
||||
this.setHasEnabledMixin(mixinDeviceState.id);
|
||||
|
||||
const { id } = mixinDeviceState;
|
||||
const forked = sdk.fork<RebroadcastPluginFork>({
|
||||
runtime: 'node',
|
||||
});
|
||||
const forked = sdk.fork<RebroadcastPluginFork>();
|
||||
const { worker } = forked;
|
||||
const result = await forked.result;
|
||||
const mixin = await result.newPrebufferMixin(mixinDevice, mixinDeviceInterfaces, mixinDeviceState);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MediaStreamOptions, ResponseMediaStreamOptions } from "@scrypted/sdk";
|
||||
import { parse as spsParse } from "h264-sps-parser";
|
||||
import net from 'net';
|
||||
import { EventEmitter, Readable } from "stream";
|
||||
import { ParserSession, setupActivityTimer } from "./ffmpeg-session";
|
||||
import { ParserSession, setupActivityTimer } from "./ffmpeg-rebroadcast";
|
||||
import { getSpsResolution } from "./sps-resolution";
|
||||
|
||||
export function negotiateMediaStream(sdp: string, mediaStreamOptions: MediaStreamOptions, inputVideoCodec: string, inputAudioCodec: string, requestMediaStream: MediaStreamOptions) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { StreamChunk } from "@scrypted/common/src/stream-parser";
|
||||
import { ResponseMediaStreamOptions } from "@scrypted/sdk";
|
||||
import dgram from 'dgram';
|
||||
import { EventEmitter } from "stream";
|
||||
import { ParserSession, setupActivityTimer } from "./ffmpeg-session";
|
||||
import { ParserSession, setupActivityTimer } from "./ffmpeg-rebroadcast";
|
||||
import { negotiateMediaStream } from "./rfc4571";
|
||||
|
||||
export type RtspChannelCodecMapping = { [key: number]: string };
|
||||
|
||||
4
plugins/snapshot/package-lock.json
generated
4
plugins/snapshot/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/snapshot",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/snapshot",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
"sharp": "^0.33.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/snapshot",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"description": "Snapshot Plugin for Scrypted",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ffmpegFilterImage, ffmpegFilterImageBuffer } from './ffmpeg-image-filte
|
||||
import { ImageConverter, ImageConverterNativeId } from './image-converter';
|
||||
import { ImageReader, ImageReaderNativeId, loadSharp, loadVipsImage } from './image-reader';
|
||||
import { ImageWriter, ImageWriterNativeId } from './image-writer';
|
||||
import { fixLegacyClipPath, normalizeBox, polygonIntersectsBoundingBox } from '../../objectdetector/src/polygon';
|
||||
|
||||
const { mediaManager, systemManager } = sdk;
|
||||
if (os.cpus().find(cpu => cpu.model?.toLowerCase().includes('qemu'))) {
|
||||
@@ -433,10 +434,11 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
|
||||
if (!this.storageSettings.values.snapshotCropScale?.length)
|
||||
return picture;
|
||||
|
||||
const xmin = Math.min(...this.storageSettings.values.snapshotCropScale.map(([x, y]) => x)) / 100;
|
||||
const ymin = Math.min(...this.storageSettings.values.snapshotCropScale.map(([x, y]) => y)) / 100;
|
||||
const xmax = Math.max(...this.storageSettings.values.snapshotCropScale.map(([x, y]) => x)) / 100;
|
||||
const ymax = Math.max(...this.storageSettings.values.snapshotCropScale.map(([x, y]) => y)) / 100;
|
||||
const clipPath = fixLegacyClipPath(this.storageSettings.values.snapshotCropScale);
|
||||
const xmin = Math.min(...clipPath.map(([x, y]) => x));
|
||||
const ymin = Math.min(...clipPath.map(([x, y]) => y));
|
||||
const xmax = Math.max(...clipPath.map(([x, y]) => x));
|
||||
const ymax = Math.max(...clipPath.map(([x, y]) => y));
|
||||
|
||||
if (loadSharp()) {
|
||||
const vips = await loadVipsImage(picture, this.id);
|
||||
|
||||
4
plugins/webrtc/package-lock.json
generated
4
plugins/webrtc/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.2.76",
|
||||
"version": "0.2.77",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.2.76",
|
||||
"version": "0.2.77",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.2.76",
|
||||
"version": "0.2.78",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
"prescrypted-setup-project": "scrypted-package-json",
|
||||
|
||||
@@ -458,7 +458,13 @@ export function parseOptions(options: RTCSignalingOptions) {
|
||||
if (options?.userAgent?.includes('Firefox/'))
|
||||
sessionSupportsH264High = true;
|
||||
|
||||
const transcodeWidth = Math.max(640, Math.min(options?.screen?.width || 960, 1280));
|
||||
// Some devices return a `screen width` value that is not a multiple of 2, which is not allowed for the h264 codec.
|
||||
// Convert to a smaller even value.
|
||||
const screenWidthForTranscodeH264 = !options?.screen?.width
|
||||
? 960
|
||||
: Math.trunc(options?.screen?.width / 2) * 2;
|
||||
|
||||
const transcodeWidth = Math.max(640, Math.min(screenWidthForTranscodeH264, 1280));
|
||||
const devicePixelRatio = options?.screen?.devicePixelRatio || 1;
|
||||
const width = (options?.screen?.width * devicePixelRatio) || undefined;
|
||||
const height = (options?.screen?.height * devicePixelRatio) || undefined;
|
||||
|
||||
@@ -79,6 +79,16 @@ function getNalType(data: Buffer): number {
|
||||
return (data[0] & 0x7E) >> 1; // 6 bits starting from bit 1
|
||||
}
|
||||
|
||||
function isKeyFrame(nalType: number): boolean {
|
||||
// For IDR frames, send codec info first
|
||||
if (nalType === NAL_TYPE_IDR_W_RADL || nalType === NAL_TYPE_IDR_N_LP ||
|
||||
nalType === NAL_TYPE_BLA_W_LP || nalType === NAL_TYPE_BLA_W_RADL ||
|
||||
nalType === NAL_TYPE_BLA_N_LP || nalType === NAL_TYPE_CRA_NUT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to depacketize Aggregation Packets (similar to STAP-A in H.264)
|
||||
export function depacketizeAP(data: Buffer) {
|
||||
const ret: Buffer[] = [];
|
||||
@@ -385,7 +395,7 @@ export class H265Repacketizer {
|
||||
}
|
||||
else {
|
||||
// For IDR frames, send codec info first
|
||||
if (splitNaluType === NAL_TYPE_IDR_W_RADL || splitNaluType === NAL_TYPE_IDR_N_LP) {
|
||||
if (isKeyFrame(splitNaluType)) {
|
||||
this.maybeSendAPCodecInfo(first, ret);
|
||||
}
|
||||
|
||||
@@ -689,9 +699,7 @@ export class H265Repacketizer {
|
||||
}
|
||||
|
||||
// For IDR frames, send codec info first
|
||||
if (nalType === NAL_TYPE_IDR_W_RADL || nalType === NAL_TYPE_IDR_N_LP ||
|
||||
nalType === NAL_TYPE_BLA_W_LP || nalType === NAL_TYPE_BLA_W_RADL ||
|
||||
nalType === NAL_TYPE_BLA_N_LP) {
|
||||
if (isKeyFrame(nalType)) {
|
||||
this.maybeSendAPCodecInfo(packet, ret);
|
||||
}
|
||||
|
||||
|
||||
262
server/package-lock.json
generated
262
server/package-lock.json
generated
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.138.22",
|
||||
"version": "0.138.27",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.138.22",
|
||||
"version": "0.138.27",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@scrypted/ffmpeg-static": "^6.1.0-build3",
|
||||
"@scrypted/node-pty": "^1.0.22",
|
||||
"@scrypted/node-pty": "^1.0.24",
|
||||
"@scrypted/types": "^0.5.12",
|
||||
"adm-zip": "^0.5.16",
|
||||
"body-parser": "^2.2.0",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dotenv": "^16.4.7",
|
||||
"dotenv": "^16.5.0",
|
||||
"engine.io": "^6.6.4",
|
||||
"express": "^5.1.0",
|
||||
"follow-redirects": "^1.15.9",
|
||||
"http-auth": "^4.2.0",
|
||||
"level": "^9.0.0",
|
||||
"level": "^10.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mime": "^4.0.7",
|
||||
"mime-types": "^3.0.1",
|
||||
"node-dijkstra": "^2.5.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-gyp": "^11.2.0",
|
||||
@@ -47,7 +47,8 @@
|
||||
"@types/follow-redirects": "^1.14.4",
|
||||
"@types/http-auth": "^4.1.4",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^22.14.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/node-dijkstra": "^2.5.6",
|
||||
"@types/node-forge": "^1.3.11",
|
||||
"@types/semver": "^7.7.0",
|
||||
@@ -564,12 +565,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@scrypted/node-pty": {
|
||||
"version": "1.0.22",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/node-pty/-/node-pty-1.0.22.tgz",
|
||||
"integrity": "sha512-GXpxrtDkbEG9oFOqJ4kVNT8r0HBzSDzQyVAllAApHTec2NezgKU2wMDK668s0gPW7Q1mvF3g0EV4646cAA0hHg==",
|
||||
"version": "1.0.24",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/node-pty/-/node-pty-1.0.24.tgz",
|
||||
"integrity": "sha512-UyrsMRsH0hRazVDUeA+oBrIPcoryDhXXD5fVS/z19q4zHube20Tj7xvP1AWte1NGGQ7AnIZiK8EPlQgweXC15g==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prebuild-install": "npm:@scrypted/prebuild-install@^7.1.8"
|
||||
"prebuild-install": "npm:@scrypted/prebuild-install@^7.1.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@scrypted/types": {
|
||||
@@ -680,10 +682,17 @@
|
||||
"integrity": "sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mime-types": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
||||
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
|
||||
"integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==",
|
||||
"version": "22.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz",
|
||||
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -784,20 +793,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/abstract-level": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-2.0.2.tgz",
|
||||
"integrity": "sha512-pPJixmXk/kTKLB2sSue7o4Uj6TlLD2XfaP2gWZomHVCC6cuUGX/VslQqKG1yZHfXwBb/3lS6oSTMPGzh1P1iig==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-3.1.0.tgz",
|
||||
"integrity": "sha512-j2e+TsAxy7Ri+0h7dJqwasymgt0zHBWX4+nMk3XatyuqgHfdstBJ9wsMfbiGwE1O+QovRyPcVAqcViMYdyPaaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"is-buffer": "^2.0.5",
|
||||
"level-supports": "^6.0.0",
|
||||
"level-supports": "^6.2.0",
|
||||
"level-transcoder": "^1.0.1",
|
||||
"maybe-combine-errors": "^1.0.0",
|
||||
"module-error": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
@@ -812,6 +821,27 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
|
||||
@@ -889,7 +919,8 @@
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
@@ -908,6 +939,7 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
@@ -932,6 +964,7 @@
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
@@ -989,12 +1022,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browser-level": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/browser-level/-/browser-level-2.0.0.tgz",
|
||||
"integrity": "sha512-RuYSCHG/jwFCrK+KWA3dLSUNLKHEgIYhO5ORPjJMjCt7T3e+RzpIDmYKWRHxq2pfKGXjlRuEff7y7RESAAgzew==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/browser-level/-/browser-level-3.0.0.tgz",
|
||||
"integrity": "sha512-kGXtLh29jMwqKaskz5xeDLtCtN1KBz/DbQSqmvH7QdJiyGRC7RAM8PPg6gvUiNMa+wVnaxS9eSmEtP/f5ajOVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abstract-level": "^2.0.1"
|
||||
"abstract-level": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
@@ -1131,13 +1164,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/classic-level": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/classic-level/-/classic-level-2.0.0.tgz",
|
||||
"integrity": "sha512-ftiMvKgCQK+OppXcvMieDoYlYLYWhScK6yZRFBrrlHQRbm4k6Gr+yDgu/wt3V0k1/jtNbuiXAsRmuAFcD0Tx5Q==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/classic-level/-/classic-level-3.0.0.tgz",
|
||||
"integrity": "sha512-yGy8j8LjPbN0Bh3+ygmyYvrmskVita92pD/zCoalfcC9XxZj6iDtZTAnz+ot7GG8p9KLTG+MZ84tSA4AhkgVZQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abstract-level": "^2.0.0",
|
||||
"abstract-level": "^3.1.0",
|
||||
"module-error": "^1.0.1",
|
||||
"napi-macros": "^2.2.2",
|
||||
"node-gyp-build": "^4.3.0"
|
||||
@@ -1292,6 +1325,7 @@
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
@@ -1313,9 +1347,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||
"version": "16.5.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
|
||||
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -1376,6 +1410,7 @@
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
@@ -1491,6 +1526,7 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -1581,27 +1617,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -1736,7 +1751,8 @@
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "3.0.3",
|
||||
@@ -1799,7 +1815,8 @@
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "11.0.0",
|
||||
@@ -1998,7 +2015,8 @@
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
@@ -2017,7 +2035,8 @@
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "9.0.5",
|
||||
@@ -2113,14 +2132,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/level": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/level/-/level-9.0.0.tgz",
|
||||
"integrity": "sha512-n+mVuf63mUEkd8NUx7gwxY+QF5vtkibv6fXTGUgtHWLPDaA5/XZjLcI/Q1nQ8k6OttHT6Ezt+7nSEXsRUfHtOQ==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/level/-/level-10.0.0.tgz",
|
||||
"integrity": "sha512-aZJvdfRr/f0VBbSRF5C81FHON47ZsC2TkGxbBezXpGGXAUEL/s6+GP73nnhAYRSCIqUNsmJjfeOF4lzRDKbUig==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abstract-level": "^2.0.1",
|
||||
"browser-level": "^2.0.0",
|
||||
"classic-level": "^2.0.0"
|
||||
"abstract-level": "^3.1.0",
|
||||
"browser-level": "^3.0.0",
|
||||
"classic-level": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -2235,35 +2254,22 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz",
|
||||
"integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
@@ -2288,6 +2294,7 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -2430,7 +2437,8 @@
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/module-error": {
|
||||
"version": "1.0.2",
|
||||
@@ -2449,7 +2457,8 @@
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/napi-macros": {
|
||||
"version": "2.2.2",
|
||||
@@ -2466,14 +2475,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.63.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.63.0.tgz",
|
||||
"integrity": "sha512-vAszCsOUrUxjGAmdnM/pq7gUgie0IRteCQMX6d4A534fQCR93EJU5qgzBvU6EkFfK27s0T3HEV3BOyJIr7OMYw==",
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.4.0.tgz",
|
||||
"integrity": "sha512-+sBEWs/HZ3ZDBtPSPKfYndkTF9ebr1BJm/z2TBDJj/upiOx9J6BeGXRtFyOXz1r6vUqzsCRM5pUr+K83i64agg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
"semver": "^7.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-dijkstra": {
|
||||
@@ -2651,9 +2661,10 @@
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"name": "@scrypted/prebuild-install",
|
||||
"version": "7.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/prebuild-install/-/prebuild-install-7.1.8.tgz",
|
||||
"integrity": "sha512-ghmvo7gRUUyTUtjBGEcZfL7fizBNdzFFLnMRiNh3+lL25t8Rjv4EDBEKmDT6C4/wKVfdtzAnITBBc9r9DhVqRg==",
|
||||
"version": "7.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/prebuild-install/-/prebuild-install-7.1.10.tgz",
|
||||
"integrity": "sha512-DkDz+z6O4EKe17GJ3rs9hdyv9gYj3VI9GhO2ZzBhSmBNNYkYs5DULMczsxRpLH8eygJ0zzW8Arf7+hip/oUZwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
@@ -2662,7 +2673,7 @@
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^1.0.1",
|
||||
"node-abi": "^3.3.0",
|
||||
"node-abi": "^4.4.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"tar-fs": "^2.0.0",
|
||||
@@ -2710,9 +2721,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
@@ -2771,6 +2783,7 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
@@ -2785,6 +2798,7 @@
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
@@ -2937,27 +2951,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -3208,6 +3201,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
@@ -3266,6 +3260,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -3301,12 +3296,14 @@
|
||||
"node_modules/tar-fs/node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
@@ -3359,6 +3356,7 @@
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
@@ -3380,27 +3378,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
@@ -3461,7 +3438,8 @@
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.138.23",
|
||||
"version": "0.138.27",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@scrypted/ffmpeg-static": "^6.1.0-build3",
|
||||
"@scrypted/node-pty": "^1.0.22",
|
||||
"@scrypted/node-pty": "^1.0.24",
|
||||
"@scrypted/types": "^0.5.12",
|
||||
"adm-zip": "^0.5.16",
|
||||
"body-parser": "^2.2.0",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dotenv": "^16.4.7",
|
||||
"dotenv": "^16.5.0",
|
||||
"engine.io": "^6.6.4",
|
||||
"express": "^5.1.0",
|
||||
"follow-redirects": "^1.15.9",
|
||||
"http-auth": "^4.2.0",
|
||||
"level": "^9.0.0",
|
||||
"level": "^10.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mime": "^4.0.7",
|
||||
"mime-types": "^3.0.1",
|
||||
"node-dijkstra": "^2.5.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-gyp": "^11.2.0",
|
||||
@@ -37,7 +37,8 @@
|
||||
"@types/follow-redirects": "^1.14.4",
|
||||
"@types/http-auth": "^4.1.4",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^22.14.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/node-dijkstra": "^2.5.6",
|
||||
"@types/node-forge": "^1.3.11",
|
||||
"@types/semver": "^7.7.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BufferConverter, DeviceManager, FFmpegInput, MediaConverter, MediaManager, MediaObjectCreateOptions, MediaObject as MediaObjectInterface, MediaStreamUrl, ScryptedDevice, ScryptedInterface, ScryptedInterfaceProperty, ScryptedMimeTypes, ScryptedNativeId, SystemDeviceState, SystemManager } from "@scrypted/types";
|
||||
import fs from 'fs';
|
||||
import https from 'https';
|
||||
import mime from 'mime';
|
||||
import mime from 'mime-types';
|
||||
import Graph from 'node-dijkstra';
|
||||
import path from 'path';
|
||||
import MimeType from 'whatwg-mimetype';
|
||||
@@ -77,8 +77,8 @@ export abstract class MediaManagerBase implements MediaManager {
|
||||
}
|
||||
|
||||
const ab = await fs.promises.readFile(filename);
|
||||
const mt = mime.getType(filename);
|
||||
const mo = this.createMediaObject(ab, mt);
|
||||
const mt = mime.lookup(filename);
|
||||
const mo = this.createMediaObject(ab, mt || 'application/octet-stream');
|
||||
return mo;
|
||||
}
|
||||
});
|
||||
@@ -238,8 +238,8 @@ export abstract class MediaManagerBase implements MediaManager {
|
||||
|
||||
ensureMediaObjectRemote(mediaObject: string | MediaObjectInterface): MediaObjectRemote {
|
||||
if (typeof mediaObject === 'string') {
|
||||
const mt = mime.getType(mediaObject);
|
||||
return this.createMediaObjectRemote(mediaObject, mt);
|
||||
const mt = mime.lookup(mediaObject);
|
||||
return this.createMediaObjectRemote(mediaObject, mt || 'application/octet-stream');
|
||||
}
|
||||
return mediaObject as MediaObjectRemote;
|
||||
}
|
||||
|
||||
@@ -172,6 +172,9 @@ function createClusterForkParam(mainFilename: string, clusterId: string, cluster
|
||||
});
|
||||
let getRemote: any;
|
||||
let ping: any;
|
||||
const timeout = setTimeout(() => {
|
||||
threadPeer.kill('cluster fork timeout');
|
||||
}, 10000);
|
||||
try {
|
||||
const initializeCluster: InitializeCluster = await threadPeer.getParam('initializeCluster');
|
||||
await initializeCluster({ clusterId, clusterSecret, clusterWorkerId });
|
||||
@@ -189,9 +192,6 @@ function createClusterForkParam(mainFilename: string, clusterId: string, cluster
|
||||
}
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
threadPeer.kill('cluster fork timeout');
|
||||
}, 10000);
|
||||
const clusterGetRemote = (...args: any[]) => {
|
||||
clearTimeout(timeout);
|
||||
return {
|
||||
@@ -252,6 +252,7 @@ export function startClusterClient(mainFilename: string, options?: {
|
||||
}
|
||||
catch (e) {
|
||||
console.warn('Cluster server not available.', host, port, e);
|
||||
rawSocket.destroy();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -264,6 +265,7 @@ export function startClusterClient(mainFilename: string, options?: {
|
||||
await once(socket, 'secureConnect');
|
||||
}
|
||||
catch (e) {
|
||||
socket.destroy();
|
||||
console.warn('Cluster server tls failed.', host, port, e);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user