@apocaliss92/nodelink-js 0.3.5 → 0.4.1

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.
@@ -4912,15 +4912,18 @@ var init_zip = __esm({
4912
4912
  // src/debug/DiagnosticsTools.ts
4913
4913
  var DiagnosticsTools_exports = {};
4914
4914
  __export(DiagnosticsTools_exports, {
4915
+ captureModelFixtures: () => captureModelFixtures,
4915
4916
  collectCgiDiagnostics: () => collectCgiDiagnostics,
4916
4917
  collectMultifocalDiagnostics: () => collectMultifocalDiagnostics,
4917
4918
  collectNativeDiagnostics: () => collectNativeDiagnostics,
4918
4919
  collectNvrDiagnostics: () => collectNvrDiagnostics,
4920
+ computeExpectedStreamCompatibility: () => computeExpectedStreamCompatibility,
4919
4921
  createDiagnosticsBundle: () => createDiagnosticsBundle,
4920
4922
  printNvrDiagnostics: () => printNvrDiagnostics,
4921
4923
  runAllDiagnosticsConsecutively: () => runAllDiagnosticsConsecutively,
4922
4924
  runMultifocalDiagnosticsConsecutively: () => runMultifocalDiagnosticsConsecutively,
4923
4925
  sampleStreams: () => sampleStreams,
4926
+ sanitizeFixtureData: () => sanitizeFixtureData,
4924
4927
  testChannelStreams: () => testChannelStreams
4925
4928
  });
4926
4929
  function safeStringifyError(error) {
@@ -4945,6 +4948,10 @@ function writeJson(filePath, obj) {
4945
4948
  mkdirp(path4.dirname(filePath));
4946
4949
  fs4.writeFileSync(filePath, JSON.stringify(obj, null, 2));
4947
4950
  }
4951
+ function writeText(filePath, text) {
4952
+ mkdirp(path4.dirname(filePath));
4953
+ fs4.writeFileSync(filePath, text);
4954
+ }
4948
4955
  function appendNdjson(filePath, obj) {
4949
4956
  mkdirp(path4.dirname(filePath));
4950
4957
  fs4.appendFileSync(filePath, JSON.stringify(obj) + "\n");
@@ -7208,7 +7215,411 @@ async function runAllDiagnosticsConsecutively(params) {
7208
7215
  streamsDir
7209
7216
  };
7210
7217
  }
7211
- var fs4, path4, import_node_child_process2, import_node_path;
7218
+ function maskIp(ip) {
7219
+ const parts = ip.split(".");
7220
+ return `${parts[0]}.***.***.***`;
7221
+ }
7222
+ function maskMac(mac) {
7223
+ const sep = mac.includes("-") ? "-" : ":";
7224
+ const parts = mac.split(/[:-]/);
7225
+ return `${parts[0]}${sep}${parts[1]}${sep}**${sep}**${sep}**${sep}**`;
7226
+ }
7227
+ function maskSerial(val) {
7228
+ if (val.length <= 4) return "****";
7229
+ return val.slice(0, 2) + "*".repeat(val.length - 4) + val.slice(-2);
7230
+ }
7231
+ function sanitizeString(s) {
7232
+ let out = s;
7233
+ out = out.replace(/:\/\/([^:@]+):([^@]+)@/g, "://***:***@");
7234
+ out = out.replace(/(password=)[^&\s]*/gi, "$1***");
7235
+ out = out.replace(/(user=)[^&\s]*/gi, "$1***");
7236
+ out = out.replace(IPV4_RE, (match) => maskIp(match));
7237
+ out = out.replace(MAC_RE, (match) => maskMac(match));
7238
+ return out;
7239
+ }
7240
+ function sanitizeFixtureData(value) {
7241
+ if (value === null || value === void 0) return value;
7242
+ if (typeof value === "string") {
7243
+ return sanitizeString(value);
7244
+ }
7245
+ if (Array.isArray(value)) {
7246
+ return value.map(sanitizeFixtureData);
7247
+ }
7248
+ if (typeof value === "object") {
7249
+ const out = {};
7250
+ for (const [k, v] of Object.entries(value)) {
7251
+ const kLower = k.toLowerCase();
7252
+ if (REDACT_KEYS.has(kLower)) {
7253
+ out[k] = "***";
7254
+ } else if (MASK_KEYS.has(kLower) || kLower === "serialnumber") {
7255
+ out[k] = typeof v === "string" ? maskSerial(v) : "***";
7256
+ } else if (kLower === "mac") {
7257
+ out[k] = typeof v === "string" ? maskMac(v) : "***";
7258
+ } else if (kLower === "ip" || kLower === "ipaddress" || kLower === "host") {
7259
+ out[k] = typeof v === "string" ? maskIp(v) : v;
7260
+ } else if (kLower === "name" && typeof v === "string" && k !== "name") {
7261
+ out[k] = v;
7262
+ } else {
7263
+ out[k] = sanitizeFixtureData(v);
7264
+ }
7265
+ }
7266
+ return out;
7267
+ }
7268
+ return value;
7269
+ }
7270
+ function computeExpectedStreamCompatibility(params) {
7271
+ const { channelCount } = params;
7272
+ const profiles = params.profiles ?? ["main", "sub", "ext"];
7273
+ const expectedStreamType = { main: 0, sub: 1, ext: 0 };
7274
+ const allStreams = [];
7275
+ for (let ch = 0; ch < channelCount; ch++) {
7276
+ for (const p of profiles) {
7277
+ allStreams.push({ ch, profile: p, label: channelCount > 1 ? `ch${ch}_${p}` : p });
7278
+ }
7279
+ }
7280
+ const results = [];
7281
+ for (let i = 0; i < allStreams.length; i++) {
7282
+ for (let j = i + 1; j < allStreams.length; j++) {
7283
+ const a = allStreams[i];
7284
+ const b = allStreams[j];
7285
+ const stA = expectedStreamType[a.profile] ?? 0;
7286
+ const stB = expectedStreamType[b.profile] ?? 0;
7287
+ const sameChannel = a.ch === b.ch;
7288
+ let expectedOk;
7289
+ let reason;
7290
+ if (sameChannel && stA === stB) {
7291
+ expectedOk = false;
7292
+ reason = `same streamType (${stA}) on same channel`;
7293
+ } else if (!sameChannel && a.profile === b.profile) {
7294
+ expectedOk = false;
7295
+ reason = `multifocal rejects same profile (${a.profile}) across channels`;
7296
+ } else if (!sameChannel && stA === stB) {
7297
+ expectedOk = false;
7298
+ reason = `same streamType (${stA}) across channels`;
7299
+ } else {
7300
+ expectedOk = true;
7301
+ reason = `different streamTypes (${stA} vs ${stB})`;
7302
+ }
7303
+ results.push({ pair: [a.label, b.label], expectedOk, reason });
7304
+ }
7305
+ }
7306
+ return results;
7307
+ }
7308
+ async function captureModelFixtures(params) {
7309
+ const { api, channel, outDir } = params;
7310
+ const log = params.log ?? console.log;
7311
+ mkdirp(outDir);
7312
+ const writeJsonSafe = (filePath, data) => writeJson(filePath, sanitizeFixtureData(data));
7313
+ const writeTextSafe = (filePath, text) => writeText(filePath, sanitizeString(text));
7314
+ const calls = {};
7315
+ const errors = [];
7316
+ async function capture(name, fn, writer) {
7317
+ try {
7318
+ const value = await fn();
7319
+ calls[name] = { ok: true, value };
7320
+ if (writer && value !== void 0 && value !== null) {
7321
+ writer(value);
7322
+ }
7323
+ log(` \u2713 ${name}`);
7324
+ return value;
7325
+ } catch (e) {
7326
+ const msg = e instanceof Error ? e.message : String(e);
7327
+ calls[name] = { ok: false, error: msg };
7328
+ errors.push(`${name}: ${msg}`);
7329
+ log(` \u2717 ${name}: ${msg}`);
7330
+ return void 0;
7331
+ }
7332
+ }
7333
+ const info = await capture(
7334
+ "getInfo",
7335
+ () => api.getInfo(channel),
7336
+ (v) => writeJsonSafe(path4.join(outDir, "device-info.json"), v)
7337
+ );
7338
+ const support = await capture(
7339
+ "getSupportInfo",
7340
+ () => api.getSupportInfo(),
7341
+ (v) => writeJsonSafe(path4.join(outDir, "support-info.json"), v)
7342
+ );
7343
+ const abilities = await capture(
7344
+ "getAbilityInfo",
7345
+ () => api.getAbilityInfo(),
7346
+ (v) => writeJsonSafe(path4.join(outDir, "ability-info.json"), v)
7347
+ );
7348
+ await capture(
7349
+ "getDeviceCapabilities",
7350
+ () => api.getDeviceCapabilities(channel),
7351
+ (v) => writeJsonSafe(path4.join(outDir, "capabilities.json"), v)
7352
+ );
7353
+ await capture("cmd289-WhiteLed", () => api.sendXml({
7354
+ cmdId: BC_CMD_ID_GET_WHITE_LED,
7355
+ channel,
7356
+ timeoutMs: 3e3
7357
+ }), (v) => writeTextSafe(path4.join(outDir, "cmd289-white-led.xml"), v));
7358
+ await capture(
7359
+ "getStreamMetadata",
7360
+ () => api.getStreamMetadata(channel),
7361
+ (v) => writeJsonSafe(path4.join(outDir, "stream-metadata.json"), v)
7362
+ );
7363
+ await capture(
7364
+ "getEncXml",
7365
+ () => api.getEncXml(channel),
7366
+ (v) => writeTextSafe(path4.join(outDir, "enc-config.xml"), v)
7367
+ );
7368
+ await capture(
7369
+ "getPorts",
7370
+ () => api.getPorts(),
7371
+ (v) => writeJsonSafe(path4.join(outDir, "ports.json"), v)
7372
+ );
7373
+ await capture(
7374
+ "getTalkAbility",
7375
+ () => api.getTalkAbility(channel),
7376
+ (v) => writeJsonSafe(path4.join(outDir, "talk-ability.json"), v)
7377
+ );
7378
+ await capture(
7379
+ "getTwoWayAudioConfig",
7380
+ () => api.getTwoWayAudioConfig(channel),
7381
+ (v) => writeJsonSafe(path4.join(outDir, "two-way-audio-config.json"), v)
7382
+ );
7383
+ await capture(
7384
+ "getAiState",
7385
+ () => api.getAiState(channel),
7386
+ (v) => writeJsonSafe(path4.join(outDir, "ai-state.json"), v)
7387
+ );
7388
+ await capture(
7389
+ "getAiCfg",
7390
+ () => api.getAiCfg(channel),
7391
+ (v) => writeJsonSafe(path4.join(outDir, "ai-cfg.json"), v)
7392
+ );
7393
+ await capture(
7394
+ "getOsd",
7395
+ () => api.getOsd(channel),
7396
+ (v) => writeJsonSafe(path4.join(outDir, "osd.json"), v)
7397
+ );
7398
+ await capture(
7399
+ "getMotionAlarm",
7400
+ () => api.getMotionAlarm(channel),
7401
+ (v) => writeJsonSafe(path4.join(outDir, "motion-alarm.json"), v)
7402
+ );
7403
+ await capture(
7404
+ "getRecordCfg",
7405
+ () => api.getRecordCfg(channel),
7406
+ (v) => writeJsonSafe(path4.join(outDir, "record-cfg.json"), v)
7407
+ );
7408
+ await capture(
7409
+ "getVideoInput",
7410
+ () => api.getVideoInput(channel),
7411
+ (v) => writeJsonSafe(path4.join(outDir, "video-input.json"), v)
7412
+ );
7413
+ await capture(
7414
+ "getPtzPresets",
7415
+ () => api.getPtzPresets(channel),
7416
+ (v) => writeJsonSafe(path4.join(outDir, "ptz-presets.json"), v)
7417
+ );
7418
+ await capture(
7419
+ "getNetworkInfo",
7420
+ () => api.getNetworkInfo(),
7421
+ (v) => writeJsonSafe(path4.join(outDir, "network-info.json"), v)
7422
+ );
7423
+ await capture(
7424
+ "getSystemGeneral",
7425
+ () => api.getSystemGeneral(),
7426
+ (v) => writeJsonSafe(path4.join(outDir, "system-general.json"), v)
7427
+ );
7428
+ await capture(
7429
+ "getWifiSignal",
7430
+ () => api.getWifiSignal(channel),
7431
+ (v) => writeJsonSafe(path4.join(outDir, "wifi-signal.json"), v)
7432
+ );
7433
+ await capture(
7434
+ "getWhiteLedState",
7435
+ () => api.getWhiteLedState(channel),
7436
+ (v) => writeJsonSafe(path4.join(outDir, "white-led-state.json"), v)
7437
+ );
7438
+ await capture(
7439
+ "getFloodlightOnMotion",
7440
+ () => api.getFloodlightOnMotion(channel),
7441
+ (v) => writeJsonSafe(path4.join(outDir, "floodlight-on-motion.json"), v)
7442
+ );
7443
+ await capture(
7444
+ "buildVideoStreamOptions",
7445
+ () => api.buildVideoStreamOptions({ channel }),
7446
+ (v) => writeJsonSafe(path4.join(outDir, "video-stream-options.json"), v)
7447
+ );
7448
+ await capture(
7449
+ "getDualLensChannelInfo",
7450
+ () => api.getDualLensChannelInfo(channel),
7451
+ (v) => writeJsonSafe(path4.join(outDir, "dual-lens-info.json"), v)
7452
+ );
7453
+ await capture("streamCombinationTest", async () => {
7454
+ let dualLensInfo;
7455
+ try {
7456
+ dualLensInfo = await api.getDualLensChannelInfo(channel);
7457
+ } catch {
7458
+ }
7459
+ const isMultifocal = dualLensInfo?.isDualLens === true;
7460
+ const channelCount = dualLensInfo?.streamChannelCount ?? 1;
7461
+ const allStreams = [];
7462
+ const profiles = ["main", "sub", "ext"];
7463
+ for (let ch = 0; ch < channelCount; ch++) {
7464
+ for (const p of profiles) {
7465
+ const label = channelCount > 1 ? `ch${ch}_${p}` : p;
7466
+ allStreams.push({ ch, profile: p, label });
7467
+ }
7468
+ }
7469
+ const pairs = [];
7470
+ for (let i = 0; i < allStreams.length; i++) {
7471
+ for (let j = i + 1; j < allStreams.length; j++) {
7472
+ pairs.push([allStreams[i], allStreams[j]]);
7473
+ }
7474
+ }
7475
+ const expectedStreamType = { main: 0, sub: 1, ext: 0 };
7476
+ const expectedCompat = [];
7477
+ for (const [a, b] of pairs) {
7478
+ const stA = expectedStreamType[a.profile];
7479
+ const stB = expectedStreamType[b.profile];
7480
+ const sameChannel = a.ch === b.ch;
7481
+ let expectedOk;
7482
+ let reason;
7483
+ if (sameChannel && stA === stB) {
7484
+ expectedOk = false;
7485
+ reason = `same streamType (${stA}) on same channel`;
7486
+ } else if (!sameChannel && a.profile === b.profile) {
7487
+ expectedOk = false;
7488
+ reason = `multifocal rejects same profile (${a.profile}) across channels`;
7489
+ } else if (!sameChannel && stA === stB) {
7490
+ expectedOk = false;
7491
+ reason = `same streamType (${stA}) across channels`;
7492
+ } else {
7493
+ expectedOk = true;
7494
+ reason = `different streamTypes (${stA} vs ${stB})`;
7495
+ }
7496
+ expectedCompat.push({ pair: [a.label, b.label], expectedOk, reason });
7497
+ }
7498
+ const results = [];
7499
+ const TEST_DURATION_MS = 4e3;
7500
+ for (let pairIdx = 0; pairIdx < pairs.length; pairIdx++) {
7501
+ const [a, b] = pairs[pairIdx];
7502
+ const expected = expectedCompat[pairIdx];
7503
+ log(` testing ${a.label}+${b.label} on shared socket...`);
7504
+ let session;
7505
+ try {
7506
+ session = await api.createDedicatedSession(
7507
+ `test:combo:${a.label}_${b.label}`
7508
+ );
7509
+ } catch (e) {
7510
+ const result2 = {
7511
+ pair: [a.label, b.label],
7512
+ ok: false,
7513
+ framesA: 0,
7514
+ framesB: 0,
7515
+ mismatches: 0,
7516
+ error: `session: ${e instanceof Error ? e.message : String(e)}`,
7517
+ durationMs: 0,
7518
+ expectedOk: expected.expectedOk,
7519
+ expectedReason: expected.reason,
7520
+ matchesExpected: !expected.expectedOk
7521
+ // failed as expected if we expected failure
7522
+ };
7523
+ results.push(result2);
7524
+ continue;
7525
+ }
7526
+ const testClient = session.client;
7527
+ let framesA = 0;
7528
+ let framesB = 0;
7529
+ let mismatches = 0;
7530
+ const start = Date.now();
7531
+ const stTypes = {
7532
+ main: /* @__PURE__ */ new Set([0, 2]),
7533
+ sub: /* @__PURE__ */ new Set([1, 3]),
7534
+ ext: /* @__PURE__ */ new Set([0, 2])
7535
+ };
7536
+ const setA = stTypes[a.profile];
7537
+ const setB = stTypes[b.profile];
7538
+ const onFrame = (frame) => {
7539
+ if (frame.header?.cmdId !== BC_CMD_ID_VIDEO) return;
7540
+ const st = frame.header.streamType;
7541
+ if (setA.has(st)) framesA++;
7542
+ else if (setB.has(st)) framesB++;
7543
+ else mismatches++;
7544
+ };
7545
+ testClient.on("frame", onFrame);
7546
+ let error;
7547
+ try {
7548
+ await api.startVideoStream(a.ch, a.profile, { client: testClient });
7549
+ await api.startVideoStream(b.ch, b.profile, { client: testClient });
7550
+ await new Promise((r) => setTimeout(r, TEST_DURATION_MS));
7551
+ await api.stopVideoStream(a.ch, a.profile, { client: testClient }).catch(() => {
7552
+ });
7553
+ await api.stopVideoStream(b.ch, b.profile, { client: testClient }).catch(() => {
7554
+ });
7555
+ } catch (e) {
7556
+ error = e instanceof Error ? e.message : String(e);
7557
+ } finally {
7558
+ testClient.removeListener("frame", onFrame);
7559
+ await session.release().catch(() => {
7560
+ });
7561
+ }
7562
+ const elapsed = Date.now() - start;
7563
+ const ok2 = !error && framesA > 0 && framesB > 0 && mismatches === 0;
7564
+ const result = {
7565
+ pair: [a.label, b.label],
7566
+ ok: ok2,
7567
+ framesA,
7568
+ framesB,
7569
+ mismatches,
7570
+ ...error ? { error } : {},
7571
+ durationMs: elapsed,
7572
+ expectedOk: expected.expectedOk,
7573
+ expectedReason: expected.reason,
7574
+ matchesExpected: ok2 === expected.expectedOk
7575
+ };
7576
+ results.push(result);
7577
+ const matchStr = result.matchesExpected ? "" : " *** UNEXPECTED ***";
7578
+ log(` ${a.label}+${b.label}: ${ok2 ? "OK" : "FAIL"} (expected=${expected.expectedOk ? "OK" : "FAIL"}) A=${framesA} B=${framesB} mismatch=${mismatches}${matchStr}`);
7579
+ }
7580
+ const unexpected = results.filter((r) => !r.matchesExpected);
7581
+ return {
7582
+ isMultifocal,
7583
+ channelCount,
7584
+ results,
7585
+ summary: {
7586
+ total: results.length,
7587
+ ok: results.filter((r) => r.ok).length,
7588
+ failed: results.filter((r) => !r.ok).length,
7589
+ matchesExpected: results.filter((r) => r.matchesExpected).length,
7590
+ unexpected: unexpected.map((r) => `${r.pair[0]}+${r.pair[1]}: got ${r.ok ? "OK" : "FAIL"}, expected ${r.expectedOk ? "OK" : "FAIL"}`)
7591
+ }
7592
+ };
7593
+ }, (v) => writeJsonSafe(path4.join(outDir, "stream-combination-test.json"), v));
7594
+ const total = Object.keys(calls).length;
7595
+ const ok = Object.values(calls).filter((c) => c.ok).length;
7596
+ const failed = total - ok;
7597
+ const summary = { total, ok, failed, errors };
7598
+ writeJsonSafe(path4.join(outDir, "_summary.json"), {
7599
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
7600
+ model: info?.type ?? "unknown",
7601
+ itemNo: info?.itemNo ?? "unknown",
7602
+ firmwareVersion: info?.firmwareVersion ?? "unknown",
7603
+ channel,
7604
+ ...summary,
7605
+ calls: Object.fromEntries(
7606
+ Object.entries(calls).map(([k, v]) => [
7607
+ k,
7608
+ v.ok ? "ok" : `FAILED: ${v.error}`
7609
+ ])
7610
+ )
7611
+ });
7612
+ log(`
7613
+ Summary: ${ok}/${total} ok, ${failed} failed`);
7614
+ if (errors.length) {
7615
+ log(` Errors:`);
7616
+ for (const err of errors) {
7617
+ log(` - ${err}`);
7618
+ }
7619
+ }
7620
+ return { calls, outDir, summary };
7621
+ }
7622
+ var fs4, path4, import_node_child_process2, import_node_path, REDACT_KEYS, MASK_KEYS, IPV4_RE, MAC_RE;
7212
7623
  var init_DiagnosticsTools = __esm({
7213
7624
  "src/debug/DiagnosticsTools.ts"() {
7214
7625
  "use strict";
@@ -7224,6 +7635,27 @@ var init_DiagnosticsTools = __esm({
7224
7635
  init_H265Converter();
7225
7636
  init_constants();
7226
7637
  init_xml();
7638
+ REDACT_KEYS = /* @__PURE__ */ new Set([
7639
+ "password",
7640
+ "pass",
7641
+ "token",
7642
+ "secret",
7643
+ "apiKey",
7644
+ "api_key"
7645
+ ]);
7646
+ MASK_KEYS = /* @__PURE__ */ new Set([
7647
+ "serialNumber",
7648
+ "serial",
7649
+ "uid",
7650
+ "mac",
7651
+ "ssid",
7652
+ "wifiPassword",
7653
+ "userName",
7654
+ "username",
7655
+ "user"
7656
+ ]);
7657
+ IPV4_RE = /\b(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\b/g;
7658
+ MAC_RE = /\b([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\b/g;
7227
7659
  }
7228
7660
  });
7229
7661
 
@@ -14680,7 +15112,7 @@ function computeDeviceCapabilities(params) {
14680
15112
  const ptzControlRaw = supportItem ? supportItem.ptzControl : void 0;
14681
15113
  const supportExplicitlyDefinesPtz = ptzTypeRaw !== void 0 || ptzControlRaw !== void 0;
14682
15114
  const ptzExplicitlyDisabledBySupportItem = supportExplicitlyDefinesPtz && !isTruthyNumberLike(ptzTypeRaw) && !isTruthyNumberLike(ptzControlRaw);
14683
- const hasPtzFromSupportItem = isTruthyNumberLike(ptzTypeRaw) || isTruthyNumberLike(ptzControlRaw) || isTruthyNumberLike(supportItem?.ptzPreset);
15115
+ const hasPtzFromSupportItem = isTruthyNumberLike(ptzTypeRaw);
14684
15116
  const ptzDisabledBySupport = (ptzMode === "none" || ptzMode === "0") && !hasPtzFromSupportItem;
14685
15117
  const hasBatteryFromSupport = supportItem ? isTruthyNumberLike(supportItem.battery) : false;
14686
15118
  const ptzPresetRaw = supportItem ? supportItem.ptzPreset : void 0;
@@ -14744,6 +15176,17 @@ function computeDeviceCapabilities(params) {
14744
15176
  if (ptzMode !== void 0) result.ptzMode = ptzMode;
14745
15177
  return result;
14746
15178
  }
15179
+ function xmlIndicatesFloodlight(xml) {
15180
+ if (/(<FloodlightTask\b|<FloodlightManual\b|<FloodlightStatusList\b)/i.test(
15181
+ xml
15182
+ )) {
15183
+ return true;
15184
+ }
15185
+ if (/<WhiteLed\b/i.test(xml)) {
15186
+ return /(<brightness_cur>|<bright>|<LightingSchedule\b)/i.test(xml);
15187
+ }
15188
+ return false;
15189
+ }
14747
15190
 
14748
15191
  // src/reolink/baichuan/utils/abilityInfo.ts
14749
15192
  init_xml();
@@ -23780,9 +24223,7 @@ ${stderr}`)
23780
24223
  `probeFloodlightSupportByCmd289: received XML for channel ${ch}:
23781
24224
  ${xml}`
23782
24225
  );
23783
- return /(<FloodlightTask\b|<FloodlightManual\b|<FloodlightStatusList\b|<WhiteLed\b)/i.test(
23784
- xml
23785
- );
24226
+ return xmlIndicatesFloodlight(xml);
23786
24227
  } catch {
23787
24228
  return false;
23788
24229
  }