@camstack/addon-provider-reolink 1.2.139 → 1.2.141

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-Dk-BdnBf.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).
@@ -31815,6 +31815,26 @@ var PtzHomePresetSchema = object({
31815
31815
  "none"
31816
31816
  ])
31817
31817
  });
31818
+ /**
31819
+ * The camera's own idle-return behaviour: whether it goes home by itself, and
31820
+ * after how long.
31821
+ *
31822
+ * ONE shape, not two scalars, because on the camera they are ONE fact —
31823
+ * Reolink's guard point carries `benable` and `timeout` in the same element,
31824
+ * written by the same command. Reading them apart means two round-trips that
31825
+ * can disagree.
31826
+ *
31827
+ * `enabled` and `seconds` are INDEPENDENT: a camera can hold a 68 s delay with
31828
+ * the behaviour switched off, which is exactly what the vendor app leaves when
31829
+ * you turn the guard point off without clearing it. The first version of this
31830
+ * cap reported only the delay, so that state was invisible — a camera could be
31831
+ * configured to return after 68 seconds with no way to say whether it should
31832
+ * return at all.
31833
+ */
31834
+ var PtzHomeReturnSchema = object({
31835
+ enabled: boolean(),
31836
+ seconds: number().int()
31837
+ });
31818
31838
  var ptzCapability = {
31819
31839
  name: "ptz",
31820
31840
  scope: "device",
@@ -31874,6 +31894,54 @@ var ptzCapability = {
31874
31894
  auth: "admin"
31875
31895
  }),
31876
31896
  /**
31897
+ * Make WHERE THE HEAD IS POINTING RIGHT NOW this camera's home.
31898
+ *
31899
+ * `setHomePreset` takes a preset id, and a preset id is the wrong shape for
31900
+ * the most natural thing an operator does: aim the camera, then say "here".
31901
+ * It is also the only shape a camera whose home is NOT a preset can accept
31902
+ * -- Reolink's home is a guard point, a stored position with no id at all,
31903
+ * and hiding the control for that case (as the UI briefly did) left the one
31904
+ * vendor with a native home unable to set it.
31905
+ *
31906
+ * Each provider does it its own way:
31907
+ * reolink `setGrd` with `needSetPos`, pinning the guard point here
31908
+ * hikvision / amcrest save a preset, then pin it as home
31909
+ * onvif REFUSES -- its home is the PTZ origin and cannot be moved
31910
+ *
31911
+ * A provider that cannot honour it throws rather than silently doing
31912
+ * nothing: an operator who pressed "set home here" and saw no error would
31913
+ * believe it took.
31914
+ */
31915
+ captureHomeHere: method(object({ deviceId: number() }), _void(), {
31916
+ kind: "mutation",
31917
+ auth: "admin"
31918
+ }),
31919
+ /**
31920
+ * Whether the camera returns home on its own when left idle, and after how
31921
+ * long. `null` when it has no such behaviour at all.
31922
+ *
31923
+ * Reolink's guard point carries one (`timeout`, freely settable in
31924
+ * seconds). It is a real function of the camera that we did not expose at
31925
+ * all, and it belongs next to the home it governs rather than in a vendor
31926
+ * settings page nobody associates with Home.
31927
+ */
31928
+ getHomeReturn: method(object({ deviceId: number() }), PtzHomeReturnSchema.nullable()),
31929
+ /**
31930
+ * Set both together. Refused by a camera with no idle-return behaviour.
31931
+ *
31932
+ * They travel together for the same reason they are read together: the
31933
+ * underlying write carries both, so setting one alone means reading the
31934
+ * other back first and racing whoever else is writing.
31935
+ */
31936
+ setHomeReturn: method(object({
31937
+ deviceId: number(),
31938
+ enabled: boolean(),
31939
+ seconds: number().int().min(0).max(3600)
31940
+ }), _void(), {
31941
+ kind: "mutation",
31942
+ auth: "admin"
31943
+ }),
31944
+ /**
31877
31945
  * Pull the current PTZ position. Redundant with the auto-injected
31878
31946
  * `getStatus` method (see `status` below); kept for callers that
31879
31947
  * haven't migrated. Will be folded into `getStatus` in a future
@@ -41531,6 +41599,12 @@ Object.freeze({
41531
41599
  addonId: null,
41532
41600
  access: "create"
41533
41601
  },
41602
+ "ptz.captureHomeHere": {
41603
+ capName: "ptz",
41604
+ capScope: "device",
41605
+ addonId: null,
41606
+ access: "create"
41607
+ },
41534
41608
  "ptz.continuousMove": {
41535
41609
  capName: "ptz",
41536
41610
  capScope: "device",
@@ -41549,6 +41623,12 @@ Object.freeze({
41549
41623
  addonId: null,
41550
41624
  access: "view"
41551
41625
  },
41626
+ "ptz.getHomeReturn": {
41627
+ capName: "ptz",
41628
+ capScope: "device",
41629
+ addonId: null,
41630
+ access: "view"
41631
+ },
41552
41632
  "ptz.getOptions": {
41553
41633
  capName: "ptz",
41554
41634
  capScope: "device",
@@ -41603,6 +41683,12 @@ Object.freeze({
41603
41683
  addonId: null,
41604
41684
  access: "create"
41605
41685
  },
41686
+ "ptz.setHomeReturn": {
41687
+ capName: "ptz",
41688
+ capScope: "device",
41689
+ addonId: null,
41690
+ access: "create"
41691
+ },
41606
41692
  "ptz.stop": {
41607
41693
  capName: "ptz",
41608
41694
  capScope: "device",
@@ -44766,6 +44852,11 @@ Object.freeze({
44766
44852
  form: "single",
44767
44853
  optional: false
44768
44854
  }],
44855
+ "ptz.captureHomeHere": [{
44856
+ name: "deviceId",
44857
+ form: "single",
44858
+ optional: false
44859
+ }],
44769
44860
  "ptz.continuousMove": [{
44770
44861
  name: "deviceId",
44771
44862
  form: "single",
@@ -44781,6 +44872,11 @@ Object.freeze({
44781
44872
  form: "single",
44782
44873
  optional: false
44783
44874
  }],
44875
+ "ptz.getHomeReturn": [{
44876
+ name: "deviceId",
44877
+ form: "single",
44878
+ optional: false
44879
+ }],
44784
44880
  "ptz.getOptions": [{
44785
44881
  name: "deviceId",
44786
44882
  form: "single",
@@ -44826,6 +44922,11 @@ Object.freeze({
44826
44922
  form: "single",
44827
44923
  optional: false
44828
44924
  }],
44925
+ "ptz.setHomeReturn": [{
44926
+ name: "deviceId",
44927
+ form: "single",
44928
+ optional: false
44929
+ }],
44829
44930
  "ptz.stop": [{
44830
44931
  name: "deviceId",
44831
44932
  form: "single",
@@ -68510,7 +68611,7 @@ var require_yazl = /* @__PURE__ */ __commonJSMin(((exports) => {
68510
68611
  }
68511
68612
  }));
68512
68613
  //#endregion
68513
- //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-HL6TWIAL.js
68614
+ //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-KWQVN7H5.js
68514
68615
  var import_undici = require_undici();
68515
68616
  var import_yazl = /* @__PURE__ */ __toESM(require_yazl(), 1);
68516
68617
  var FLAGS_CAM_V2 = {
@@ -74927,7 +75028,7 @@ var require_lz4 = /* @__PURE__ */ __commonJSMin(((exports) => {
74927
75028
  };
74928
75029
  }));
74929
75030
  //#endregion
74930
- //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-3SEJZ2U5.js
75031
+ //#region node_modules/@apocaliss92/nodelink-js/dist/chunk-CE77DTET.js
74931
75032
  var import_fxp = require_fxp();
74932
75033
  var import_lz4 = /* @__PURE__ */ __toESM(require_lz4(), 1);
74933
75034
  function encodeHeader(h) {
@@ -75246,8 +75347,8 @@ function buildC2mQ(params) {
75246
75347
  const os = params.os ?? "MAC";
75247
75348
  return buildP2pXml(`<C2M_Q><uid>${xmlEscape(params.uid)}</uid><p>${xmlEscape(os)}</p></C2M_Q>`);
75248
75349
  }
75249
- function parseIpPortBlock(tag, body) {
75250
- const m = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i").exec(body);
75350
+ function parseIpPortBlock(tag2, body) {
75351
+ const m = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
75251
75352
  if (!m) return void 0;
75252
75353
  const block = m[1] ?? "";
75253
75354
  const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
@@ -75292,8 +75393,8 @@ function parseR2cCr(xml) {
75292
75393
  if (!Number.isFinite(rsp)) return void 0;
75293
75394
  const sidStr = /<sid>(-?\d+)<\/sid>/i.exec(body)?.[1];
75294
75395
  const sid = sidStr != null ? Number(sidStr) : void 0;
75295
- const parseCustom = (tag) => {
75296
- const mm = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i").exec(body);
75396
+ const parseCustom = (tag2) => {
75397
+ const mm = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
75297
75398
  if (!mm) return void 0;
75298
75399
  const block = mm[1] ?? "";
75299
75400
  const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
@@ -76853,12 +76954,12 @@ function asLogger(logger) {
76853
76954
  error: resolveMethod(base, "error"),
76854
76955
  debug: resolveMethod(base, "debug")
76855
76956
  };
76856
- out.child = (tag) => createTaggedLogger(out, tag);
76957
+ out.child = (tag2) => createTaggedLogger(out, tag2);
76857
76958
  return out;
76858
76959
  }
76859
- function createTaggedLogger(base, tag) {
76960
+ function createTaggedLogger(base, tag2) {
76860
76961
  const b = base.log ? base : asLogger(base);
76861
- const prefix = `[${tag}] `;
76962
+ const prefix = `[${tag2}] `;
76862
76963
  const wrap = (fn) => {
76863
76964
  return (message, ...optionalParams) => {
76864
76965
  if (typeof message === "string") fn(`${prefix}${message}`, ...optionalParams);
@@ -76885,7 +76986,7 @@ function createDebugGateLogger(base, enabled = false) {
76885
76986
  error: b.error,
76886
76987
  debug: enabled ? b.debug : noop
76887
76988
  };
76888
- out.child = (tag) => createDebugGateLogger(createTaggedLogger(out, tag), enabled);
76989
+ out.child = (tag2) => createDebugGateLogger(createTaggedLogger(out, tag2), enabled);
76889
76990
  return out;
76890
76991
  }
76891
76992
  function isTalkCmd(cmdId) {
@@ -82579,29 +82680,29 @@ function parseSupportXml(xml) {
82579
82680
  if (!match) return void 0;
82580
82681
  const supportXml = match[1] ?? "";
82581
82682
  const ptzMode = supportXml.match(/<ptzMode>([^<]*)<\/ptzMode>/i)?.[1];
82582
- const topLevelInt = (tag) => {
82583
- return toNumberOrUndefined(supportXml.match(new RegExp(`<${tag}>([^<]*)<\\/${tag}>`, "i"))?.[1]);
82683
+ const topLevelInt = (tag2) => {
82684
+ return toNumberOrUndefined(supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1]);
82584
82685
  };
82585
- const topLevelString = (tag) => {
82586
- return supportXml.match(new RegExp(`<${tag}>([^<]*)<\\/${tag}>`, "i"))?.[1];
82686
+ const topLevelString = (tag2) => {
82687
+ return supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1];
82587
82688
  };
82588
82689
  const items = [];
82589
82690
  for (const itemMatch of supportXml.matchAll(/<item[^>]*>([\s\S]*?)<\/item>/gi)) {
82590
82691
  const itemXml = itemMatch[1] ?? "";
82591
82692
  const item = { chnID: toNumberOrUndefined(itemXml.match(/<chnID>([^<]*)<\/chnID>/i)?.[1]) ?? 0 };
82592
82693
  for (const tagMatch of itemXml.matchAll(/<([A-Za-z0-9_]+)>([^<]*)<\/\1>/g)) {
82593
- const tag = tagMatch[1];
82694
+ const tag2 = tagMatch[1];
82594
82695
  const value = tagMatch[2];
82595
- if (!tag) continue;
82596
- if (tag === "chnID") continue;
82597
- item[tag] = toNumberOrUndefined(value) ?? value;
82696
+ if (!tag2) continue;
82697
+ if (tag2 === "chnID") continue;
82698
+ item[tag2] = toNumberOrUndefined(value) ?? value;
82598
82699
  }
82599
82700
  items.push(item);
82600
82701
  }
82601
82702
  const support = { items };
82602
82703
  if (ptzMode !== void 0) support.ptzMode = ptzMode;
82603
- const assignInt = (key, tag) => {
82604
- const v = topLevelInt(tag);
82704
+ const assignInt = (key, tag2) => {
82705
+ const v = topLevelInt(tag2);
82605
82706
  if (v !== void 0) support[key] = v;
82606
82707
  };
82607
82708
  assignInt("IOInputPortNum", "IOInputPortNum");
@@ -82828,15 +82929,15 @@ function extractCanvasFromShelterXml(xml) {
82828
82929
  const yMatch = xml.match(/<topLeftY>(\d+)<\/topLeftY>/g) ?? [];
82829
82930
  let canvasX = 0;
82830
82931
  let canvasY = 0;
82831
- for (const tag of xMatch) {
82832
- const v = Number(tag.replace(/<\/?topLeftX>/g, "")) | 0;
82932
+ for (const tag2 of xMatch) {
82933
+ const v = Number(tag2.replace(/<\/?topLeftX>/g, "")) | 0;
82833
82934
  if (v > 0) {
82834
82935
  canvasX = v & 65535;
82835
82936
  break;
82836
82937
  }
82837
82938
  }
82838
- for (const tag of yMatch) {
82839
- const v = Number(tag.replace(/<\/?topLeftY>/g, "")) | 0;
82939
+ for (const tag2 of yMatch) {
82940
+ const v = Number(tag2.replace(/<\/?topLeftY>/g, "")) | 0;
82840
82941
  if (v > 0) {
82841
82942
  canvasY = v & 65535;
82842
82943
  break;
@@ -82849,9 +82950,9 @@ function extractCanvasFromShelterXml(xml) {
82849
82950
  }
82850
82951
  function parseRectTags(block) {
82851
82952
  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];
82953
+ const grab = (tag2) => {
82954
+ const m = block.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`));
82955
+ if (m && m[1] !== void 0) out[tag2] = m[1];
82855
82956
  };
82856
82957
  grab("id");
82857
82958
  grab("name");
@@ -83096,9 +83197,9 @@ var buildDetectionClasses = (parsed, recordType) => {
83096
83197
  };
83097
83198
  var getXmlTexts = (xml, tags) => {
83098
83199
  const out = {};
83099
- for (const tag of tags) {
83100
- const v = getXmlText(xml, tag);
83101
- if (v !== void 0) out[tag] = v;
83200
+ for (const tag2 of tags) {
83201
+ const v = getXmlText(xml, tag2);
83202
+ if (v !== void 0) out[tag2] = v;
83102
83203
  }
83103
83204
  return out;
83104
83205
  };
@@ -83360,11 +83461,11 @@ function patchBlock(xml, block, fields) {
83360
83461
  const end = xml.indexOf(`</${block}>`, start);
83361
83462
  if (end < 0) return xml;
83362
83463
  let body = xml.slice(start, end);
83363
- for (const [tag, value] of Object.entries(fields)) {
83464
+ for (const [tag2, value] of Object.entries(fields)) {
83364
83465
  if (value === void 0) continue;
83365
83466
  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}>`;
83467
+ if (body.includes(`<${tag2}>`)) body = body.replace(new RegExp(`<${tag2}>[^<]*<\\/${tag2}>`), `<${tag2}>${escaped}</${tag2}>`);
83468
+ else body += `<${tag2}>${escaped}</${tag2}>`;
83368
83469
  }
83369
83470
  return xml.slice(0, start) + body + xml.slice(end);
83370
83471
  }
@@ -83432,6 +83533,66 @@ var OSD_CORNER_LABELS = {
83432
83533
  "bottom-left": "Bottom left",
83433
83534
  "bottom-right": "Bottom right"
83434
83535
  };
83536
+ function wireFloat(value) {
83537
+ return value.toExponential(6).replace(/e([+-])(\d)$/, "e$10$2");
83538
+ }
83539
+ function buildPtzGuardExtensionXml(channelId, direction) {
83540
+ return `<?xml version="1.0" encoding="UTF-8" ?>
83541
+ <Extension version="1.1">
83542
+ <channelId>${channelId}</channelId>${direction === "read" ? `
83543
+ <chnType>0</chnType>` : ""}
83544
+ </Extension>
83545
+ `;
83546
+ }
83547
+ function guardBody(channelId, command, fields) {
83548
+ return [
83549
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",
83550
+ "<body>",
83551
+ "<PtzGuard version=\"1.1\">",
83552
+ `<channelId>${channelId}</channelId>`,
83553
+ ...fields,
83554
+ `<command>${command}</command>`,
83555
+ "<imageName></imageName>",
83556
+ `<xpos>${wireFloat(0)}</xpos>`,
83557
+ `<ypos>${wireFloat(0)}</ypos>`,
83558
+ `<height>${wireFloat(0)}</height>`,
83559
+ `<width>${wireFloat(0)}</width>`,
83560
+ "<mode>global</mode>",
83561
+ "</PtzGuard>",
83562
+ "</body>",
83563
+ ""
83564
+ ].join("\n");
83565
+ }
83566
+ function buildPtzGuardGoXml(channelId) {
83567
+ return guardBody(channelId, "toGrd", ["<benable>0</benable>", "<timeout>68</timeout>"]);
83568
+ }
83569
+ function buildPtzGuardSetXml(input) {
83570
+ return guardBody(input.channelId, "setGrd", [
83571
+ `<benable>${input.enabled ? 1 : 0}</benable>`,
83572
+ `<timeout>${Math.round(input.timeoutSeconds)}</timeout>`,
83573
+ ...input.setPosition ? ["<needSetPos>1</needSetPos>"] : []
83574
+ ]);
83575
+ }
83576
+ function tag(xml, name) {
83577
+ const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml);
83578
+ return m === null ? null : (m[1] ?? "").trim();
83579
+ }
83580
+ function parsePtzGuardXml(xml) {
83581
+ if (!xml.includes("<PtzGuard")) return null;
83582
+ const enabled = tag(xml, "benable");
83583
+ const valid = tag(xml, "bvalid");
83584
+ const timeout = tag(xml, "timeout");
83585
+ if (enabled === null || valid === null || timeout === null) return null;
83586
+ const timeoutSeconds = Number.parseInt(timeout, 10);
83587
+ if (!Number.isFinite(timeoutSeconds)) return null;
83588
+ return {
83589
+ enabled: enabled === "1",
83590
+ valid: valid === "1",
83591
+ timeoutSeconds,
83592
+ mode: tag(xml, "mode") ?? "global",
83593
+ imageName: tag(xml, "imageName") ?? ""
83594
+ };
83595
+ }
83435
83596
  var emitter = new EventEmitter();
83436
83597
  var lastEventByCamera = /* @__PURE__ */ new Map();
83437
83598
  var MAX_GLOBAL_EVENTS = 300;
@@ -84644,8 +84805,8 @@ var buildFileInfoListStopXml = (params) => {
84644
84805
  </body>`;
84645
84806
  };
84646
84807
  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}>`;
84808
+ var xmlDateTimePayload = (tag2, d) => {
84809
+ 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
84810
  };
84650
84811
  var buildFileInfoListOpenXml = (params) => {
84651
84812
  return `<?xml version="1.0" encoding="UTF-8" ?>
@@ -84833,10 +84994,10 @@ var isPlausibleStream = (s) => {
84833
84994
  return s.width > 0 && s.height > 0 && (s.frameRate > 0 || s.bitRate > 0);
84834
84995
  };
84835
84996
  var logDebugStreamBlock = (params) => {
84836
- const { logger, traceNativeStream, channel, tag, blockXml } = params;
84997
+ const { logger, traceNativeStream, channel, tag: tag2, blockXml } = params;
84837
84998
  if (!traceNativeStream) return;
84838
84999
  if (!blockXml) {
84839
- (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag}> missing`);
85000
+ (logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag2}> missing`);
84840
85001
  return;
84841
85002
  }
84842
85003
  const raw = blockXml;
@@ -84863,7 +85024,7 @@ var logDebugStreamBlock = (params) => {
84863
85024
  const previewMax = 1400;
84864
85025
  const xmlPreview = raw.length <= previewMax ? raw : raw.slice(0, previewMax) + `
84865
85026
  ...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({
85027
+ (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
85028
  widthText,
84868
85029
  heightText,
84869
85030
  frameText,
@@ -84956,20 +85117,20 @@ var parseChannelStreamMetadataFromGetEncXml = (params) => {
84956
85117
  audioEnabled = audioEnabled && s.audio === 1;
84957
85118
  }
84958
85119
  }
84959
- for (const tag of [
85120
+ for (const tag2 of [
84960
85121
  "extStream",
84961
85122
  "thirdStream",
84962
85123
  "externStream",
84963
85124
  "extraStream"
84964
85125
  ]) {
84965
- const extMatch = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`));
85126
+ const extMatch = xml.match(new RegExp(`<${tag2}[^>]*>([\\s\\S]*?)<\\/${tag2}>`));
84966
85127
  if (!extMatch) continue;
84967
85128
  const extXml = extMatch[1] ?? "";
84968
85129
  logDebugStreamBlock({
84969
85130
  logger,
84970
85131
  traceNativeStream,
84971
85132
  channel,
84972
- tag,
85133
+ tag: tag2,
84973
85134
  blockXml: extXml
84974
85135
  });
84975
85136
  const s = buildStream({
@@ -86562,7 +86723,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86562
86723
  * @param logger - Optional logger for debug output
86563
86724
  * @returns The socket and a release function
86564
86725
  */
86565
- async acquirePooledSocket(tag, logger) {
86726
+ async acquirePooledSocket(tag2, logger) {
86566
86727
  const log = logger ?? this.logger;
86567
86728
  const now = Date.now();
86568
86729
  const cooldownEntry = this.socketPoolCooldowns.get(this.host);
@@ -86573,12 +86734,12 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86573
86734
  } else if (now < cooldownEntry.cooldownUntil) {
86574
86735
  const remainingMs = cooldownEntry.cooldownUntil - now;
86575
86736
  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}`);
86737
+ const error = /* @__PURE__ */ new Error(`[SocketPool] Host ${this.host} is in cooldown for ${Math.ceil(remainingMs / 1e3)}s due to ${reason}. tag=${tag2}`);
86577
86738
  log?.debug?.(error.message);
86578
86739
  throw error;
86579
86740
  }
86580
86741
  }
86581
- const existing = this.socketPool.get(tag);
86742
+ const existing = this.socketPool.get(tag2);
86582
86743
  if (existing) {
86583
86744
  if (existing.idleCloseTimer) {
86584
86745
  clearTimeout(existing.idleCloseTimer);
@@ -86588,35 +86749,35 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86588
86749
  const client2 = await existing.pendingPromise;
86589
86750
  existing.refCount++;
86590
86751
  existing.lastUsedAt = Date.now();
86591
- log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${tag} (refCount=${existing.refCount})`);
86752
+ log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${tag2} (refCount=${existing.refCount})`);
86592
86753
  return {
86593
86754
  client: client2,
86594
- release: () => this.releasePooledSocket(tag, logger)
86755
+ release: () => this.releasePooledSocket(tag2, logger)
86595
86756
  };
86596
86757
  }
86597
86758
  if (existing.refCount === 0) {
86598
86759
  existing.refCount = 1;
86599
86760
  existing.lastUsedAt = Date.now();
86600
- log?.debug?.(`[SocketPool] Reusing idle socket for tag=${tag}`);
86761
+ log?.debug?.(`[SocketPool] Reusing idle socket for tag=${tag2}`);
86601
86762
  try {
86602
86763
  if (!existing.client.loggedIn) await existing.client.login();
86603
86764
  } catch {}
86604
86765
  if (existing.client.loggedIn) return {
86605
86766
  client: existing.client,
86606
- release: () => this.releasePooledSocket(tag, logger)
86767
+ release: () => this.releasePooledSocket(tag2, logger)
86607
86768
  };
86608
- } else if (tag.startsWith("replay:")) log?.debug?.(`[SocketPool] Preempting active replay socket for tag=${tag}`);
86769
+ } else if (tag2.startsWith("replay:")) log?.debug?.(`[SocketPool] Preempting active replay socket for tag=${tag2}`);
86609
86770
  else {
86610
86771
  existing.refCount++;
86611
86772
  existing.lastUsedAt = Date.now();
86612
- log?.debug?.(`[SocketPool] Reusing active socket for tag=${tag} (refCount=${existing.refCount})`);
86773
+ log?.debug?.(`[SocketPool] Reusing active socket for tag=${tag2} (refCount=${existing.refCount})`);
86613
86774
  return {
86614
86775
  client: existing.client,
86615
- release: () => this.releasePooledSocket(tag, logger)
86776
+ release: () => this.releasePooledSocket(tag2, logger)
86616
86777
  };
86617
86778
  }
86618
- log?.debug?.(`[SocketPool] Closing existing socket for tag=${tag} (recreating)`);
86619
- this.socketPool.delete(tag);
86779
+ log?.debug?.(`[SocketPool] Closing existing socket for tag=${tag2} (recreating)`);
86780
+ this.socketPool.delete(tag2);
86620
86781
  if (existing.generalPermitRelease) {
86621
86782
  try {
86622
86783
  existing.generalPermitRelease();
@@ -86629,10 +86790,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86629
86790
  skipLogout: true
86630
86791
  });
86631
86792
  } catch (e) {
86632
- log?.warn?.(`[SocketPool] Error closing old socket for tag=${tag}: ${e}`);
86793
+ log?.warn?.(`[SocketPool] Error closing old socket for tag=${tag2}: ${e}`);
86633
86794
  }
86634
86795
  }
86635
- log?.log?.(`[SocketPool] Creating new socket for tag=${tag}`);
86796
+ log?.log?.(`[SocketPool] Creating new socket for tag=${tag2}`);
86636
86797
  const entry = {
86637
86798
  client: void 0,
86638
86799
  refCount: 0,
@@ -86649,7 +86810,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86649
86810
  } : this.clientOptions);
86650
86811
  this.attachD2cDiscListener(newClient);
86651
86812
  newClient.on("error", (err) => {
86652
- log?.debug?.(`[SocketPool] tag=${tag} client error: ${err?.message ?? err}`);
86813
+ log?.debug?.(`[SocketPool] tag=${tag2} client error: ${err?.message ?? err}`);
86653
86814
  });
86654
86815
  await newClient.login();
86655
86816
  const existingCooldown = this.socketPoolCooldowns.get(this.host);
@@ -86661,10 +86822,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86661
86822
  entry.refCount = 1;
86662
86823
  entry.lastUsedAt = Date.now();
86663
86824
  delete entry.pendingPromise;
86664
- log?.log?.(`[SocketPool] Socket connected for tag=${tag}`);
86665
- if (tag !== "general") try {
86825
+ log?.log?.(`[SocketPool] Socket connected for tag=${tag2}`);
86826
+ if (tag2 !== "general") try {
86666
86827
  const generalEntry = this.socketPool.get("general");
86667
- if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${tag}`);
86828
+ if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${tag2}`);
86668
86829
  } catch {}
86669
86830
  if (this.sessionGuardEnabled) this.maybeRebootOnTooManySessions();
86670
86831
  return newClient;
@@ -86675,21 +86836,21 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86675
86836
  if (failureCount >= _ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD) {
86676
86837
  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
86838
  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}`);
86839
+ log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}). Entering cooldown for ${Math.ceil(backoffMs / 1e3)}s. tag=${tag2}`);
86840
+ } else log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}/${_ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD} before cooldown). tag=${tag2}`);
86680
86841
  this.socketPoolCooldowns.set(this.host, {
86681
86842
  failureCount,
86682
86843
  lastFailureAt: now2,
86683
86844
  cooldownUntil
86684
86845
  });
86685
- this.socketPool.delete(tag);
86846
+ this.socketPool.delete(tag2);
86686
86847
  throw loginError;
86687
86848
  }
86688
86849
  })();
86689
- this.socketPool.set(tag, entry);
86850
+ this.socketPool.set(tag2, entry);
86690
86851
  return {
86691
86852
  client: await entry.pendingPromise,
86692
- release: () => this.releasePooledSocket(tag, logger)
86853
+ release: () => this.releasePooledSocket(tag2, logger)
86693
86854
  };
86694
86855
  }
86695
86856
  /**
@@ -86697,31 +86858,31 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86697
86858
  * For shared sockets (general, streaming), just decrements refCount.
86698
86859
  * For replay sockets, schedules idle close.
86699
86860
  */
86700
- async releasePooledSocket(tag, logger) {
86861
+ async releasePooledSocket(tag2, logger) {
86701
86862
  const log = logger ?? this.logger;
86702
- const entry = this.socketPool.get(tag);
86863
+ const entry = this.socketPool.get(tag2);
86703
86864
  if (!entry) return;
86704
86865
  entry.refCount = Math.max(0, entry.refCount - 1);
86705
86866
  entry.lastUsedAt = Date.now();
86706
- log?.debug?.(`[SocketPool] Released socket for tag=${tag} (refCount=${entry.refCount})`);
86867
+ log?.debug?.(`[SocketPool] Released socket for tag=${tag2} (refCount=${entry.refCount})`);
86707
86868
  if (entry.refCount > 0) return;
86708
- const isReplayTag = tag.startsWith("replay:");
86709
- const isStreamingTag = tag.startsWith("streaming:");
86710
- if (tag === "general") return;
86869
+ const isReplayTag = tag2.startsWith("replay:");
86870
+ const isStreamingTag = tag2.startsWith("streaming:");
86871
+ if (tag2 === "general") return;
86711
86872
  if (isStreamingTag) {
86712
86873
  if (entry.idleCloseTimer) return;
86713
86874
  entry.idleCloseTimer = setTimeout(async () => {
86714
- const current = this.socketPool.get(tag);
86875
+ const current = this.socketPool.get(tag2);
86715
86876
  if (!current) return;
86716
86877
  if (current.refCount > 0) return;
86717
- this.socketPool.delete(tag);
86878
+ this.socketPool.delete(tag2);
86718
86879
  if (current.generalPermitRelease) {
86719
86880
  try {
86720
86881
  current.generalPermitRelease();
86721
86882
  } catch {}
86722
86883
  current.generalPermitRelease = void 0;
86723
86884
  }
86724
- log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${tag}`);
86885
+ log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${tag2}`);
86725
86886
  try {
86726
86887
  await current.client.close({
86727
86888
  reason: "streaming idle close",
@@ -86734,11 +86895,11 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86734
86895
  if (isReplayTag) {
86735
86896
  if (entry.idleCloseTimer) return;
86736
86897
  entry.idleCloseTimer = setTimeout(async () => {
86737
- const current = this.socketPool.get(tag);
86898
+ const current = this.socketPool.get(tag2);
86738
86899
  if (!current) return;
86739
86900
  if (current.refCount > 0) return;
86740
- this.socketPool.delete(tag);
86741
- log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${tag} (keepalive expired)`);
86901
+ this.socketPool.delete(tag2);
86902
+ log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${tag2} (keepalive expired)`);
86742
86903
  try {
86743
86904
  await current.client.close({
86744
86905
  reason: "replay idle keepalive expired",
@@ -86748,24 +86909,24 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86748
86909
  }, _ReolinkBaichuanApi.SOCKET_POOL_KEEPALIVE_MS);
86749
86910
  return;
86750
86911
  }
86751
- this.socketPool.delete(tag);
86912
+ this.socketPool.delete(tag2);
86752
86913
  try {
86753
86914
  await entry.client.close({
86754
86915
  reason: "socket pool release",
86755
86916
  skipLogout: true
86756
86917
  });
86757
- log?.log?.(`[SocketPool] Closed socket for tag=${tag}`);
86918
+ log?.log?.(`[SocketPool] Closed socket for tag=${tag2}`);
86758
86919
  } catch (e) {
86759
- log?.warn?.(`[SocketPool] Error closing socket for tag=${tag}: ${e}`);
86920
+ log?.warn?.(`[SocketPool] Error closing socket for tag=${tag2}: ${e}`);
86760
86921
  }
86761
86922
  }
86762
86923
  /**
86763
86924
  * Force-close a socket by tag.
86764
86925
  * Used to preempt existing connections before acquiring a new one.
86765
86926
  */
86766
- async forceClosePooledSocket(tag, logger) {
86927
+ async forceClosePooledSocket(tag2, logger) {
86767
86928
  const log = logger ?? this.logger;
86768
- const entry = this.socketPool.get(tag);
86929
+ const entry = this.socketPool.get(tag2);
86769
86930
  if (!entry) return false;
86770
86931
  if (entry.idleCloseTimer) {
86771
86932
  clearTimeout(entry.idleCloseTimer);
@@ -86777,16 +86938,16 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86777
86938
  } catch {}
86778
86939
  entry.generalPermitRelease = void 0;
86779
86940
  }
86780
- log?.debug?.(`[SocketPool] Force-closing socket for tag=${tag}`);
86781
- this.socketPool.delete(tag);
86941
+ log?.debug?.(`[SocketPool] Force-closing socket for tag=${tag2}`);
86942
+ this.socketPool.delete(tag2);
86782
86943
  try {
86783
86944
  await entry.client.close({
86784
86945
  reason: "force closed",
86785
86946
  skipLogout: true
86786
86947
  });
86787
- log?.log?.(`[SocketPool] Force-closed socket for tag=${tag}`);
86948
+ log?.log?.(`[SocketPool] Force-closed socket for tag=${tag2}`);
86788
86949
  } catch (e) {
86789
- log?.warn?.(`[SocketPool] Error during force-close for tag=${tag}: ${e}`);
86950
+ log?.warn?.(`[SocketPool] Error during force-close for tag=${tag2}: ${e}`);
86790
86951
  }
86791
86952
  return true;
86792
86953
  }
@@ -86796,7 +86957,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86796
86957
  async cleanupSocketPool() {
86797
86958
  const entries = Array.from(this.socketPool.entries());
86798
86959
  this.socketPool.clear();
86799
- await Promise.allSettled(entries.map(async ([tag, entry]) => {
86960
+ await Promise.allSettled(entries.map(async ([tag2, entry]) => {
86800
86961
  try {
86801
86962
  if (entry.idleCloseTimer) clearTimeout(entry.idleCloseTimer);
86802
86963
  if (entry.generalPermitRelease) {
@@ -86805,7 +86966,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86805
86966
  } catch {}
86806
86967
  entry.generalPermitRelease = void 0;
86807
86968
  }
86808
- this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${tag}`);
86969
+ this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${tag2}`);
86809
86970
  await entry.client.close({
86810
86971
  reason: "API cleanup",
86811
86972
  skipLogout: true
@@ -86838,17 +86999,17 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86838
86999
  * ```
86839
87000
  */
86840
87001
  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);
87002
+ const tag2 = this.resolveSocketTag(sessionKey);
87003
+ (logger ?? this.logger)?.debug?.(`[SocketPool] createDedicatedSession sessionKey=${sessionKey} \u2192 tag=${tag2}`);
87004
+ return await this.acquirePooledSocket(tag2, logger);
86844
87005
  }
86845
87006
  /**
86846
87007
  * @deprecated Use forceClosePooledSocket via createDedicatedSession instead.
86847
87008
  * Force-close a dedicated client if it exists.
86848
87009
  */
86849
87010
  async forceCloseDedicatedClient(sessionKey, logger) {
86850
- const tag = this.resolveSocketTag(sessionKey);
86851
- return await this.forceClosePooledSocket(tag, logger);
87011
+ const tag2 = this.resolveSocketTag(sessionKey);
87012
+ return await this.forceClosePooledSocket(tag2, logger);
86852
87013
  }
86853
87014
  /**
86854
87015
  * @deprecated Cleanup handled by cleanupSocketPool now.
@@ -86863,8 +87024,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
86863
87024
  const debugCfg = this.client.getDebugConfig?.();
86864
87025
  if (debugCfg) {
86865
87026
  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}`);
87027
+ const tag2 = sid ? `ReolinkSimpleEvent sid=${sid}` : "ReolinkSimpleEvent";
87028
+ eventTraceLog(debugCfg, this.logger, tag2, `dispatch type=${evt.type} channel=${evt.channel} timestamp=${evt.timestamp}`);
86868
87029
  }
86869
87030
  for (const cb of this.simpleEventListeners) try {
86870
87031
  Promise.resolve(cb(evt)).catch((e) => {
@@ -87462,7 +87623,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
87462
87623
  return;
87463
87624
  }
87464
87625
  entry.startInFlight = (async () => {
87465
- const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-PBJL3EB5-D-etWPiW.mjs");
87626
+ const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-2M4UO7MB-CB-tIHMA.mjs");
87466
87627
  const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
87467
87628
  const dedicated = await this.createDedicatedSession(sessionKey);
87468
87629
  const stream = new BaichuanVideoStream2({
@@ -88029,8 +88190,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88029
88190
  const idleTimeoutMs = options?.idleTimeoutMs ?? 3e4;
88030
88191
  const sessionKey = `talk:${options?.deviceId ?? "unknown"}:ch${channel}:${Date.now()}`;
88031
88192
  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);
88193
+ const tag2 = this.resolveSocketTag(sessionKey);
88194
+ const { client: dedicatedClient, release } = await this.acquirePooledSocket(tag2, logger);
88034
88195
  const summary = this.getSocketPoolSummary();
88035
88196
  logger?.info?.(`[DedicatedTalk] Session created [sessions: ${summary.count} active${summary.count > 0 ? ` (${summary.tags.join(", ")})` : ""}]`);
88036
88197
  try {
@@ -88143,8 +88304,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88143
88304
  }
88144
88305
  /** SetNetPort via Baichuan: cmd_id 36 (enable/disable rtsp/rtmp/onvif/http/https) */
88145
88306
  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>`;
88307
+ const tag2 = `${params.port[0].toUpperCase()}${params.port.slice(1)}Port`;
88308
+ const xml = `<?xml version="1.0" encoding="UTF-8" ?><body><${tag2} version="1.1"><enable>${params.enable ? 1 : 0}</enable></${tag2}></body>`;
88148
88309
  await this.sendXml({
88149
88310
  cmdId: 36,
88150
88311
  payloadXml: xml
@@ -88175,13 +88336,13 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88175
88336
  */
88176
88337
  async setPortConfig(patch) {
88177
88338
  const blocks = [];
88178
- const append = (tag, portField, cfg) => {
88339
+ const append = (tag2, portField, cfg) => {
88179
88340
  if (!cfg) return;
88180
88341
  if (cfg.port === void 0 && cfg.enable === void 0) return;
88181
88342
  const inner = [];
88182
88343
  if (cfg.port !== void 0) inner.push(`<${portField}>${cfg.port}</${portField}>`);
88183
88344
  if (cfg.enable !== void 0) inner.push(`<enable>${cfg.enable ? 1 : 0}</enable>`);
88184
- blocks.push(`<${tag} version="1.1">${inner.join("")}</${tag}>`);
88345
+ blocks.push(`<${tag2} version="1.1">${inner.join("")}</${tag2}>`);
88185
88346
  };
88186
88347
  append("ServerPort", "serverPort", patch.server);
88187
88348
  append("HttpPort", "httpPort", patch.http);
@@ -88695,8 +88856,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
88695
88856
  ];
88696
88857
  const current = await this.getEncXml(ch);
88697
88858
  let updated = null;
88698
- for (const tag of candidateTags) {
88699
- const sectionRe = new RegExp(`(<${tag}[^>]*>[\\s\\S]*?<videoEncType>)(\\d+)(</videoEncType>)`);
88859
+ for (const tag2 of candidateTags) {
88860
+ const sectionRe = new RegExp(`(<${tag2}[^>]*>[\\s\\S]*?<videoEncType>)(\\d+)(</videoEncType>)`);
88700
88861
  if (!sectionRe.test(current)) continue;
88701
88862
  const next = current.replace(sectionRe, `$1${desired}$3`);
88702
88863
  if (next !== current) {
@@ -89226,9 +89387,9 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
89226
89387
  const streamType = params.streamType;
89227
89388
  const logger = params.logger ?? this.logger;
89228
89389
  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);
89390
+ const tag2 = this.resolveSocketTag(sessionKey);
89391
+ logger?.debug?.(`[startRecordingReplayStreamStandalone] sessionKey=${sessionKey} -> tag=${tag2}`);
89392
+ const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
89232
89393
  const uid = await this.ensureUidForRecordings(channel, void 0);
89233
89394
  const payloadXml = buildFileInfoListReplayByNameXml({
89234
89395
  channel,
@@ -89331,8 +89492,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
89331
89492
  const streamType = params.streamType;
89332
89493
  const logger = params.logger ?? this.logger;
89333
89494
  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);
89495
+ const tag2 = this.resolveSocketTag(sessionKey);
89496
+ const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
89336
89497
  let uid;
89337
89498
  try {
89338
89499
  uid = await this.ensureUidForRecordings(channel, void 0);
@@ -91559,6 +91720,73 @@ ${stderr}`));
91559
91720
  return result;
91560
91721
  }
91561
91722
  /**
91723
+ * Read the PTZ guard point ("monitoring point" in the app).
91724
+ *
91725
+ * cmd_id: 332
91726
+ *
91727
+ * Returns `null` when the camera has no readable guard configuration — never
91728
+ * a fabricated "none", because that answer is what a consumer uses to decide
91729
+ * whether to move the head.
91730
+ */
91731
+ async getPtzGuard(channel) {
91732
+ const ch = this.normalizeChannel(channel);
91733
+ return parsePtzGuardXml(await this.sendXml({
91734
+ cmdId: 332,
91735
+ channel: ch,
91736
+ channelIdOverride: ch,
91737
+ extensionXml: buildPtzGuardExtensionXml(ch, "read"),
91738
+ messageClass: BC_CLASS_MODERN_24,
91739
+ streamType: 0
91740
+ }));
91741
+ }
91742
+ /**
91743
+ * Configure the PTZ guard point.
91744
+ *
91745
+ * cmd_id: 331 with `<command>setGrd</command>`
91746
+ *
91747
+ * `setPosition` pins the guard point to the head's CURRENT position. Leave it
91748
+ * false when only changing the timeout or the enable flag: re-sending it
91749
+ * would silently move a point the operator had already placed.
91750
+ */
91751
+ async setPtzGuard(options, channel) {
91752
+ const ch = this.normalizeChannel(channel);
91753
+ await this.sendXml({
91754
+ cmdId: 331,
91755
+ channel: ch,
91756
+ channelIdOverride: ch,
91757
+ extensionXml: buildPtzGuardExtensionXml(ch, "write"),
91758
+ payloadXml: buildPtzGuardSetXml({
91759
+ channelId: ch,
91760
+ enabled: options.enabled,
91761
+ timeoutSeconds: options.timeoutSeconds,
91762
+ setPosition: options.setPosition === true
91763
+ }),
91764
+ messageClass: BC_CLASS_MODERN_24,
91765
+ streamType: 0
91766
+ });
91767
+ }
91768
+ /**
91769
+ * Send the head to the guard point NOW.
91770
+ *
91771
+ * cmd_id: 331 with `<command>toGrd</command>`
91772
+ *
91773
+ * This is the closest thing Baichuan has to a "go home": the guard point is
91774
+ * an operator-placed position, unlike preset slot 0 which merely happens to
91775
+ * be first.
91776
+ */
91777
+ async goToPtzGuard(channel) {
91778
+ const ch = this.normalizeChannel(channel);
91779
+ await this.sendXml({
91780
+ cmdId: 331,
91781
+ channel: ch,
91782
+ channelIdOverride: ch,
91783
+ extensionXml: buildPtzGuardExtensionXml(ch, "write"),
91784
+ payloadXml: buildPtzGuardGoXml(ch),
91785
+ messageClass: BC_CLASS_MODERN_24,
91786
+ streamType: 0
91787
+ });
91788
+ }
91789
+ /**
91562
91790
  * Read zoom/focus min/max/current positions.
91563
91791
  * cmd_id: 294 (MSG_ID_GET_ZOOM_FOCUS)
91564
91792
  */
@@ -91651,10 +91879,10 @@ ${stderr}`));
91651
91879
  notifyD2cDisc() {
91652
91880
  const now = Date.now();
91653
91881
  this.lastD2cDiscAtMs = now;
91654
- const streamingTags = Array.from(this.socketPool.keys()).filter((tag) => tag.startsWith("streaming:"));
91882
+ const streamingTags = Array.from(this.socketPool.keys()).filter((tag2) => tag2.startsWith("streaming:"));
91655
91883
  if (streamingTags.length > 0) {
91656
91884
  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(() => {});
91885
+ for (const tag2 of streamingTags) this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
91658
91886
  }
91659
91887
  const immediateCooldownUntil = now + _ReolinkBaichuanApi.D2C_DISC_IMMEDIATE_COOLDOWN_MS;
91660
91888
  const existing = this.socketPoolCooldowns.get(this.host);
@@ -91687,15 +91915,15 @@ ${stderr}`));
91687
91915
  * Returns undefined if the client is not in the pool (e.g. it's the general socket used directly).
91688
91916
  */
91689
91917
  findSocketTagForClient(client) {
91690
- for (const [tag, entry] of this.socketPool) if (entry.client === client) return tag;
91918
+ for (const [tag2, entry] of this.socketPool) if (entry.client === client) return tag2;
91691
91919
  }
91692
91920
  /**
91693
91921
  * Reset the consecutive stream-start timeout counter for a streaming socket.
91694
91922
  * Called on successful stream start.
91695
91923
  */
91696
91924
  resetStreamTimeoutCounter(client) {
91697
- const tag = this.findSocketTagForClient(client);
91698
- if (tag) this.consecutiveStreamTimeouts.delete(tag);
91925
+ const tag2 = this.findSocketTagForClient(client);
91926
+ if (tag2) this.consecutiveStreamTimeouts.delete(tag2);
91699
91927
  }
91700
91928
  /**
91701
91929
  * Track a stream-start timeout on a streaming socket.
@@ -91703,14 +91931,14 @@ ${stderr}`));
91703
91931
  * socket so the next attempt creates a fresh connection.
91704
91932
  */
91705
91933
  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);
91934
+ const tag2 = this.findSocketTagForClient(client);
91935
+ if (!tag2 || !tag2.startsWith("streaming:")) return;
91936
+ const count = (this.consecutiveStreamTimeouts.get(tag2) ?? 0) + 1;
91937
+ this.consecutiveStreamTimeouts.set(tag2, count);
91710
91938
  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(() => {});
91939
+ this.logger?.warn?.(`[SocketPool] ${count} consecutive stream timeouts on tag=${tag2}, force-closing socket`);
91940
+ this.consecutiveStreamTimeouts.delete(tag2);
91941
+ this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
91714
91942
  }
91715
91943
  }
91716
91944
  /**
@@ -92577,8 +92805,20 @@ ${xml}`);
92577
92805
  const support = supportResult.status === "fulfilled" ? supportResult.value : void 0;
92578
92806
  const abilities = abilitiesResult.status === "fulfilled" ? abilitiesResult.value : void 0;
92579
92807
  const supportItem = getSupportItemForChannel(support, ch);
92808
+ let model;
92809
+ try {
92810
+ const info = await this.getInfo(void 0, { timeoutMs: 5e3 });
92811
+ model = typeof info?.type === "string" ? info.type : void 0;
92812
+ } catch (e) {
92813
+ this.logger.debug("[ReolinkBaichuanApi] getDeviceCapabilities: getInfo(type) failed", {
92814
+ host: this.host,
92815
+ channel: ch,
92816
+ err: e instanceof Error ? e.message : String(e)
92817
+ });
92818
+ }
92580
92819
  const capabilities = computeDeviceCapabilities({
92581
92820
  channel: ch,
92821
+ ...model != null && { model },
92582
92822
  ...support != null && { support },
92583
92823
  ...abilities != null && { abilities }
92584
92824
  });
@@ -93347,7 +93587,7 @@ ${xml}`);
93347
93587
  * @returns Test results for all stream types and profiles
93348
93588
  */
93349
93589
  async testChannelStreams(channel, logger) {
93350
- const { testChannelStreams } = await import("./DiagnosticsTools-TID5M22B-9NV95vRN.mjs");
93590
+ const { testChannelStreams } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
93351
93591
  return await testChannelStreams({
93352
93592
  api: this,
93353
93593
  channel: this.normalizeChannel(channel),
@@ -93363,7 +93603,7 @@ ${xml}`);
93363
93603
  * @returns Complete diagnostics for all channels and streams
93364
93604
  */
93365
93605
  async collectMultifocalDiagnostics(logger) {
93366
- const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-TID5M22B-9NV95vRN.mjs");
93606
+ const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
93367
93607
  return await collectMultifocalDiagnostics({
93368
93608
  api: this,
93369
93609
  logger
@@ -150155,15 +150395,39 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
150155
150395
  */
150156
150396
  async resolveHomePreset() {
150157
150397
  const chosen = this.config.get("homePresetId") ?? "";
150158
- if (chosen === "") return {
150398
+ if (chosen !== "") return {
150399
+ presetId: chosen,
150400
+ source: "operator"
150401
+ };
150402
+ if ((await this.readGuardStatus())?.valid === true) return {
150159
150403
  presetId: null,
150160
- source: "none"
150404
+ source: "native"
150161
150405
  };
150162
150406
  return {
150163
- presetId: chosen,
150164
- source: "operator"
150407
+ presetId: null,
150408
+ source: "none"
150165
150409
  };
150166
150410
  }
150411
+ /**
150412
+ * The camera's guard-point configuration, or `null` when it cannot be read.
150413
+ *
150414
+ * Never a fabricated "no guard configured": that answer decides whether
150415
+ * `goHome` moves the head, and an unreadable camera is not evidence that no
150416
+ * guard point exists (D393).
150417
+ */
150418
+ async readGuardStatus() {
150419
+ try {
150420
+ const api = await this.ensureApi();
150421
+ const channel = this.getChannel();
150422
+ return await api.getPtzGuard(channel);
150423
+ } catch (err) {
150424
+ this.ctx.logger.warn("reolink guard point unreadable — goHome will fall back", {
150425
+ tags: { deviceId: this.id },
150426
+ meta: { error: err instanceof Error ? err.message : String(err) }
150427
+ });
150428
+ return null;
150429
+ }
150430
+ }
150167
150431
  getChannel() {
150168
150432
  const ch = this.config.get("channel");
150169
150433
  if (typeof ch === "number" && ch >= 0) return ch;
@@ -153616,7 +153880,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
153616
153880
  goHome: async ({ deviceId }) => {
153617
153881
  if (deviceId !== this.id) return;
153618
153882
  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");
153883
+ if (home.source === "native") {
153884
+ await (await this.ensureApi()).goToPtzGuard(this.getChannel());
153885
+ return;
153886
+ }
153887
+ 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
153888
  const id = Number(home.presetId);
153621
153889
  if (!Number.isFinite(id)) throw new Error(`Configured home preset is not a Baichuan id: ${home.presetId}`);
153622
153890
  const api = await this.ensureApi();
@@ -153630,6 +153898,41 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
153630
153898
  };
153631
153899
  return this.resolveHomePreset();
153632
153900
  },
153901
+ captureHomeHere: async ({ deviceId }) => {
153902
+ if (deviceId !== this.id) return;
153903
+ const current = await this.readGuardStatus();
153904
+ const api = await this.ensureApi();
153905
+ const channel = this.getChannel();
153906
+ await api.setPtzGuard({
153907
+ enabled: current?.enabled ?? false,
153908
+ timeoutSeconds: current?.timeoutSeconds ?? 60,
153909
+ setPosition: true
153910
+ }, channel);
153911
+ this.ctx.logger.info("reolink: guard point pinned to the current position", { tags: { deviceId: this.id } });
153912
+ },
153913
+ getHomeReturn: async ({ deviceId }) => {
153914
+ if (deviceId !== this.id) return null;
153915
+ const guard = await this.readGuardStatus();
153916
+ return guard === null ? null : {
153917
+ enabled: guard.enabled,
153918
+ seconds: guard.timeoutSeconds
153919
+ };
153920
+ },
153921
+ setHomeReturn: async ({ deviceId, enabled, seconds }) => {
153922
+ if (deviceId !== this.id) return;
153923
+ await (await this.ensureApi()).setPtzGuard({
153924
+ enabled,
153925
+ timeoutSeconds: seconds,
153926
+ setPosition: false
153927
+ }, this.getChannel());
153928
+ this.ctx.logger.info("reolink: guard point idle-return updated", {
153929
+ tags: { deviceId: this.id },
153930
+ meta: {
153931
+ enabled,
153932
+ seconds
153933
+ }
153934
+ });
153935
+ },
153633
153936
  setHomePreset: async ({ deviceId, presetId }) => {
153634
153937
  if (deviceId !== this.id) return;
153635
153938
  await this.config.setAll({ homePresetId: presetId ?? "" });