@camstack/addon-provider-reolink 1.2.139 → 1.2.140

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/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-CNf5ZN-e.mjs";
2
- import { A as splitAnnexBToNalPayloads2, C as extractVpsFromAnnexB, D as normalizeDebugOptions, E as md5StrModern, M as traceLog, O as recordingsTraceLog, S as extractSpsFromAnnexB, T as isH265Irap, _ as convertToAnnexB2, a as BC_MAGIC, b as eventTraceLog, c as BaichuanVideoStream, d as aesDecrypt, f as aesEncrypt, g as convertToAnnexB, h as bcHeaderHasPayloadOffset, i as BC_CLASS_MODERN_24, j as talkTraceLog, k as splitAnnexBToNalPayloads, l as BcMediaAnnexBDecoder, m as bcEncrypt, n as BC_CLASS_LEGACY, o as BC_MAGIC_REV, p as bcDecrypt, r as BC_CLASS_MODERN_20, t as BC_CLASS_FILE_DOWNLOAD, u as __require$1, v as debugLog, w as getH265NalType, x as extractPpsFromAnnexB, y as deriveAesKey } from "./chunk-KWWUCNIY-Ccq-OAGJ.mjs";
2
+ import { A as splitAnnexBToNalPayloads2, C as extractVpsFromAnnexB, D as normalizeDebugOptions, E as md5StrModern, M as traceLog, O as recordingsTraceLog, S as extractSpsFromAnnexB, T as isH265Irap, _ as convertToAnnexB2, a as BC_MAGIC, b as eventTraceLog, c as BaichuanVideoStream, d as aesDecrypt, f as aesEncrypt, g as convertToAnnexB, h as bcHeaderHasPayloadOffset, i as BC_CLASS_MODERN_24, j as talkTraceLog, k as splitAnnexBToNalPayloads, l as BcMediaAnnexBDecoder, m as bcEncrypt, n as BC_CLASS_LEGACY, o as BC_MAGIC_REV, p as bcDecrypt, r as BC_CLASS_MODERN_20, t as BC_CLASS_FILE_DOWNLOAD, u as __require$1, v as debugLog, w as getH265NalType, x as extractPpsFromAnnexB, y as deriveAesKey } from "./chunk-ZQFQRCLQ-BNqCZtSS.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { EventEmitter } from "events";
5
5
  import * as fs2 from "fs";
@@ -5381,7 +5381,7 @@ var ZodIssueCode = {
5381
5381
  var ZodFirstPartyTypeKind;
5382
5382
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5383
5383
  //#endregion
5384
- //#region ../types/dist/sleep-B1y0Fo1U.mjs
5384
+ //#region ../types/dist/sleep-vl6nBE8d.mjs
5385
5385
  /**
5386
5386
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5387
5387
  * window to float samples (D455).
@@ -31874,6 +31874,47 @@ var ptzCapability = {
31874
31874
  auth: "admin"
31875
31875
  }),
31876
31876
  /**
31877
+ * Make WHERE THE HEAD IS POINTING RIGHT NOW this camera's home.
31878
+ *
31879
+ * `setHomePreset` takes a preset id, and a preset id is the wrong shape for
31880
+ * the most natural thing an operator does: aim the camera, then say "here".
31881
+ * It is also the only shape a camera whose home is NOT a preset can accept
31882
+ * -- Reolink's home is a guard point, a stored position with no id at all,
31883
+ * and hiding the control for that case (as the UI briefly did) left the one
31884
+ * vendor with a native home unable to set it.
31885
+ *
31886
+ * Each provider does it its own way:
31887
+ * reolink `setGrd` with `needSetPos`, pinning the guard point here
31888
+ * hikvision / amcrest save a preset, then pin it as home
31889
+ * onvif REFUSES -- its home is the PTZ origin and cannot be moved
31890
+ *
31891
+ * A provider that cannot honour it throws rather than silently doing
31892
+ * nothing: an operator who pressed "set home here" and saw no error would
31893
+ * believe it took.
31894
+ */
31895
+ captureHomeHere: method(object({ deviceId: number() }), _void(), {
31896
+ kind: "mutation",
31897
+ auth: "admin"
31898
+ }),
31899
+ /**
31900
+ * How long the camera waits, idle, before returning home on its own --
31901
+ * `null` when it has no such behaviour.
31902
+ *
31903
+ * Reolink's guard point carries one (`timeout`, freely settable in
31904
+ * seconds). It is a real function of the camera that we did not expose at
31905
+ * all, and it belongs next to the home it governs rather than in a vendor
31906
+ * settings page nobody associates with Home.
31907
+ */
31908
+ getHomeReturnSeconds: method(object({ deviceId: number() }), number().int().nullable()),
31909
+ /** Set the idle-return delay. Refused by a camera that has no such timer. */
31910
+ setHomeReturnSeconds: method(object({
31911
+ deviceId: number(),
31912
+ seconds: number().int().min(0).max(3600)
31913
+ }), _void(), {
31914
+ kind: "mutation",
31915
+ auth: "admin"
31916
+ }),
31917
+ /**
31877
31918
  * Pull the current PTZ position. Redundant with the auto-injected
31878
31919
  * `getStatus` method (see `status` below); kept for callers that
31879
31920
  * haven't migrated. Will be folded into `getStatus` in a future
@@ -41531,6 +41572,12 @@ Object.freeze({
41531
41572
  addonId: null,
41532
41573
  access: "create"
41533
41574
  },
41575
+ "ptz.captureHomeHere": {
41576
+ capName: "ptz",
41577
+ capScope: "device",
41578
+ addonId: null,
41579
+ access: "create"
41580
+ },
41534
41581
  "ptz.continuousMove": {
41535
41582
  capName: "ptz",
41536
41583
  capScope: "device",
@@ -41549,6 +41596,12 @@ Object.freeze({
41549
41596
  addonId: null,
41550
41597
  access: "view"
41551
41598
  },
41599
+ "ptz.getHomeReturnSeconds": {
41600
+ capName: "ptz",
41601
+ capScope: "device",
41602
+ addonId: null,
41603
+ access: "view"
41604
+ },
41552
41605
  "ptz.getOptions": {
41553
41606
  capName: "ptz",
41554
41607
  capScope: "device",
@@ -41603,6 +41656,12 @@ Object.freeze({
41603
41656
  addonId: null,
41604
41657
  access: "create"
41605
41658
  },
41659
+ "ptz.setHomeReturnSeconds": {
41660
+ capName: "ptz",
41661
+ capScope: "device",
41662
+ addonId: null,
41663
+ access: "create"
41664
+ },
41606
41665
  "ptz.stop": {
41607
41666
  capName: "ptz",
41608
41667
  capScope: "device",
@@ -44766,6 +44825,11 @@ Object.freeze({
44766
44825
  form: "single",
44767
44826
  optional: false
44768
44827
  }],
44828
+ "ptz.captureHomeHere": [{
44829
+ name: "deviceId",
44830
+ form: "single",
44831
+ optional: false
44832
+ }],
44769
44833
  "ptz.continuousMove": [{
44770
44834
  name: "deviceId",
44771
44835
  form: "single",
@@ -44781,6 +44845,11 @@ Object.freeze({
44781
44845
  form: "single",
44782
44846
  optional: false
44783
44847
  }],
44848
+ "ptz.getHomeReturnSeconds": [{
44849
+ name: "deviceId",
44850
+ form: "single",
44851
+ optional: false
44852
+ }],
44784
44853
  "ptz.getOptions": [{
44785
44854
  name: "deviceId",
44786
44855
  form: "single",
@@ -44826,6 +44895,11 @@ Object.freeze({
44826
44895
  form: "single",
44827
44896
  optional: false
44828
44897
  }],
44898
+ "ptz.setHomeReturnSeconds": [{
44899
+ name: "deviceId",
44900
+ form: "single",
44901
+ optional: false
44902
+ }],
44829
44903
  "ptz.stop": [{
44830
44904
  name: "deviceId",
44831
44905
  form: "single",
@@ -68510,7 +68584,7 @@ var require_yazl = /* @__PURE__ */ __commonJSMin(((exports) => {
68510
68584
  }
68511
68585
  }));
68512
68586
  //#endregion
68513
- //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-HL6TWIAL.js
68587
+ //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-KWQVN7H5.js
68514
68588
  var import_undici = require_undici();
68515
68589
  var import_yazl = /* @__PURE__ */ __toESM(require_yazl(), 1);
68516
68590
  var FLAGS_CAM_V2 = {
@@ -74927,7 +75001,7 @@ var require_lz4 = /* @__PURE__ */ __commonJSMin(((exports) => {
74927
75001
  };
74928
75002
  }));
74929
75003
  //#endregion
74930
- //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-3SEJZ2U5.js
75004
+ //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-CE77DTET.js
74931
75005
  var import_fxp = require_fxp();
74932
75006
  var import_lz4 = /* @__PURE__ */ __toESM(require_lz4(), 1);
74933
75007
  function encodeHeader(h) {
@@ -75246,8 +75320,8 @@ function buildC2mQ(params) {
75246
75320
  const os = params.os ?? "MAC";
75247
75321
  return buildP2pXml(`<C2M_Q><uid>${xmlEscape(params.uid)}</uid><p>${xmlEscape(os)}</p></C2M_Q>`);
75248
75322
  }
75249
- function parseIpPortBlock(tag, body) {
75250
- const m = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i").exec(body);
75323
+ function parseIpPortBlock(tag2, body) {
75324
+ const m = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
75251
75325
  if (!m) return void 0;
75252
75326
  const block = m[1] ?? "";
75253
75327
  const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
@@ -75292,8 +75366,8 @@ function parseR2cCr(xml) {
75292
75366
  if (!Number.isFinite(rsp)) return void 0;
75293
75367
  const sidStr = /<sid>(-?\d+)<\/sid>/i.exec(body)?.[1];
75294
75368
  const sid = sidStr != null ? Number(sidStr) : void 0;
75295
- const parseCustom = (tag) => {
75296
- const mm = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i").exec(body);
75369
+ const parseCustom = (tag2) => {
75370
+ const mm = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
75297
75371
  if (!mm) return void 0;
75298
75372
  const block = mm[1] ?? "";
75299
75373
  const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
@@ -76853,12 +76927,12 @@ function asLogger(logger) {
76853
76927
  error: resolveMethod(base, "error"),
76854
76928
  debug: resolveMethod(base, "debug")
76855
76929
  };
76856
- out.child = (tag) => createTaggedLogger(out, tag);
76930
+ out.child = (tag2) => createTaggedLogger(out, tag2);
76857
76931
  return out;
76858
76932
  }
76859
- function createTaggedLogger(base, tag) {
76933
+ function createTaggedLogger(base, tag2) {
76860
76934
  const b = base.log ? base : asLogger(base);
76861
- const prefix = `[${tag}] `;
76935
+ const prefix = `[${tag2}] `;
76862
76936
  const wrap = (fn) => {
76863
76937
  return (message, ...optionalParams) => {
76864
76938
  if (typeof message === "string") fn(`${prefix}${message}`, ...optionalParams);
@@ -76885,7 +76959,7 @@ function createDebugGateLogger(base, enabled = false) {
76885
76959
  error: b.error,
76886
76960
  debug: enabled ? b.debug : noop
76887
76961
  };
76888
- out.child = (tag) => createDebugGateLogger(createTaggedLogger(out, tag), enabled);
76962
+ out.child = (tag2) => createDebugGateLogger(createTaggedLogger(out, tag2), enabled);
76889
76963
  return out;
76890
76964
  }
76891
76965
  function isTalkCmd(cmdId) {
@@ -82579,29 +82653,29 @@ function parseSupportXml(xml) {
82579
82653
  if (!match) return void 0;
82580
82654
  const supportXml = match[1] ?? "";
82581
82655
  const ptzMode = supportXml.match(/<ptzMode>([^<]*)<\/ptzMode>/i)?.[1];
82582
- const topLevelInt = (tag) => {
82583
- return toNumberOrUndefined(supportXml.match(new RegExp(`<${tag}>([^<]*)<\\/${tag}>`, "i"))?.[1]);
82656
+ const topLevelInt = (tag2) => {
82657
+ return toNumberOrUndefined(supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1]);
82584
82658
  };
82585
- const topLevelString = (tag) => {
82586
- return supportXml.match(new RegExp(`<${tag}>([^<]*)<\\/${tag}>`, "i"))?.[1];
82659
+ const topLevelString = (tag2) => {
82660
+ return supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1];
82587
82661
  };
82588
82662
  const items = [];
82589
82663
  for (const itemMatch of supportXml.matchAll(/<item[^>]*>([\s\S]*?)<\/item>/gi)) {
82590
82664
  const itemXml = itemMatch[1] ?? "";
82591
82665
  const item = { chnID: toNumberOrUndefined(itemXml.match(/<chnID>([^<]*)<\/chnID>/i)?.[1]) ?? 0 };
82592
82666
  for (const tagMatch of itemXml.matchAll(/<([A-Za-z0-9_]+)>([^<]*)<\/\1>/g)) {
82593
- const tag = tagMatch[1];
82667
+ const tag2 = tagMatch[1];
82594
82668
  const value = tagMatch[2];
82595
- if (!tag) continue;
82596
- if (tag === "chnID") continue;
82597
- item[tag] = toNumberOrUndefined(value) ?? value;
82669
+ if (!tag2) continue;
82670
+ if (tag2 === "chnID") continue;
82671
+ item[tag2] = toNumberOrUndefined(value) ?? value;
82598
82672
  }
82599
82673
  items.push(item);
82600
82674
  }
82601
82675
  const support = { items };
82602
82676
  if (ptzMode !== void 0) support.ptzMode = ptzMode;
82603
- const assignInt = (key, tag) => {
82604
- const v = topLevelInt(tag);
82677
+ const assignInt = (key, tag2) => {
82678
+ const v = topLevelInt(tag2);
82605
82679
  if (v !== void 0) support[key] = v;
82606
82680
  };
82607
82681
  assignInt("IOInputPortNum", "IOInputPortNum");
@@ -82828,15 +82902,15 @@ function extractCanvasFromShelterXml(xml) {
82828
82902
  const yMatch = xml.match(/<topLeftY>(\d+)<\/topLeftY>/g) ?? [];
82829
82903
  let canvasX = 0;
82830
82904
  let canvasY = 0;
82831
- for (const tag of xMatch) {
82832
- const v = Number(tag.replace(/<\/?topLeftX>/g, "")) | 0;
82905
+ for (const tag2 of xMatch) {
82906
+ const v = Number(tag2.replace(/<\/?topLeftX>/g, "")) | 0;
82833
82907
  if (v > 0) {
82834
82908
  canvasX = v & 65535;
82835
82909
  break;
82836
82910
  }
82837
82911
  }
82838
- for (const tag of yMatch) {
82839
- const v = Number(tag.replace(/<\/?topLeftY>/g, "")) | 0;
82912
+ for (const tag2 of yMatch) {
82913
+ const v = Number(tag2.replace(/<\/?topLeftY>/g, "")) | 0;
82840
82914
  if (v > 0) {
82841
82915
  canvasY = v & 65535;
82842
82916
  break;
@@ -82849,9 +82923,9 @@ function extractCanvasFromShelterXml(xml) {
82849
82923
  }
82850
82924
  function parseRectTags(block) {
82851
82925
  const out = {};
82852
- const grab = (tag) => {
82853
- const m = block.match(new RegExp(`<${tag}>([^<]*)<\\/${tag}>`));
82854
- if (m && m[1] !== void 0) out[tag] = m[1];
82926
+ const grab = (tag2) => {
82927
+ const m = block.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`));
82928
+ if (m && m[1] !== void 0) out[tag2] = m[1];
82855
82929
  };
82856
82930
  grab("id");
82857
82931
  grab("name");
@@ -83096,9 +83170,9 @@ var buildDetectionClasses = (parsed, recordType) => {
83096
83170
  };
83097
83171
  var getXmlTexts = (xml, tags) => {
83098
83172
  const out = {};
83099
- for (const tag of tags) {
83100
- const v = getXmlText(xml, tag);
83101
- if (v !== void 0) out[tag] = v;
83173
+ for (const tag2 of tags) {
83174
+ const v = getXmlText(xml, tag2);
83175
+ if (v !== void 0) out[tag2] = v;
83102
83176
  }
83103
83177
  return out;
83104
83178
  };
@@ -83360,11 +83434,11 @@ function patchBlock(xml, block, fields) {
83360
83434
  const end = xml.indexOf(`</${block}>`, start);
83361
83435
  if (end < 0) return xml;
83362
83436
  let body = xml.slice(start, end);
83363
- for (const [tag, value] of Object.entries(fields)) {
83437
+ for (const [tag2, value] of Object.entries(fields)) {
83364
83438
  if (value === void 0) continue;
83365
83439
  const escaped = escapeXmlText(typeof value === "boolean" ? value ? "1" : "0" : String(value));
83366
- if (body.includes(`<${tag}>`)) body = body.replace(new RegExp(`<${tag}>[^<]*<\\/${tag}>`), `<${tag}>${escaped}</${tag}>`);
83367
- else body += `<${tag}>${escaped}</${tag}>`;
83440
+ if (body.includes(`<${tag2}>`)) body = body.replace(new RegExp(`<${tag2}>[^<]*<\\/${tag2}>`), `<${tag2}>${escaped}</${tag2}>`);
83441
+ else body += `<${tag2}>${escaped}</${tag2}>`;
83368
83442
  }
83369
83443
  return xml.slice(0, start) + body + xml.slice(end);
83370
83444
  }
@@ -83432,6 +83506,66 @@ var OSD_CORNER_LABELS = {
83432
83506
  "bottom-left": "Bottom left",
83433
83507
  "bottom-right": "Bottom right"
83434
83508
  };
83509
+ function wireFloat(value) {
83510
+ return value.toExponential(6).replace(/e([+-])(\d)$/, "e$10$2");
83511
+ }
83512
+ function buildPtzGuardExtensionXml(channelId, direction) {
83513
+ return `<?xml version="1.0" encoding="UTF-8" ?>
83514
+ <Extension version="1.1">
83515
+ <channelId>${channelId}</channelId>${direction === "read" ? `
83516
+ <chnType>0</chnType>` : ""}
83517
+ </Extension>
83518
+ `;
83519
+ }
83520
+ function guardBody(channelId, command, fields) {
83521
+ return [
83522
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",
83523
+ "<body>",
83524
+ "<PtzGuard version=\"1.1\">",
83525
+ `<channelId>${channelId}</channelId>`,
83526
+ ...fields,
83527
+ `<command>${command}</command>`,
83528
+ "<imageName></imageName>",
83529
+ `<xpos>${wireFloat(0)}</xpos>`,
83530
+ `<ypos>${wireFloat(0)}</ypos>`,
83531
+ `<height>${wireFloat(0)}</height>`,
83532
+ `<width>${wireFloat(0)}</width>`,
83533
+ "<mode>global</mode>",
83534
+ "</PtzGuard>",
83535
+ "</body>",
83536
+ ""
83537
+ ].join("\n");
83538
+ }
83539
+ function buildPtzGuardGoXml(channelId) {
83540
+ return guardBody(channelId, "toGrd", ["<benable>0</benable>", "<timeout>68</timeout>"]);
83541
+ }
83542
+ function buildPtzGuardSetXml(input) {
83543
+ return guardBody(input.channelId, "setGrd", [
83544
+ `<benable>${input.enabled ? 1 : 0}</benable>`,
83545
+ `<timeout>${Math.round(input.timeoutSeconds)}</timeout>`,
83546
+ ...input.setPosition ? ["<needSetPos>1</needSetPos>"] : []
83547
+ ]);
83548
+ }
83549
+ function tag(xml, name) {
83550
+ const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml);
83551
+ return m === null ? null : (m[1] ?? "").trim();
83552
+ }
83553
+ function parsePtzGuardXml(xml) {
83554
+ if (!xml.includes("<PtzGuard")) return null;
83555
+ const enabled = tag(xml, "benable");
83556
+ const valid = tag(xml, "bvalid");
83557
+ const timeout = tag(xml, "timeout");
83558
+ if (enabled === null || valid === null || timeout === null) return null;
83559
+ const timeoutSeconds = Number.parseInt(timeout, 10);
83560
+ if (!Number.isFinite(timeoutSeconds)) return null;
83561
+ return {
83562
+ enabled: enabled === "1",
83563
+ valid: valid === "1",
83564
+ timeoutSeconds,
83565
+ mode: tag(xml, "mode") ?? "global",
83566
+ imageName: tag(xml, "imageName") ?? ""
83567
+ };
83568
+ }
83435
83569
  var emitter = new EventEmitter();
83436
83570
  var lastEventByCamera = /* @__PURE__ */ new Map();
83437
83571
  var MAX_GLOBAL_EVENTS = 300;
@@ -84644,8 +84778,8 @@ var buildFileInfoListStopXml = (params) => {
84644
84778
  </body>`;
84645
84779
  };
84646
84780
  var sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
84647
- var xmlDateTimePayload = (tag, d) => {
84648
- return `<${tag}><year>${d.getFullYear()}</year><month>${d.getMonth() + 1}</month><day>${d.getDate()}</day><hour>${d.getHours()}</hour><minute>${d.getMinutes()}</minute><second>${d.getSeconds()}</second></${tag}>`;
84781
+ var xmlDateTimePayload = (tag2, d) => {
84782
+ return `<${tag2}><year>${d.getFullYear()}</year><month>${d.getMonth() + 1}</month><day>${d.getDate()}</day><hour>${d.getHours()}</hour><minute>${d.getMinutes()}</minute><second>${d.getSeconds()}</second></${tag2}>`;
84649
84783
  };
84650
84784
  var buildFileInfoListOpenXml = (params) => {
84651
84785
  return `<?xml version="1.0" encoding="UTF-8" ?>
@@ -84833,10 +84967,10 @@ var isPlausibleStream = (s) => {
84833
84967
  return s.width > 0 && s.height > 0 && (s.frameRate > 0 || s.bitRate > 0);
84834
84968
  };
84835
84969
  var logDebugStreamBlock = (params) => {
84836
- const { logger, traceNativeStream, channel, tag, blockXml } = params;
84970
+ const { logger, traceNativeStream, channel, tag: tag2, blockXml } = params;
84837
84971
  if (!traceNativeStream) return;
84838
84972
  if (!blockXml) {
84839
- (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag}> missing`);
84973
+ (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag2}> missing`);
84840
84974
  return;
84841
84975
  }
84842
84976
  const raw = blockXml;
@@ -84863,7 +84997,7 @@ var logDebugStreamBlock = (params) => {
84863
84997
  const previewMax = 1400;
84864
84998
  const xmlPreview = raw.length <= previewMax ? raw : raw.slice(0, previewMax) + `
84865
84999
  ...truncated (+${raw.length - previewMax} chars)`;
84866
- (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag}> enabled=${isEnabled} plausible=${plausible} width=${width} height=${height} frame=${frameRate} bitRate=${bitRate} audio=${audio} videoEncType=${videoEncTypeText ?? "?"} rawFields=${JSON.stringify({
85000
+ (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag2}> enabled=${isEnabled} plausible=${plausible} width=${width} height=${height} frame=${frameRate} bitRate=${bitRate} audio=${audio} videoEncType=${videoEncTypeText ?? "?"} rawFields=${JSON.stringify({
84867
85001
  widthText,
84868
85002
  heightText,
84869
85003
  frameText,
@@ -84956,20 +85090,20 @@ var parseChannelStreamMetadataFromGetEncXml = (params) => {
84956
85090
  audioEnabled = audioEnabled && s.audio === 1;
84957
85091
  }
84958
85092
  }
84959
- for (const tag of [
85093
+ for (const tag2 of [
84960
85094
  "extStream",
84961
85095
  "thirdStream",
84962
85096
  "externStream",
84963
85097
  "extraStream"
84964
85098
  ]) {
84965
- const extMatch = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`));
85099
+ const extMatch = xml.match(new RegExp(`<${tag2}[^>]*>([\\s\\S]*?)<\\/${tag2}>`));
84966
85100
  if (!extMatch) continue;
84967
85101
  const extXml = extMatch[1] ?? "";
84968
85102
  logDebugStreamBlock({
84969
85103
  logger,
84970
85104
  traceNativeStream,
84971
85105
  channel,
84972
- tag,
85106
+ tag: tag2,
84973
85107
  blockXml: extXml
84974
85108
  });
84975
85109
  const s = buildStream({
@@ -86562,7 +86696,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86562
86696
  * @param logger - Optional logger for debug output
86563
86697
  * @returns The socket and a release function
86564
86698
  */
86565
- async acquirePooledSocket(tag, logger) {
86699
+ async acquirePooledSocket(tag2, logger) {
86566
86700
  const log = logger ?? this.logger;
86567
86701
  const now = Date.now();
86568
86702
  const cooldownEntry = this.socketPoolCooldowns.get(this.host);
@@ -86573,12 +86707,12 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86573
86707
  } else if (now < cooldownEntry.cooldownUntil) {
86574
86708
  const remainingMs = cooldownEntry.cooldownUntil - now;
86575
86709
  const reason = this.lastD2cDiscAtMs > 0 && now - this.lastD2cDiscAtMs < 12e4 ? "D2C_DISC (camera sleeping)" : "repeated login failures";
86576
- const error = /* @__PURE__ */ new Error(`[SocketPool] Host ${this.host} is in cooldown for ${Math.ceil(remainingMs / 1e3)}s due to ${reason}. tag=${tag}`);
86710
+ const error = /* @__PURE__ */ new Error(`[SocketPool] Host ${this.host} is in cooldown for ${Math.ceil(remainingMs / 1e3)}s due to ${reason}. tag=${tag2}`);
86577
86711
  log?.debug?.(error.message);
86578
86712
  throw error;
86579
86713
  }
86580
86714
  }
86581
- const existing = this.socketPool.get(tag);
86715
+ const existing = this.socketPool.get(tag2);
86582
86716
  if (existing) {
86583
86717
  if (existing.idleCloseTimer) {
86584
86718
  clearTimeout(existing.idleCloseTimer);
@@ -86588,35 +86722,35 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86588
86722
  const client2 = await existing.pendingPromise;
86589
86723
  existing.refCount++;
86590
86724
  existing.lastUsedAt = Date.now();
86591
- log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${tag} (refCount=${existing.refCount})`);
86725
+ log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${tag2} (refCount=${existing.refCount})`);
86592
86726
  return {
86593
86727
  client: client2,
86594
- release: () => this.releasePooledSocket(tag, logger)
86728
+ release: () => this.releasePooledSocket(tag2, logger)
86595
86729
  };
86596
86730
  }
86597
86731
  if (existing.refCount === 0) {
86598
86732
  existing.refCount = 1;
86599
86733
  existing.lastUsedAt = Date.now();
86600
- log?.debug?.(`[SocketPool] Reusing idle socket for tag=${tag}`);
86734
+ log?.debug?.(`[SocketPool] Reusing idle socket for tag=${tag2}`);
86601
86735
  try {
86602
86736
  if (!existing.client.loggedIn) await existing.client.login();
86603
86737
  } catch {}
86604
86738
  if (existing.client.loggedIn) return {
86605
86739
  client: existing.client,
86606
- release: () => this.releasePooledSocket(tag, logger)
86740
+ release: () => this.releasePooledSocket(tag2, logger)
86607
86741
  };
86608
- } else if (tag.startsWith("replay:")) log?.debug?.(`[SocketPool] Preempting active replay socket for tag=${tag}`);
86742
+ } else if (tag2.startsWith("replay:")) log?.debug?.(`[SocketPool] Preempting active replay socket for tag=${tag2}`);
86609
86743
  else {
86610
86744
  existing.refCount++;
86611
86745
  existing.lastUsedAt = Date.now();
86612
- log?.debug?.(`[SocketPool] Reusing active socket for tag=${tag} (refCount=${existing.refCount})`);
86746
+ log?.debug?.(`[SocketPool] Reusing active socket for tag=${tag2} (refCount=${existing.refCount})`);
86613
86747
  return {
86614
86748
  client: existing.client,
86615
- release: () => this.releasePooledSocket(tag, logger)
86749
+ release: () => this.releasePooledSocket(tag2, logger)
86616
86750
  };
86617
86751
  }
86618
- log?.debug?.(`[SocketPool] Closing existing socket for tag=${tag} (recreating)`);
86619
- this.socketPool.delete(tag);
86752
+ log?.debug?.(`[SocketPool] Closing existing socket for tag=${tag2} (recreating)`);
86753
+ this.socketPool.delete(tag2);
86620
86754
  if (existing.generalPermitRelease) {
86621
86755
  try {
86622
86756
  existing.generalPermitRelease();
@@ -86629,10 +86763,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86629
86763
  skipLogout: true
86630
86764
  });
86631
86765
  } catch (e) {
86632
- log?.warn?.(`[SocketPool] Error closing old socket for tag=${tag}: ${e}`);
86766
+ log?.warn?.(`[SocketPool] Error closing old socket for tag=${tag2}: ${e}`);
86633
86767
  }
86634
86768
  }
86635
- log?.log?.(`[SocketPool] Creating new socket for tag=${tag}`);
86769
+ log?.log?.(`[SocketPool] Creating new socket for tag=${tag2}`);
86636
86770
  const entry = {
86637
86771
  client: void 0,
86638
86772
  refCount: 0,
@@ -86649,7 +86783,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86649
86783
  } : this.clientOptions);
86650
86784
  this.attachD2cDiscListener(newClient);
86651
86785
  newClient.on("error", (err) => {
86652
- log?.debug?.(`[SocketPool] tag=${tag} client error: ${err?.message ?? err}`);
86786
+ log?.debug?.(`[SocketPool] tag=${tag2} client error: ${err?.message ?? err}`);
86653
86787
  });
86654
86788
  await newClient.login();
86655
86789
  const existingCooldown = this.socketPoolCooldowns.get(this.host);
@@ -86661,10 +86795,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86661
86795
  entry.refCount = 1;
86662
86796
  entry.lastUsedAt = Date.now();
86663
86797
  delete entry.pendingPromise;
86664
- log?.log?.(`[SocketPool] Socket connected for tag=${tag}`);
86665
- if (tag !== "general") try {
86798
+ log?.log?.(`[SocketPool] Socket connected for tag=${tag2}`);
86799
+ if (tag2 !== "general") try {
86666
86800
  const generalEntry = this.socketPool.get("general");
86667
- if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${tag}`);
86801
+ if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${tag2}`);
86668
86802
  } catch {}
86669
86803
  if (this.sessionGuardEnabled) this.maybeRebootOnTooManySessions();
86670
86804
  return newClient;
@@ -86675,21 +86809,21 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86675
86809
  if (failureCount >= _ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD) {
86676
86810
  const backoffMs = Math.min(_ReolinkBaichuanApi.SOCKET_POOL_BASE_COOLDOWN_MS * Math.pow(2, failureCount - _ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD), _ReolinkBaichuanApi.SOCKET_POOL_MAX_COOLDOWN_MS);
86677
86811
  cooldownUntil = now2 + backoffMs;
86678
- log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}). Entering cooldown for ${Math.ceil(backoffMs / 1e3)}s. tag=${tag}`);
86679
- } else log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}/${_ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD} before cooldown). tag=${tag}`);
86812
+ log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}). Entering cooldown for ${Math.ceil(backoffMs / 1e3)}s. tag=${tag2}`);
86813
+ } else log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}/${_ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD} before cooldown). tag=${tag2}`);
86680
86814
  this.socketPoolCooldowns.set(this.host, {
86681
86815
  failureCount,
86682
86816
  lastFailureAt: now2,
86683
86817
  cooldownUntil
86684
86818
  });
86685
- this.socketPool.delete(tag);
86819
+ this.socketPool.delete(tag2);
86686
86820
  throw loginError;
86687
86821
  }
86688
86822
  })();
86689
- this.socketPool.set(tag, entry);
86823
+ this.socketPool.set(tag2, entry);
86690
86824
  return {
86691
86825
  client: await entry.pendingPromise,
86692
- release: () => this.releasePooledSocket(tag, logger)
86826
+ release: () => this.releasePooledSocket(tag2, logger)
86693
86827
  };
86694
86828
  }
86695
86829
  /**
@@ -86697,31 +86831,31 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86697
86831
  * For shared sockets (general, streaming), just decrements refCount.
86698
86832
  * For replay sockets, schedules idle close.
86699
86833
  */
86700
- async releasePooledSocket(tag, logger) {
86834
+ async releasePooledSocket(tag2, logger) {
86701
86835
  const log = logger ?? this.logger;
86702
- const entry = this.socketPool.get(tag);
86836
+ const entry = this.socketPool.get(tag2);
86703
86837
  if (!entry) return;
86704
86838
  entry.refCount = Math.max(0, entry.refCount - 1);
86705
86839
  entry.lastUsedAt = Date.now();
86706
- log?.debug?.(`[SocketPool] Released socket for tag=${tag} (refCount=${entry.refCount})`);
86840
+ log?.debug?.(`[SocketPool] Released socket for tag=${tag2} (refCount=${entry.refCount})`);
86707
86841
  if (entry.refCount > 0) return;
86708
- const isReplayTag = tag.startsWith("replay:");
86709
- const isStreamingTag = tag.startsWith("streaming:");
86710
- if (tag === "general") return;
86842
+ const isReplayTag = tag2.startsWith("replay:");
86843
+ const isStreamingTag = tag2.startsWith("streaming:");
86844
+ if (tag2 === "general") return;
86711
86845
  if (isStreamingTag) {
86712
86846
  if (entry.idleCloseTimer) return;
86713
86847
  entry.idleCloseTimer = setTimeout(async () => {
86714
- const current = this.socketPool.get(tag);
86848
+ const current = this.socketPool.get(tag2);
86715
86849
  if (!current) return;
86716
86850
  if (current.refCount > 0) return;
86717
- this.socketPool.delete(tag);
86851
+ this.socketPool.delete(tag2);
86718
86852
  if (current.generalPermitRelease) {
86719
86853
  try {
86720
86854
  current.generalPermitRelease();
86721
86855
  } catch {}
86722
86856
  current.generalPermitRelease = void 0;
86723
86857
  }
86724
- log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${tag}`);
86858
+ log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${tag2}`);
86725
86859
  try {
86726
86860
  await current.client.close({
86727
86861
  reason: "streaming idle close",
@@ -86734,11 +86868,11 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86734
86868
  if (isReplayTag) {
86735
86869
  if (entry.idleCloseTimer) return;
86736
86870
  entry.idleCloseTimer = setTimeout(async () => {
86737
- const current = this.socketPool.get(tag);
86871
+ const current = this.socketPool.get(tag2);
86738
86872
  if (!current) return;
86739
86873
  if (current.refCount > 0) return;
86740
- this.socketPool.delete(tag);
86741
- log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${tag} (keepalive expired)`);
86874
+ this.socketPool.delete(tag2);
86875
+ log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${tag2} (keepalive expired)`);
86742
86876
  try {
86743
86877
  await current.client.close({
86744
86878
  reason: "replay idle keepalive expired",
@@ -86748,24 +86882,24 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86748
86882
  }, _ReolinkBaichuanApi.SOCKET_POOL_KEEPALIVE_MS);
86749
86883
  return;
86750
86884
  }
86751
- this.socketPool.delete(tag);
86885
+ this.socketPool.delete(tag2);
86752
86886
  try {
86753
86887
  await entry.client.close({
86754
86888
  reason: "socket pool release",
86755
86889
  skipLogout: true
86756
86890
  });
86757
- log?.log?.(`[SocketPool] Closed socket for tag=${tag}`);
86891
+ log?.log?.(`[SocketPool] Closed socket for tag=${tag2}`);
86758
86892
  } catch (e) {
86759
- log?.warn?.(`[SocketPool] Error closing socket for tag=${tag}: ${e}`);
86893
+ log?.warn?.(`[SocketPool] Error closing socket for tag=${tag2}: ${e}`);
86760
86894
  }
86761
86895
  }
86762
86896
  /**
86763
86897
  * Force-close a socket by tag.
86764
86898
  * Used to preempt existing connections before acquiring a new one.
86765
86899
  */
86766
- async forceClosePooledSocket(tag, logger) {
86900
+ async forceClosePooledSocket(tag2, logger) {
86767
86901
  const log = logger ?? this.logger;
86768
- const entry = this.socketPool.get(tag);
86902
+ const entry = this.socketPool.get(tag2);
86769
86903
  if (!entry) return false;
86770
86904
  if (entry.idleCloseTimer) {
86771
86905
  clearTimeout(entry.idleCloseTimer);
@@ -86777,16 +86911,16 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86777
86911
  } catch {}
86778
86912
  entry.generalPermitRelease = void 0;
86779
86913
  }
86780
- log?.debug?.(`[SocketPool] Force-closing socket for tag=${tag}`);
86781
- this.socketPool.delete(tag);
86914
+ log?.debug?.(`[SocketPool] Force-closing socket for tag=${tag2}`);
86915
+ this.socketPool.delete(tag2);
86782
86916
  try {
86783
86917
  await entry.client.close({
86784
86918
  reason: "force closed",
86785
86919
  skipLogout: true
86786
86920
  });
86787
- log?.log?.(`[SocketPool] Force-closed socket for tag=${tag}`);
86921
+ log?.log?.(`[SocketPool] Force-closed socket for tag=${tag2}`);
86788
86922
  } catch (e) {
86789
- log?.warn?.(`[SocketPool] Error during force-close for tag=${tag}: ${e}`);
86923
+ log?.warn?.(`[SocketPool] Error during force-close for tag=${tag2}: ${e}`);
86790
86924
  }
86791
86925
  return true;
86792
86926
  }
@@ -86796,7 +86930,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86796
86930
  async cleanupSocketPool() {
86797
86931
  const entries = Array.from(this.socketPool.entries());
86798
86932
  this.socketPool.clear();
86799
- await Promise.allSettled(entries.map(async ([tag, entry]) => {
86933
+ await Promise.allSettled(entries.map(async ([tag2, entry]) => {
86800
86934
  try {
86801
86935
  if (entry.idleCloseTimer) clearTimeout(entry.idleCloseTimer);
86802
86936
  if (entry.generalPermitRelease) {
@@ -86805,7 +86939,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86805
86939
  } catch {}
86806
86940
  entry.generalPermitRelease = void 0;
86807
86941
  }
86808
- this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${tag}`);
86942
+ this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${tag2}`);
86809
86943
  await entry.client.close({
86810
86944
  reason: "API cleanup",
86811
86945
  skipLogout: true
@@ -86838,17 +86972,17 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86838
86972
  * ```
86839
86973
  */
86840
86974
  async createDedicatedSession(sessionKey, logger) {
86841
- const tag = this.resolveSocketTag(sessionKey);
86842
- (logger ?? this.logger)?.debug?.(`[SocketPool] createDedicatedSession sessionKey=${sessionKey} \u2192 tag=${tag}`);
86843
- return await this.acquirePooledSocket(tag, logger);
86975
+ const tag2 = this.resolveSocketTag(sessionKey);
86976
+ (logger ?? this.logger)?.debug?.(`[SocketPool] createDedicatedSession sessionKey=${sessionKey} \u2192 tag=${tag2}`);
86977
+ return await this.acquirePooledSocket(tag2, logger);
86844
86978
  }
86845
86979
  /**
86846
86980
  * @deprecated Use forceClosePooledSocket via createDedicatedSession instead.
86847
86981
  * Force-close a dedicated client if it exists.
86848
86982
  */
86849
86983
  async forceCloseDedicatedClient(sessionKey, logger) {
86850
- const tag = this.resolveSocketTag(sessionKey);
86851
- return await this.forceClosePooledSocket(tag, logger);
86984
+ const tag2 = this.resolveSocketTag(sessionKey);
86985
+ return await this.forceClosePooledSocket(tag2, logger);
86852
86986
  }
86853
86987
  /**
86854
86988
  * @deprecated Cleanup handled by cleanupSocketPool now.
@@ -86863,8 +86997,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86863
86997
  const debugCfg = this.client.getDebugConfig?.();
86864
86998
  if (debugCfg) {
86865
86999
  const sid = this.client.getSocketSessionId?.();
86866
- const tag = sid ? `ReolinkSimpleEvent sid=${sid}` : "ReolinkSimpleEvent";
86867
- eventTraceLog(debugCfg, this.logger, tag, `dispatch type=${evt.type} channel=${evt.channel} timestamp=${evt.timestamp}`);
87000
+ const tag2 = sid ? `ReolinkSimpleEvent sid=${sid}` : "ReolinkSimpleEvent";
87001
+ eventTraceLog(debugCfg, this.logger, tag2, `dispatch type=${evt.type} channel=${evt.channel} timestamp=${evt.timestamp}`);
86868
87002
  }
86869
87003
  for (const cb of this.simpleEventListeners) try {
86870
87004
  Promise.resolve(cb(evt)).catch((e) => {
@@ -87462,7 +87596,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
87462
87596
  return;
87463
87597
  }
87464
87598
  entry.startInFlight = (async () => {
87465
- const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-PBJL3EB5-D-etWPiW.mjs");
87599
+ const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-2M4UO7MB-CB-tIHMA.mjs");
87466
87600
  const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
87467
87601
  const dedicated = await this.createDedicatedSession(sessionKey);
87468
87602
  const stream = new BaichuanVideoStream2({
@@ -88029,8 +88163,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88029
88163
  const idleTimeoutMs = options?.idleTimeoutMs ?? 3e4;
88030
88164
  const sessionKey = `talk:${options?.deviceId ?? "unknown"}:ch${channel}:${Date.now()}`;
88031
88165
  logger?.info?.(`[DedicatedTalk] Creating session: ${sessionKey} (idleTimeout=${idleTimeoutMs}ms)`);
88032
- const tag = this.resolveSocketTag(sessionKey);
88033
- const { client: dedicatedClient, release } = await this.acquirePooledSocket(tag, logger);
88166
+ const tag2 = this.resolveSocketTag(sessionKey);
88167
+ const { client: dedicatedClient, release } = await this.acquirePooledSocket(tag2, logger);
88034
88168
  const summary = this.getSocketPoolSummary();
88035
88169
  logger?.info?.(`[DedicatedTalk] Session created [sessions: ${summary.count} active${summary.count > 0 ? ` (${summary.tags.join(", ")})` : ""}]`);
88036
88170
  try {
@@ -88143,8 +88277,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88143
88277
  }
88144
88278
  /** SetNetPort via Baichuan: cmd_id 36 (enable/disable rtsp/rtmp/onvif/http/https) */
88145
88279
  async setPortEnabled(params) {
88146
- const tag = `${params.port[0].toUpperCase()}${params.port.slice(1)}Port`;
88147
- const xml = `<?xml version="1.0" encoding="UTF-8" ?><body><${tag} version="1.1"><enable>${params.enable ? 1 : 0}</enable></${tag}></body>`;
88280
+ const tag2 = `${params.port[0].toUpperCase()}${params.port.slice(1)}Port`;
88281
+ const xml = `<?xml version="1.0" encoding="UTF-8" ?><body><${tag2} version="1.1"><enable>${params.enable ? 1 : 0}</enable></${tag2}></body>`;
88148
88282
  await this.sendXml({
88149
88283
  cmdId: 36,
88150
88284
  payloadXml: xml
@@ -88175,13 +88309,13 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88175
88309
  */
88176
88310
  async setPortConfig(patch) {
88177
88311
  const blocks = [];
88178
- const append = (tag, portField, cfg) => {
88312
+ const append = (tag2, portField, cfg) => {
88179
88313
  if (!cfg) return;
88180
88314
  if (cfg.port === void 0 && cfg.enable === void 0) return;
88181
88315
  const inner = [];
88182
88316
  if (cfg.port !== void 0) inner.push(`<${portField}>${cfg.port}</${portField}>`);
88183
88317
  if (cfg.enable !== void 0) inner.push(`<enable>${cfg.enable ? 1 : 0}</enable>`);
88184
- blocks.push(`<${tag} version="1.1">${inner.join("")}</${tag}>`);
88318
+ blocks.push(`<${tag2} version="1.1">${inner.join("")}</${tag2}>`);
88185
88319
  };
88186
88320
  append("ServerPort", "serverPort", patch.server);
88187
88321
  append("HttpPort", "httpPort", patch.http);
@@ -88695,8 +88829,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88695
88829
  ];
88696
88830
  const current = await this.getEncXml(ch);
88697
88831
  let updated = null;
88698
- for (const tag of candidateTags) {
88699
- const sectionRe = new RegExp(`(<${tag}[^>]*>[\\s\\S]*?<videoEncType>)(\\d+)(</videoEncType>)`);
88832
+ for (const tag2 of candidateTags) {
88833
+ const sectionRe = new RegExp(`(<${tag2}[^>]*>[\\s\\S]*?<videoEncType>)(\\d+)(</videoEncType>)`);
88700
88834
  if (!sectionRe.test(current)) continue;
88701
88835
  const next = current.replace(sectionRe, `$1${desired}$3`);
88702
88836
  if (next !== current) {
@@ -89226,9 +89360,9 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
89226
89360
  const streamType = params.streamType;
89227
89361
  const logger = params.logger ?? this.logger;
89228
89362
  const sessionKey = params.deviceId ? `replay:${params.deviceId}:ch${channel}` : `replay:standalone:ch${channel}:${Date.now()}`;
89229
- const tag = this.resolveSocketTag(sessionKey);
89230
- logger?.debug?.(`[startRecordingReplayStreamStandalone] sessionKey=${sessionKey} -> tag=${tag}`);
89231
- const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag, logger);
89363
+ const tag2 = this.resolveSocketTag(sessionKey);
89364
+ logger?.debug?.(`[startRecordingReplayStreamStandalone] sessionKey=${sessionKey} -> tag=${tag2}`);
89365
+ const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
89232
89366
  const uid = await this.ensureUidForRecordings(channel, void 0);
89233
89367
  const payloadXml = buildFileInfoListReplayByNameXml({
89234
89368
  channel,
@@ -89331,8 +89465,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
89331
89465
  const streamType = params.streamType;
89332
89466
  const logger = params.logger ?? this.logger;
89333
89467
  const sessionKey = params.deviceId ? `replay:${params.deviceId}:ch${channel}` : `replay:nvr:ch${channel}:${Date.now()}`;
89334
- const tag = this.resolveSocketTag(sessionKey);
89335
- const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag, logger);
89468
+ const tag2 = this.resolveSocketTag(sessionKey);
89469
+ const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
89336
89470
  let uid;
89337
89471
  try {
89338
89472
  uid = await this.ensureUidForRecordings(channel, void 0);
@@ -91559,6 +91693,73 @@ ${stderr}`));
91559
91693
  return result;
91560
91694
  }
91561
91695
  /**
91696
+ * Read the PTZ guard point ("monitoring point" in the app).
91697
+ *
91698
+ * cmd_id: 332
91699
+ *
91700
+ * Returns `null` when the camera has no readable guard configuration — never
91701
+ * a fabricated "none", because that answer is what a consumer uses to decide
91702
+ * whether to move the head.
91703
+ */
91704
+ async getPtzGuard(channel) {
91705
+ const ch = this.normalizeChannel(channel);
91706
+ return parsePtzGuardXml(await this.sendXml({
91707
+ cmdId: 332,
91708
+ channel: ch,
91709
+ channelIdOverride: ch,
91710
+ extensionXml: buildPtzGuardExtensionXml(ch, "read"),
91711
+ messageClass: BC_CLASS_MODERN_24,
91712
+ streamType: 0
91713
+ }));
91714
+ }
91715
+ /**
91716
+ * Configure the PTZ guard point.
91717
+ *
91718
+ * cmd_id: 331 with `<command>setGrd</command>`
91719
+ *
91720
+ * `setPosition` pins the guard point to the head's CURRENT position. Leave it
91721
+ * false when only changing the timeout or the enable flag: re-sending it
91722
+ * would silently move a point the operator had already placed.
91723
+ */
91724
+ async setPtzGuard(options, channel) {
91725
+ const ch = this.normalizeChannel(channel);
91726
+ await this.sendXml({
91727
+ cmdId: 331,
91728
+ channel: ch,
91729
+ channelIdOverride: ch,
91730
+ extensionXml: buildPtzGuardExtensionXml(ch, "write"),
91731
+ payloadXml: buildPtzGuardSetXml({
91732
+ channelId: ch,
91733
+ enabled: options.enabled,
91734
+ timeoutSeconds: options.timeoutSeconds,
91735
+ setPosition: options.setPosition === true
91736
+ }),
91737
+ messageClass: BC_CLASS_MODERN_24,
91738
+ streamType: 0
91739
+ });
91740
+ }
91741
+ /**
91742
+ * Send the head to the guard point NOW.
91743
+ *
91744
+ * cmd_id: 331 with `<command>toGrd</command>`
91745
+ *
91746
+ * This is the closest thing Baichuan has to a "go home": the guard point is
91747
+ * an operator-placed position, unlike preset slot 0 which merely happens to
91748
+ * be first.
91749
+ */
91750
+ async goToPtzGuard(channel) {
91751
+ const ch = this.normalizeChannel(channel);
91752
+ await this.sendXml({
91753
+ cmdId: 331,
91754
+ channel: ch,
91755
+ channelIdOverride: ch,
91756
+ extensionXml: buildPtzGuardExtensionXml(ch, "write"),
91757
+ payloadXml: buildPtzGuardGoXml(ch),
91758
+ messageClass: BC_CLASS_MODERN_24,
91759
+ streamType: 0
91760
+ });
91761
+ }
91762
+ /**
91562
91763
  * Read zoom/focus min/max/current positions.
91563
91764
  * cmd_id: 294 (MSG_ID_GET_ZOOM_FOCUS)
91564
91765
  */
@@ -91651,10 +91852,10 @@ ${stderr}`));
91651
91852
  notifyD2cDisc() {
91652
91853
  const now = Date.now();
91653
91854
  this.lastD2cDiscAtMs = now;
91654
- const streamingTags = Array.from(this.socketPool.keys()).filter((tag) => tag.startsWith("streaming:"));
91855
+ const streamingTags = Array.from(this.socketPool.keys()).filter((tag2) => tag2.startsWith("streaming:"));
91655
91856
  if (streamingTags.length > 0) {
91656
91857
  this.logger?.log?.(`[D2C_DISC] Force-closing ${streamingTags.length} streaming socket(s): ${streamingTags.join(", ")}`);
91657
- for (const tag of streamingTags) this.forceClosePooledSocket(tag, this.logger).catch(() => {});
91858
+ for (const tag2 of streamingTags) this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
91658
91859
  }
91659
91860
  const immediateCooldownUntil = now + _ReolinkBaichuanApi.D2C_DISC_IMMEDIATE_COOLDOWN_MS;
91660
91861
  const existing = this.socketPoolCooldowns.get(this.host);
@@ -91687,15 +91888,15 @@ ${stderr}`));
91687
91888
  * Returns undefined if the client is not in the pool (e.g. it's the general socket used directly).
91688
91889
  */
91689
91890
  findSocketTagForClient(client) {
91690
- for (const [tag, entry] of this.socketPool) if (entry.client === client) return tag;
91891
+ for (const [tag2, entry] of this.socketPool) if (entry.client === client) return tag2;
91691
91892
  }
91692
91893
  /**
91693
91894
  * Reset the consecutive stream-start timeout counter for a streaming socket.
91694
91895
  * Called on successful stream start.
91695
91896
  */
91696
91897
  resetStreamTimeoutCounter(client) {
91697
- const tag = this.findSocketTagForClient(client);
91698
- if (tag) this.consecutiveStreamTimeouts.delete(tag);
91898
+ const tag2 = this.findSocketTagForClient(client);
91899
+ if (tag2) this.consecutiveStreamTimeouts.delete(tag2);
91699
91900
  }
91700
91901
  /**
91701
91902
  * Track a stream-start timeout on a streaming socket.
@@ -91703,14 +91904,14 @@ ${stderr}`));
91703
91904
  * socket so the next attempt creates a fresh connection.
91704
91905
  */
91705
91906
  trackStreamTimeout(client) {
91706
- const tag = this.findSocketTagForClient(client);
91707
- if (!tag || !tag.startsWith("streaming:")) return;
91708
- const count = (this.consecutiveStreamTimeouts.get(tag) ?? 0) + 1;
91709
- this.consecutiveStreamTimeouts.set(tag, count);
91907
+ const tag2 = this.findSocketTagForClient(client);
91908
+ if (!tag2 || !tag2.startsWith("streaming:")) return;
91909
+ const count = (this.consecutiveStreamTimeouts.get(tag2) ?? 0) + 1;
91910
+ this.consecutiveStreamTimeouts.set(tag2, count);
91710
91911
  if (count >= _ReolinkBaichuanApi.MAX_CONSECUTIVE_STREAM_TIMEOUTS) {
91711
- this.logger?.warn?.(`[SocketPool] ${count} consecutive stream timeouts on tag=${tag}, force-closing socket`);
91712
- this.consecutiveStreamTimeouts.delete(tag);
91713
- this.forceClosePooledSocket(tag, this.logger).catch(() => {});
91912
+ this.logger?.warn?.(`[SocketPool] ${count} consecutive stream timeouts on tag=${tag2}, force-closing socket`);
91913
+ this.consecutiveStreamTimeouts.delete(tag2);
91914
+ this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
91714
91915
  }
91715
91916
  }
91716
91917
  /**
@@ -92577,8 +92778,20 @@ ${xml}`);
92577
92778
  const support = supportResult.status === "fulfilled" ? supportResult.value : void 0;
92578
92779
  const abilities = abilitiesResult.status === "fulfilled" ? abilitiesResult.value : void 0;
92579
92780
  const supportItem = getSupportItemForChannel(support, ch);
92781
+ let model;
92782
+ try {
92783
+ const info = await this.getInfo(void 0, { timeoutMs: 5e3 });
92784
+ model = typeof info?.type === "string" ? info.type : void 0;
92785
+ } catch (e) {
92786
+ this.logger.debug("[ReolinkBaichuanApi] getDeviceCapabilities: getInfo(type) failed", {
92787
+ host: this.host,
92788
+ channel: ch,
92789
+ err: e instanceof Error ? e.message : String(e)
92790
+ });
92791
+ }
92580
92792
  const capabilities = computeDeviceCapabilities({
92581
92793
  channel: ch,
92794
+ ...model != null && { model },
92582
92795
  ...support != null && { support },
92583
92796
  ...abilities != null && { abilities }
92584
92797
  });
@@ -93347,7 +93560,7 @@ ${xml}`);
93347
93560
  * @returns Test results for all stream types and profiles
93348
93561
  */
93349
93562
  async testChannelStreams(channel, logger) {
93350
- const { testChannelStreams } = await import("./DiagnosticsTools-TID5M22B-9NV95vRN.mjs");
93563
+ const { testChannelStreams } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
93351
93564
  return await testChannelStreams({
93352
93565
  api: this,
93353
93566
  channel: this.normalizeChannel(channel),
@@ -93363,7 +93576,7 @@ ${xml}`);
93363
93576
  * @returns Complete diagnostics for all channels and streams
93364
93577
  */
93365
93578
  async collectMultifocalDiagnostics(logger) {
93366
- const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-TID5M22B-9NV95vRN.mjs");
93579
+ const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
93367
93580
  return await collectMultifocalDiagnostics({
93368
93581
  api: this,
93369
93582
  logger
@@ -150155,15 +150368,39 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
150155
150368
  */
150156
150369
  async resolveHomePreset() {
150157
150370
  const chosen = this.config.get("homePresetId") ?? "";
150158
- if (chosen === "") return {
150371
+ if (chosen !== "") return {
150372
+ presetId: chosen,
150373
+ source: "operator"
150374
+ };
150375
+ if ((await this.readGuardStatus())?.valid === true) return {
150159
150376
  presetId: null,
150160
- source: "none"
150377
+ source: "native"
150161
150378
  };
150162
150379
  return {
150163
- presetId: chosen,
150164
- source: "operator"
150380
+ presetId: null,
150381
+ source: "none"
150165
150382
  };
150166
150383
  }
150384
+ /**
150385
+ * The camera's guard-point configuration, or `null` when it cannot be read.
150386
+ *
150387
+ * Never a fabricated "no guard configured": that answer decides whether
150388
+ * `goHome` moves the head, and an unreadable camera is not evidence that no
150389
+ * guard point exists (D393).
150390
+ */
150391
+ async readGuardStatus() {
150392
+ try {
150393
+ const api = await this.ensureApi();
150394
+ const channel = this.getChannel();
150395
+ return await api.getPtzGuard(channel);
150396
+ } catch (err) {
150397
+ this.ctx.logger.warn("reolink guard point unreadable — goHome will fall back", {
150398
+ tags: { deviceId: this.id },
150399
+ meta: { error: err instanceof Error ? err.message : String(err) }
150400
+ });
150401
+ return null;
150402
+ }
150403
+ }
150167
150404
  getChannel() {
150168
150405
  const ch = this.config.get("channel");
150169
150406
  if (typeof ch === "number" && ch >= 0) return ch;
@@ -153616,7 +153853,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
153616
153853
  goHome: async ({ deviceId }) => {
153617
153854
  if (deviceId !== this.id) return;
153618
153855
  const home = await this.resolveHomePreset();
153619
- if (home.source === "none" || home.presetId === null) throw new Error("No home preset configured for this camera — set one in the PTZ settings");
153856
+ if (home.source === "native") {
153857
+ await (await this.ensureApi()).goToPtzGuard(this.getChannel());
153858
+ return;
153859
+ }
153860
+ if (home.source === "none" || home.presetId === null) throw new Error("No home preset configured for this camera, and it has no guard point set — set one in the PTZ settings, or place a guard point on the camera");
153620
153861
  const id = Number(home.presetId);
153621
153862
  if (!Number.isFinite(id)) throw new Error(`Configured home preset is not a Baichuan id: ${home.presetId}`);
153622
153863
  const api = await this.ensureApi();
@@ -153630,6 +153871,34 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
153630
153871
  };
153631
153872
  return this.resolveHomePreset();
153632
153873
  },
153874
+ captureHomeHere: async ({ deviceId }) => {
153875
+ if (deviceId !== this.id) return;
153876
+ const current = await this.readGuardStatus();
153877
+ const api = await this.ensureApi();
153878
+ const channel = this.getChannel();
153879
+ await api.setPtzGuard({
153880
+ enabled: current?.enabled ?? false,
153881
+ timeoutSeconds: current?.timeoutSeconds ?? 60,
153882
+ setPosition: true
153883
+ }, channel);
153884
+ this.ctx.logger.info("reolink: guard point pinned to the current position", { tags: { deviceId: this.id } });
153885
+ },
153886
+ getHomeReturnSeconds: async ({ deviceId }) => {
153887
+ if (deviceId !== this.id) return null;
153888
+ const guard = await this.readGuardStatus();
153889
+ return guard === null ? null : guard.timeoutSeconds;
153890
+ },
153891
+ setHomeReturnSeconds: async ({ deviceId, seconds }) => {
153892
+ if (deviceId !== this.id) return;
153893
+ const current = await this.readGuardStatus();
153894
+ const api = await this.ensureApi();
153895
+ const channel = this.getChannel();
153896
+ await api.setPtzGuard({
153897
+ enabled: current?.enabled ?? true,
153898
+ timeoutSeconds: seconds,
153899
+ setPosition: false
153900
+ }, channel);
153901
+ },
153633
153902
  setHomePreset: async ({ deviceId, presetId }) => {
153634
153903
  if (deviceId !== this.id) return;
153635
153904
  await this.config.setAll({ homePresetId: presetId ?? "" });