@apocaliss92/scrypted-reolink-native 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apocaliss92/scrypted-reolink-native",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Use any reolink camera with Scrypted, even older/unsupported models without HTTP protocol support",
5
5
  "author": "@apocaliss92",
6
6
  "license": "Apache",
package/src/camera.ts CHANGED
@@ -199,6 +199,11 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
199
199
  private readonly onSimpleEventBound = (ev: ReolinkSimpleEvent) => this.onSimpleEvent(ev);
200
200
 
201
201
  storageSettings = new StorageSettings(this, {
202
+ debugLogs: {
203
+ title: 'Debug logs',
204
+ type: 'boolean',
205
+ immediate: true,
206
+ },
202
207
  // Basic connection settings
203
208
  ipAddress: {
204
209
  title: 'IP Address',
@@ -262,11 +267,6 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
262
267
  await this.credentialsChanged();
263
268
  }
264
269
  },
265
- debugLogs: {
266
- title: 'Debug logs',
267
- type: 'boolean',
268
- immediate: true,
269
- },
270
270
  mixinsSetup: {
271
271
  type: 'boolean',
272
272
  hide: true,
@@ -1319,15 +1319,22 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
1319
1319
  }
1320
1320
 
1321
1321
  protected getStreamClientInputs(): BaichuanConnectionConfig {
1322
- const { ipAddress, username, password } = this.storageSettings.values;
1322
+ const { ipAddress, username, password, uid, discoveryMethod } = this.storageSettings.values;
1323
1323
  const debugOptions = this.getBaichuanDebugOptions();
1324
1324
 
1325
+ const normalizedUid = this.isBattery ? normalizeUid(uid) : undefined;
1326
+ if (this.isBattery && !normalizedUid) {
1327
+ throw new Error('UID is required for battery cameras (BCUDP)');
1328
+ }
1329
+
1325
1330
  return {
1326
1331
  host: ipAddress,
1327
1332
  username,
1328
1333
  password,
1334
+ uid: normalizedUid,
1329
1335
  transport: this.transport,
1330
1336
  debugOptions,
1337
+ udpDiscoveryMethod: discoveryMethod as BaichuanClientOptions["udpDiscoveryMethod"],
1331
1338
  };
1332
1339
  }
1333
1340
 
@@ -2348,17 +2355,24 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2348
2355
  const { rtspChannel, variantType } = this.storageSettings.values;
2349
2356
 
2350
2357
  try {
2351
- // Lens-scoped behavior: request streams only for the current lens/variant.
2352
- // This keeps a single native_main and native_sub for the device.
2353
- const lensParam: NativeVideoStreamVariant | undefined = variantType as any;
2354
2358
 
2355
2359
  const { nativeStreams, rtmpStreams, rtspStreams } = await client.buildVideoStreamOptions({
2356
2360
  onNvr: this.isOnNvr,
2357
2361
  channel: rtspChannel,
2358
2362
  compositeOnly: this.isMultiFocal,
2359
- ...(lensParam !== undefined ? { lens: lensParam } : {})
2363
+ lens: variantType,
2360
2364
  });
2361
2365
 
2366
+ logger.debug(`Supported streams: ${JSON.stringify({
2367
+ nativeStreams,
2368
+ rtmpStreams,
2369
+ rtspStreams,
2370
+ variantType,
2371
+ onNvr: this.isOnNvr,
2372
+ channel: rtspChannel,
2373
+ compositeOnly: this.isMultiFocal,
2374
+ })}`);
2375
+
2362
2376
  // const urls = client.getRtspUrl(rtspChannel);
2363
2377
 
2364
2378
  // let supportedStreams: ReolinkSupportedStream[] = [];
@@ -2413,12 +2427,10 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2413
2427
  }
2414
2428
  }
2415
2429
 
2416
- if (streams.length) {
2417
- logger.log('Fetched video stream options', streams.map((s) => s.name).join(', '));
2418
- logger.debug(JSON.stringify(streams));
2419
- this.cachedVideoStreamOptions = streams;
2420
- return streams;
2421
- }
2430
+ logger.log('Fetched video stream options', streams.map((s) => s.name).join(', '));
2431
+ logger.debug(JSON.stringify({ streams }));
2432
+ this.cachedVideoStreamOptions = streams;
2433
+ return streams;
2422
2434
 
2423
2435
  return [];
2424
2436
  } finally {
@@ -2605,6 +2617,7 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2605
2617
  const { interfaces, type } = getDeviceInterfaces({
2606
2618
  capabilities,
2607
2619
  logger: this.console,
2620
+ lensType: this.storageSettings.values.variantType,
2608
2621
  });
2609
2622
 
2610
2623
  const device: Device = {
@@ -2696,7 +2709,7 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2696
2709
  this.storageSettings.settings.pipSize.hide = !this.isMultiFocal;
2697
2710
  this.storageSettings.settings.pipMargin.hide = !this.isMultiFocal;
2698
2711
 
2699
- this.storageSettings.settings.uid.hide = !this.isBattery
2712
+ this.storageSettings.settings.uid.hide = !this.isBattery || this.isOnNvr;
2700
2713
  this.storageSettings.settings.discoveryMethod.hide = !this.isBattery && !this.nvrDevice;
2701
2714
 
2702
2715
  if (this.isBattery && !this.storageSettings.values.mixinsSetup) {
package/src/multiFocal.ts CHANGED
@@ -50,9 +50,10 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
50
50
  const { interfaces } = getDeviceInterfaces({
51
51
  capabilities,
52
52
  logger,
53
+ lensType,
53
54
  });
54
55
 
55
- // logger.debug(`Interfaces found for lens ${lensType}: ${JSON.stringify({ interfaces, capabilities, multifocalInfo })}`);
56
+ logger.debug(`Interfaces found for lens ${lensType}: ${JSON.stringify({ interfaces, capabilities, multifocalInfo })}`);
56
57
 
57
58
  return { interfaces, capabilities };
58
59
  }
@@ -193,15 +194,23 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
193
194
  }
194
195
 
195
196
  protected getStreamClientInputs(): BaichuanConnectionConfig {
196
- const { ipAddress, username, password } = this.storageSettings.values;
197
+ const { ipAddress, username, password, uid, discoveryMethod } = this.storageSettings.values;
197
198
  const debugOptions = this.getBaichuanDebugOptions();
198
199
 
200
+ // Multifocal battery cams use BCUDP for streaming too; UID is required.
201
+ const normalizedUid = this.isBattery ? uid?.trim() || undefined : undefined;
202
+ if (this.isBattery && !normalizedUid) {
203
+ throw new Error('UID is required for battery cameras (BCUDP)');
204
+ }
205
+
199
206
  return {
200
207
  host: ipAddress,
201
208
  username,
202
209
  password,
210
+ uid: normalizedUid,
203
211
  transport: this.transport,
204
212
  debugOptions,
213
+ udpDiscoveryMethod: discoveryMethod,
205
214
  };
206
215
  }
207
216
 
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DeviceCapabilities, EnrichedRecordingFile, ParsedRecordingFileName, RecordingFile, ReolinkBaichuanApi, ReolinkDeviceInfo, VodFile, VodSearchResponse } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
1
+ import type { DeviceCapabilities, EnrichedRecordingFile, NativeVideoStreamVariant, ParsedRecordingFileName, RecordingFile, ReolinkBaichuanApi, ReolinkDeviceInfo, VodFile, VodSearchResponse } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
2
2
  import sdk, { DeviceBase, HttpRequest, HttpResponse, MediaObject, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, VideoClip, VideoClips } from "@scrypted/sdk";
3
3
  import { spawn } from "node:child_process";
4
4
  import { Readable } from "stream";
@@ -58,9 +58,10 @@ export const pirSuffix = `-pir`;
58
58
 
59
59
  export const getDeviceInterfaces = (props: {
60
60
  capabilities: DeviceCapabilities,
61
- logger: Console
61
+ logger: Console,
62
+ lensType?: NativeVideoStreamVariant
62
63
  }) => {
63
- const { capabilities, logger } = props;
64
+ const { capabilities, logger, lensType } = props;
64
65
 
65
66
  const interfaces = [
66
67
  ScryptedInterface.VideoCamera,
@@ -71,9 +72,12 @@ export const getDeviceInterfaces = (props: {
71
72
  ScryptedInterface.AudioSensor,
72
73
  ScryptedInterface.MotionSensor,
73
74
  ScryptedInterface.VideoTextOverlays,
74
- ScryptedInterface.VideoClips,
75
75
  ];
76
76
 
77
+ if (!lensType) {
78
+ interfaces.push(ScryptedInterface.VideoClips);
79
+ }
80
+
77
81
  try {
78
82
  const {
79
83
  hasPtz,