@skrillex1224/playwright-toolkit 2.1.227 → 2.1.228

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/index.js CHANGED
@@ -439,6 +439,9 @@ function createInternalLogger(moduleName, explicitLogger) {
439
439
  };
440
440
  }
441
441
 
442
+ // src/internals/screenshot.js
443
+ import delay from "delay";
444
+
442
445
  // src/internals/viewport.js
443
446
  var toPositiveInt = (value) => {
444
447
  const number = Math.round(Number(value) || 0);
@@ -472,11 +475,18 @@ var DEFAULT_TIMEOUT_MS = 5e3;
472
475
  var FORCED_FULLPAGE_TYPE = "jpeg";
473
476
  var FORCED_FULLPAGE_QUALITY = 50;
474
477
  var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
478
+ var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
479
+ var DEFAULT_MAX_HEIGHT = 8e3;
480
+ var DEFAULT_SETTLE_MS = 1e3;
475
481
  var toPositiveNumber = (value, fallback = 0) => {
476
482
  const n = Number(value);
477
483
  if (!Number.isFinite(n) || n <= 0) return fallback;
478
484
  return n;
479
485
  };
486
+ var toPositiveInteger = (value, fallback = 0) => {
487
+ const number = Math.round(Number(value) || 0);
488
+ return number > 0 ? number : fallback;
489
+ };
480
490
  var normalizeType = (value) => {
481
491
  const raw = String(value || "png").trim().toLowerCase();
482
492
  if (!SUPPORTED_TYPES.has(raw)) return "png";
@@ -505,6 +515,138 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
505
515
  scale: 1
506
516
  };
507
517
  };
518
+ var expandScrollableContent = async (page, options = {}) => {
519
+ return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
520
+ const body = document.body;
521
+ const root = document.documentElement;
522
+ const scrollingElement = document.scrollingElement;
523
+ const candidates = [];
524
+ const seen = /* @__PURE__ */ new Set();
525
+ let maxHeight = window.innerHeight || 0;
526
+ const pushCandidate = (el) => {
527
+ if (!el || seen.has(el)) return;
528
+ seen.add(el);
529
+ candidates.push(el);
530
+ };
531
+ pushCandidate(scrollingElement);
532
+ pushCandidate(root);
533
+ pushCandidate(body);
534
+ document.querySelectorAll("*").forEach(pushCandidate);
535
+ const isDocumentElement = (el) => el === root || el === body || el === scrollingElement;
536
+ const isVisible = (el, style, rect) => {
537
+ if (!el || !style || !rect) return false;
538
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
539
+ return false;
540
+ }
541
+ if (Number(style.opacity) === 0) return false;
542
+ return rect.width > 0 && rect.height > 0;
543
+ };
544
+ const isScrollableY = (el, style) => {
545
+ if (!el || el.scrollHeight <= el.clientHeight + 1) {
546
+ return false;
547
+ }
548
+ if (isDocumentElement(el)) {
549
+ return true;
550
+ }
551
+ const overflowY = String(style.overflowY || "").toLowerCase();
552
+ const overflow = String(style.overflow || "").toLowerCase();
553
+ const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
554
+ return scrollableOverflow.has(overflowY) || scrollableOverflow.has(overflow);
555
+ };
556
+ candidates.forEach((el) => {
557
+ const style = window.getComputedStyle(el);
558
+ const rect = el.getBoundingClientRect();
559
+ if (visibleOnly && !isVisible(el, style, rect)) {
560
+ return;
561
+ }
562
+ if (!isScrollableY(el, style)) {
563
+ return;
564
+ }
565
+ const scrollHeight = Math.ceil(el.scrollHeight || 0);
566
+ if (scrollHeight <= 0) {
567
+ return;
568
+ }
569
+ if (scrollHeight > maxHeight) {
570
+ maxHeight = scrollHeight;
571
+ }
572
+ if (isDocumentElement(el)) {
573
+ return;
574
+ }
575
+ if (!el.classList.contains(className)) {
576
+ el.dataset.pkOrigOverflow = el.style.overflow;
577
+ el.dataset.pkOrigOverflowPriority = el.style.getPropertyPriority("overflow") || "";
578
+ el.dataset.pkOrigHeight = el.style.height;
579
+ el.dataset.pkOrigHeightPriority = el.style.getPropertyPriority("height") || "";
580
+ el.dataset.pkOrigMinHeight = el.style.minHeight;
581
+ el.dataset.pkOrigMinHeightPriority = el.style.getPropertyPriority("min-height") || "";
582
+ el.dataset.pkOrigMaxHeight = el.style.maxHeight;
583
+ el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
584
+ el.classList.add(className);
585
+ }
586
+ if (forceScrollableHeight) {
587
+ el.style.setProperty("overflow", "visible", "important");
588
+ el.style.setProperty("height", `${scrollHeight}px`, "important");
589
+ el.style.setProperty("min-height", `${scrollHeight}px`, "important");
590
+ el.style.setProperty("max-height", "none", "important");
591
+ return;
592
+ }
593
+ el.style.overflow = "visible";
594
+ el.style.height = "auto";
595
+ el.style.maxHeight = "none";
596
+ });
597
+ return maxHeight;
598
+ }, {
599
+ className: EXPANDED_SCROLLABLE_CLASS,
600
+ forceScrollableHeight: Boolean(options.forceScrollableHeight),
601
+ visibleOnly: options.visibleOnly !== false
602
+ });
603
+ };
604
+ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
605
+ const originalViewport = await resolveCurrentViewportSize(page);
606
+ const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
607
+ const buffer = options.buffer ?? defaultBuffer;
608
+ const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
609
+ const settleMs = Math.max(0, Number(options.settleMs ?? DEFAULT_SETTLE_MS) || 0);
610
+ const maxScrollHeight = await expandScrollableContent(page, {
611
+ forceScrollableHeight: options.forceScrollableHeight,
612
+ visibleOnly: options.visibleOnly !== false
613
+ });
614
+ const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
615
+ await page.setViewportSize({
616
+ width: originalViewport.width,
617
+ height: targetHeight
618
+ });
619
+ if (settleMs > 0) {
620
+ await delay(settleMs);
621
+ }
622
+ return {
623
+ originalViewport,
624
+ maxScrollHeight,
625
+ targetHeight
626
+ };
627
+ };
628
+ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
629
+ await page.evaluate((className) => {
630
+ document.querySelectorAll(`.${className}`).forEach((el) => {
631
+ el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
632
+ el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
633
+ el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
634
+ el.style.setProperty("max-height", el.dataset.pkOrigMaxHeight || "", el.dataset.pkOrigMaxHeightPriority || "");
635
+ delete el.dataset.pkOrigOverflow;
636
+ delete el.dataset.pkOrigOverflowPriority;
637
+ delete el.dataset.pkOrigHeight;
638
+ delete el.dataset.pkOrigHeightPriority;
639
+ delete el.dataset.pkOrigMinHeight;
640
+ delete el.dataset.pkOrigMinHeightPriority;
641
+ delete el.dataset.pkOrigMaxHeight;
642
+ delete el.dataset.pkOrigMaxHeightPriority;
643
+ el.classList.remove(className);
644
+ });
645
+ }, EXPANDED_SCROLLABLE_CLASS);
646
+ if (state?.originalViewport) {
647
+ await page.setViewportSize(state.originalViewport);
648
+ }
649
+ };
508
650
  var capturePageScreenshot = async (page, options = {}) => {
509
651
  const fullPage = Boolean(options.fullPage);
510
652
  const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
@@ -558,6 +700,22 @@ var capturePageScreenshot = async (page, options = {}) => {
558
700
  return await page.screenshot(fallbackOptions);
559
701
  }
560
702
  };
703
+ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
704
+ const state = await prepareExpandedFullPageScreenshot(page, options);
705
+ try {
706
+ return await capturePageScreenshot(page, {
707
+ fullPage: true,
708
+ type: options.type || "png",
709
+ quality: options.quality,
710
+ timeout: options.timeout,
711
+ maxClipHeight: state.targetHeight
712
+ });
713
+ } finally {
714
+ if (options.restore) {
715
+ await restoreExpandedFullPageScreenshot(page, state);
716
+ }
717
+ }
718
+ };
561
719
 
562
720
  // src/errors.js
563
721
  var errors_exports = {};
@@ -2096,7 +2254,7 @@ var AntiCheat = {
2096
2254
  };
2097
2255
 
2098
2256
  // src/internals/humanize/desktop.js
2099
- import delay from "delay";
2257
+ import delay2 from "delay";
2100
2258
  import { createCursor } from "ghost-cursor-playwright";
2101
2259
  var logger6 = createInternalLogger("Humanize");
2102
2260
  var $CursorWeakMap = /* @__PURE__ */ new WeakMap();
@@ -2328,7 +2486,7 @@ var Humanize = {
2328
2486
  }
2329
2487
  await page.mouse.wheel(0, deltaY);
2330
2488
  didScroll = true;
2331
- await delay(this.jitterMs(20 + Math.random() * 40, 0.2));
2489
+ await delay2(this.jitterMs(20 + Math.random() * 40, 0.2));
2332
2490
  }
2333
2491
  logger6.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
2334
2492
  return { element, didScroll };
@@ -2357,7 +2515,7 @@ var Humanize = {
2357
2515
  restoreOnce.restored = true;
2358
2516
  if (typeof restoreOnce.do !== "function") return;
2359
2517
  try {
2360
- await delay(this.jitterMs(1e3));
2518
+ await delay2(this.jitterMs(1e3));
2361
2519
  await restoreOnce.do();
2362
2520
  } catch (restoreError) {
2363
2521
  logger6.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
@@ -2365,7 +2523,7 @@ var Humanize = {
2365
2523
  };
2366
2524
  try {
2367
2525
  if (target == null) {
2368
- await delay(this.jitterMs(reactionDelay, 0.4));
2526
+ await delay2(this.jitterMs(reactionDelay, 0.4));
2369
2527
  await cursor.actions.click();
2370
2528
  logger6.success("humanClick", "Clicked current position");
2371
2529
  return true;
@@ -2399,7 +2557,7 @@ var Humanize = {
2399
2557
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.3;
2400
2558
  const y = box.y + box.height / 2 + (Math.random() - 0.5) * box.height * 0.3;
2401
2559
  await cursor.actions.move({ x, y });
2402
- await delay(this.jitterMs(reactionDelay, 0.4));
2560
+ await delay2(this.jitterMs(reactionDelay, 0.4));
2403
2561
  await cursor.actions.click();
2404
2562
  await restoreOnce();
2405
2563
  logger6.success("humanClick");
@@ -2418,7 +2576,7 @@ var Humanize = {
2418
2576
  async randomSleep(baseMs, jitterPercent = 0.3) {
2419
2577
  const ms = this.jitterMs(baseMs, jitterPercent);
2420
2578
  logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
2421
- await delay(ms);
2579
+ await delay2(ms);
2422
2580
  logger6.success("randomSleep");
2423
2581
  },
2424
2582
  /**
@@ -2436,7 +2594,7 @@ var Humanize = {
2436
2594
  const x = 100 + Math.random() * (viewportSize.width - 200);
2437
2595
  const y = 100 + Math.random() * (viewportSize.height - 200);
2438
2596
  await cursor.actions.move({ x, y });
2439
- await delay(this.jitterMs(600, 0.5));
2597
+ await delay2(this.jitterMs(600, 0.5));
2440
2598
  }
2441
2599
  logger6.success("simulateGaze");
2442
2600
  },
@@ -2460,7 +2618,7 @@ var Humanize = {
2460
2618
  try {
2461
2619
  const locator = page.locator(selector);
2462
2620
  await Humanize.humanClick(page, locator);
2463
- await delay(this.jitterMs(200, 0.4));
2621
+ await delay2(this.jitterMs(200, 0.4));
2464
2622
  for (let i = 0; i < text.length; i++) {
2465
2623
  const char = text[i];
2466
2624
  let charDelay;
@@ -2472,11 +2630,11 @@ var Humanize = {
2472
2630
  charDelay = this.jitterMs(baseDelay, 0.4);
2473
2631
  }
2474
2632
  await page.keyboard.type(char);
2475
- await delay(charDelay);
2633
+ await delay2(charDelay);
2476
2634
  if (Math.random() < pauseProbability && i < text.length - 1) {
2477
2635
  const pauseTime = this.jitterMs(pauseBase, 0.5);
2478
2636
  logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
2479
- await delay(pauseTime);
2637
+ await delay2(pauseTime);
2480
2638
  }
2481
2639
  }
2482
2640
  logger6.success("humanType");
@@ -2510,7 +2668,7 @@ var Humanize = {
2510
2668
  if (hasTarget) {
2511
2669
  await this.humanClick(page, targetOrKey, { reactionDelay: focusDelay, scrollIfNeeded, throwOnMissing });
2512
2670
  }
2513
- await delay(this.jitterMs(reactionDelay, 0.45));
2671
+ await delay2(this.jitterMs(reactionDelay, 0.45));
2514
2672
  await page.keyboard.press(key, {
2515
2673
  ...keyboardOptions,
2516
2674
  delay: this.jitterMs(holdDelay, 0.5)
@@ -2532,14 +2690,14 @@ var Humanize = {
2532
2690
  try {
2533
2691
  const locator = page.locator(selector);
2534
2692
  await locator.click();
2535
- await delay(this.jitterMs(200, 0.4));
2693
+ await delay2(this.jitterMs(200, 0.4));
2536
2694
  const currentValue = await locator.inputValue();
2537
2695
  if (!currentValue || currentValue.length === 0) {
2538
2696
  logger6.success("humanClear", "already empty");
2539
2697
  return;
2540
2698
  }
2541
2699
  await page.keyboard.press("Meta+A");
2542
- await delay(this.jitterMs(100, 0.4));
2700
+ await delay2(this.jitterMs(100, 0.4));
2543
2701
  await page.keyboard.press("Backspace");
2544
2702
  logger6.success("humanClear");
2545
2703
  } catch (error) {
@@ -2565,13 +2723,13 @@ var Humanize = {
2565
2723
  const x = 100 + Math.random() * (viewportSize.width - 200);
2566
2724
  const y = 100 + Math.random() * (viewportSize.height - 200);
2567
2725
  await cursor.actions.move({ x, y });
2568
- await delay(this.jitterMs(350, 0.4));
2726
+ await delay2(this.jitterMs(350, 0.4));
2569
2727
  } else if (action < 0.7) {
2570
2728
  const scrollY = (Math.random() - 0.5) * 200;
2571
2729
  await page.mouse.wheel(0, scrollY);
2572
- await delay(this.jitterMs(500, 0.4));
2730
+ await delay2(this.jitterMs(500, 0.4));
2573
2731
  } else {
2574
- await delay(this.jitterMs(800, 0.5));
2732
+ await delay2(this.jitterMs(800, 0.5));
2575
2733
  }
2576
2734
  }
2577
2735
  logger6.success("warmUpBrowsing");
@@ -2600,7 +2758,7 @@ var Humanize = {
2600
2758
  const scrollAmount = stepDistance * factor * sign * jitter;
2601
2759
  await page.mouse.wheel(0, scrollAmount);
2602
2760
  const baseDelay = 60 + i * 25;
2603
- await delay(this.jitterMs(baseDelay, 0.3));
2761
+ await delay2(this.jitterMs(baseDelay, 0.3));
2604
2762
  }
2605
2763
  logger6.success("naturalScroll");
2606
2764
  } catch (error) {
@@ -2746,7 +2904,7 @@ var MachineHumanize = {
2746
2904
  };
2747
2905
 
2748
2906
  // src/internals/humanize/shared.js
2749
- import delay2 from "delay";
2907
+ import delay3 from "delay";
2750
2908
  var jitterMs = (base, jitterPercent = 0.3) => {
2751
2909
  const jitter = Number(base || 0) * Number(jitterPercent || 0) * (Math.random() * 2 - 1);
2752
2910
  return Math.max(10, Math.round(Number(base || 0) + jitter));
@@ -2772,7 +2930,7 @@ var resolveElement = async (page, target, { throwOnMissing = true } = {}) => {
2772
2930
  }
2773
2931
  return element;
2774
2932
  };
2775
- var waitJitter = (base, jitterPercent = 0.3) => delay2(jitterMs(base, jitterPercent));
2933
+ var waitJitter = (base, jitterPercent = 0.3) => delay3(jitterMs(base, jitterPercent));
2776
2934
 
2777
2935
  // src/internals/humanize/mobile.js
2778
2936
  var logger7 = createInternalLogger("Humanize.Mobile");
@@ -3573,8 +3731,8 @@ var callDelegate = (method, page, args) => {
3573
3731
  return delegate[method](page, ...args);
3574
3732
  };
3575
3733
  var Humanize2 = {
3576
- // M = Machine: native/mechanical operations for compatibility paths.
3577
- // These APIs intentionally do not humanize timing, motion, or intent.
3734
+ // M = Machine: native/mechanical operations for兼容路径。
3735
+ // 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
3578
3736
  M: MachineHumanize,
3579
3737
  jitterMs(base, jitterPercent = 0.3) {
3580
3738
  return Humanize.jitterMs(base, jitterPercent);
@@ -6081,7 +6239,7 @@ var Logger = {
6081
6239
  };
6082
6240
 
6083
6241
  // src/share.js
6084
- import delay3 from "delay";
6242
+ import delay4 from "delay";
6085
6243
 
6086
6244
  // src/internals/watermarkify.js
6087
6245
  var DEFAULT_TIMEZONE_OFFSET = 8;
@@ -6115,6 +6273,18 @@ var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
6115
6273
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
6116
6274
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
6117
6275
  var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
6276
+ var MOBILE_STRIP_HEIGHT = 104;
6277
+ var MOBILE_STRIP_PADDING_X = 14;
6278
+ var MOBILE_STRIP_PADDING_Y = 13;
6279
+ var MOBILE_STRIP_ROW_HEIGHT = 22;
6280
+ var MOBILE_STRIP_ROW_GAP = 7;
6281
+ var MOBILE_STRIP_LABEL_FONT_SIZE = 12.5;
6282
+ var MOBILE_STRIP_VALUE_FONT_SIZE = 13.5;
6283
+ var MOBILE_STRIP_LABEL_WIDTH = 45;
6284
+ var MOBILE_STRIP_PROMPT_LABEL_WIDTH = 60;
6285
+ var MOBILE_STRIP_LOC_LABEL_WIDTH = 30;
6286
+ var MOBILE_STRIP_IP_LABEL_WIDTH = 22;
6287
+ var MOBILE_STRIP_META_GAP = 12;
6118
6288
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
6119
6289
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
6120
6290
  /(?:中国)?移动$/i,
@@ -6899,10 +7069,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
6899
7069
  }),
6900
7070
  watermark: options.watermark,
6901
7071
  strip: options.strip,
6902
- stripLogoSrc
7072
+ stripLogoSrc,
7073
+ device: resolvePageDevice(page)
6903
7074
  };
6904
7075
  };
6905
7076
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7077
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7078
+ var findStripSegment = (segments, kind) => {
7079
+ const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7080
+ return found && typeof found === "object" ? found : {};
7081
+ };
6906
7082
  var buildStripSegmentLayout = (segment, options = {}) => {
6907
7083
  const label = normalizeWhitespace(segment?.label || "");
6908
7084
  const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
@@ -7230,6 +7406,116 @@ var renderStripDivider = (x, centerY, height) => {
7230
7406
  />
7231
7407
  `;
7232
7408
  };
7409
+ var renderMobileStripText = ({
7410
+ label,
7411
+ value,
7412
+ labelX,
7413
+ y,
7414
+ valueWidth,
7415
+ labelWidth = MOBILE_STRIP_LABEL_WIDTH,
7416
+ fontFamily
7417
+ }) => {
7418
+ const safeLabel = normalizeWhitespace(label) || "-";
7419
+ const safeValue = fitTextWithEllipsis(
7420
+ Array.from(normalizeWhitespace(value) || "-"),
7421
+ Math.max(18, valueWidth),
7422
+ MOBILE_STRIP_VALUE_FONT_SIZE
7423
+ );
7424
+ return `
7425
+ <text
7426
+ x="${labelX}"
7427
+ y="${y}"
7428
+ fill="#111111"
7429
+ fill-opacity="0.54"
7430
+ font-family="${fontFamily}"
7431
+ font-size="${MOBILE_STRIP_LABEL_FONT_SIZE}"
7432
+ font-weight="650"
7433
+ dominant-baseline="middle"
7434
+ >${escapeXml(safeLabel)}</text>
7435
+ <text
7436
+ x="${labelX + labelWidth}"
7437
+ y="${y}"
7438
+ fill="#111111"
7439
+ font-family="${fontFamily}"
7440
+ font-size="${MOBILE_STRIP_VALUE_FONT_SIZE}"
7441
+ font-weight="730"
7442
+ dominant-baseline="middle"
7443
+ >${escapeXml(safeValue)}</text>
7444
+ `;
7445
+ };
7446
+ var renderMobileStrip = ({ meta, width, height, fontFamily }) => {
7447
+ const stripHeight = MOBILE_STRIP_HEIGHT;
7448
+ const stripY = height - stripHeight;
7449
+ const contentX = MOBILE_STRIP_PADDING_X;
7450
+ const contentWidth = Math.max(1, width - MOBILE_STRIP_PADDING_X * 2);
7451
+ const prompt = findStripSegment(meta.stripSegments, "prompt");
7452
+ const time = findStripSegment(meta.stripSegments, "time");
7453
+ const location = findStripSegment(meta.stripSegments, "location");
7454
+ const ip = findStripSegment(meta.stripSegments, "ip");
7455
+ const row1Y = stripY + MOBILE_STRIP_PADDING_Y + MOBILE_STRIP_ROW_HEIGHT / 2;
7456
+ const row2Y = row1Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7457
+ const row3Y = row2Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7458
+ const promptValueWidth = contentWidth - MOBILE_STRIP_PROMPT_LABEL_WIDTH;
7459
+ const locValueX = contentX + MOBILE_STRIP_LOC_LABEL_WIDTH;
7460
+ const ipLabelX = Math.min(
7461
+ width - MOBILE_STRIP_PADDING_X - MOBILE_STRIP_IP_LABEL_WIDTH - 70,
7462
+ Math.max(
7463
+ locValueX + 80 + MOBILE_STRIP_META_GAP,
7464
+ contentX + Math.round(contentWidth * 0.52)
7465
+ )
7466
+ );
7467
+ const locValueWidth = Math.max(
7468
+ 28,
7469
+ ipLabelX - locValueX - MOBILE_STRIP_META_GAP
7470
+ );
7471
+ const ipValueWidth = Math.max(
7472
+ 28,
7473
+ width - MOBILE_STRIP_PADDING_X - (ipLabelX + MOBILE_STRIP_IP_LABEL_WIDTH)
7474
+ );
7475
+ return `
7476
+ <g id="strip">
7477
+ <rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
7478
+ <rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
7479
+ <rect x="${contentX}" y="${stripY}" width="${Math.max(96, Math.round(width * 0.36))}" height="2" fill="url(#stripAccent)" />
7480
+ ${renderMobileStripText({
7481
+ label: "Prompt",
7482
+ value: prompt.rawValue || prompt.value || "-",
7483
+ labelX: contentX,
7484
+ y: row1Y,
7485
+ valueWidth: promptValueWidth,
7486
+ labelWidth: MOBILE_STRIP_PROMPT_LABEL_WIDTH,
7487
+ fontFamily
7488
+ })}
7489
+ ${renderMobileStripText({
7490
+ label: "Time",
7491
+ value: time.rawValue || time.value || "-",
7492
+ labelX: contentX,
7493
+ y: row2Y,
7494
+ valueWidth: promptValueWidth,
7495
+ labelWidth: MOBILE_STRIP_LABEL_WIDTH,
7496
+ fontFamily
7497
+ })}
7498
+ ${renderMobileStripText({
7499
+ label: "Loc",
7500
+ value: location.rawValue || location.value || "-",
7501
+ labelX: contentX,
7502
+ y: row3Y,
7503
+ valueWidth: locValueWidth,
7504
+ labelWidth: MOBILE_STRIP_LOC_LABEL_WIDTH,
7505
+ fontFamily
7506
+ })}
7507
+ ${renderMobileStripText({
7508
+ label: "IP",
7509
+ value: ip.rawValue || ip.value || "-",
7510
+ labelX: ipLabelX,
7511
+ y: row3Y,
7512
+ valueWidth: ipValueWidth,
7513
+ labelWidth: MOBILE_STRIP_IP_LABEL_WIDTH,
7514
+ fontFamily
7515
+ })}
7516
+ </g>
7517
+ `;
7518
+ };
7233
7519
  var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7234
7520
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
7235
7521
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
@@ -7278,6 +7564,27 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7278
7564
  parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
7279
7565
  }
7280
7566
  if (hasStrip) {
7567
+ if (normalizeDevice(meta.device) === Device.Mobile) {
7568
+ parts.push(renderMobileStrip({
7569
+ meta,
7570
+ width,
7571
+ height,
7572
+ fontFamily
7573
+ }));
7574
+ return `
7575
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7576
+ <defs>
7577
+ <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7578
+ <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
7579
+ <stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
7580
+ <stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
7581
+ <stop offset="100%" stop-color="#111111" stop-opacity="0" />
7582
+ </linearGradient>
7583
+ </defs>
7584
+ ${parts.join("")}
7585
+ </svg>
7586
+ `;
7587
+ }
7281
7588
  const logoSize = 28;
7282
7589
  const logoX = DEFAULT_STRIP_PADDING_LEFT;
7283
7590
  const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
@@ -7404,16 +7711,16 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
7404
7711
  return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
7405
7712
  };
7406
7713
 
7407
- // src/internals/screenshot-compression.js
7714
+ // src/internals/compression.js
7408
7715
  import { Jimp, JimpMime, ResizeStrategy } from "jimp";
7409
- var logger14 = createInternalLogger("ScreenshotCompression");
7716
+ var logger14 = createInternalLogger("Compression");
7410
7717
  var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
7411
7718
  var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
7412
7719
  var DEFAULT_SCREENSHOT_QUALITY = 0.72;
7413
7720
  var DEFAULT_SCREENSHOT_MIN_QUALITY = 0.38;
7414
7721
  var DEFAULT_SCREENSHOT_MIN_SCALE = 0.25;
7415
7722
  var SUPPORTED_SCREENSHOT_OUTPUT_TYPES = /* @__PURE__ */ new Set(["jpeg"]);
7416
- var toPositiveInteger = (value, fallback = 0) => {
7723
+ var toPositiveInteger2 = (value, fallback = 0) => {
7417
7724
  const number = Math.floor(Number(value) || 0);
7418
7725
  return number > 0 ? number : fallback;
7419
7726
  };
@@ -7435,7 +7742,7 @@ var normalizeScreenshotOutputType = (value) => {
7435
7742
  };
7436
7743
  var getBase64BytesFromBuffer = (buffer) => Math.ceil(buffer.length / 3) * 4;
7437
7744
  var toJpegQuality = (value) => Math.round(normalizeQuality2(value, DEFAULT_SCREENSHOT_QUALITY) * 100);
7438
- var resolveCaptureScreenCompression = (options = {}) => {
7745
+ var resolveImageCompression = (options = {}) => {
7439
7746
  const explicit = options.compression;
7440
7747
  const source = explicit && typeof explicit === "object" && !Array.isArray(explicit) ? explicit : {};
7441
7748
  const enabled = explicit !== false && source.enabled !== false && options.compress !== false;
@@ -7449,7 +7756,7 @@ var resolveCaptureScreenCompression = (options = {}) => {
7449
7756
  );
7450
7757
  return {
7451
7758
  enabled,
7452
- maxBytes: toPositiveInteger(
7759
+ maxBytes: toPositiveInteger2(
7453
7760
  source.maxBytes ?? source.maxBase64Bytes ?? options.maxBytes ?? options.maxBase64Bytes,
7454
7761
  DEFAULT_SCREENSHOT_MAX_BYTES
7455
7762
  ),
@@ -7486,7 +7793,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
7486
7793
  format: compression.outputType
7487
7794
  };
7488
7795
  };
7489
- var compressScreenshotBuffer = async (buffer, compression) => {
7796
+ var compressImageBuffer = async (buffer, compression) => {
7490
7797
  const sourceImage = await Jimp.read(buffer);
7491
7798
  const maxQuality = toJpegQuality(compression.quality);
7492
7799
  const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
@@ -7519,12 +7826,12 @@ var compressScreenshotBuffer = async (buffer, compression) => {
7519
7826
  const fallback = !smallest || finalCandidate.bytes < smallest.bytes ? finalCandidate : smallest;
7520
7827
  return { ...fallback, withinLimit: fallback.bytes <= compression.maxBytes };
7521
7828
  };
7522
- var compressScreenshotBufferToBase64 = async (buffer, compression) => {
7829
+ var compressImageBufferToBase64 = async (buffer, compression) => {
7523
7830
  const originalBytes = getBase64BytesFromBuffer(buffer);
7524
7831
  if (!compression.enabled || originalBytes <= compression.maxBytes) {
7525
7832
  return buffer.toString("base64");
7526
7833
  }
7527
- const result = await compressScreenshotBuffer(buffer, compression).catch((error) => {
7834
+ const result = await compressImageBuffer(buffer, compression).catch((error) => {
7528
7835
  logger14.warning(`captureScreen \u538B\u7F29\u5931\u8D25\uFF0C\u8FD4\u56DE\u539F\u56FE: ${error instanceof Error ? error.message : String(error)}`);
7529
7836
  return null;
7530
7837
  });
@@ -7923,7 +8230,7 @@ var Share = {
7923
8230
  );
7924
8231
  nextProgressLogTs = now + 5e3;
7925
8232
  }
7926
- await delay3(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
8233
+ await delay4(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
7927
8234
  }
7928
8235
  if (share.mode === "response" && stats.responseMatched === 0) {
7929
8236
  logger15.warning(
@@ -7961,71 +8268,27 @@ var Share = {
7961
8268
  * @returns {Promise<string>} base64 image
7962
8269
  */
7963
8270
  async captureScreen(page, options = {}) {
7964
- const originalViewport = await resolveCurrentViewportSize(page);
7965
- const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
7966
- const buffer = options.buffer ?? defaultBuffer;
7967
8271
  const restore = options.restore ?? false;
7968
- const maxHeight = options.maxHeight ?? 8e3;
7969
8272
  const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
7970
- const compression = resolveCaptureScreenCompression(options);
7971
- try {
7972
- const maxScrollHeight = await page.evaluate(() => {
7973
- let maxHeight2 = document.body.scrollHeight;
7974
- document.querySelectorAll("*").forEach((el) => {
7975
- const style = window.getComputedStyle(el);
7976
- const overflowY = style.overflowY;
7977
- if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
7978
- if (el.scrollHeight > maxHeight2) {
7979
- maxHeight2 = el.scrollHeight;
7980
- }
7981
- el.dataset.pkOrigOverflow = el.style.overflow;
7982
- el.dataset.pkOrigHeight = el.style.height;
7983
- el.dataset.pkOrigMaxHeight = el.style.maxHeight;
7984
- el.classList.add("__pk_expanded__");
7985
- el.style.overflow = "visible";
7986
- el.style.height = "auto";
7987
- el.style.maxHeight = "none";
7988
- }
7989
- });
7990
- return maxHeight2;
7991
- });
7992
- const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
7993
- await page.setViewportSize({
7994
- width: originalViewport.width,
7995
- height: targetHeight
7996
- });
7997
- await delay3(1e3);
7998
- const capturedAt = /* @__PURE__ */ new Date();
7999
- const rawBuffer = await capturePageScreenshot(page, {
8000
- fullPage: true,
8001
- type: "png",
8002
- maxClipHeight: targetHeight
8273
+ const compression = resolveImageCompression(options);
8274
+ const captureOptions = {
8275
+ buffer: options.buffer ?? 0,
8276
+ restore,
8277
+ maxHeight: options.maxHeight,
8278
+ type: "png",
8279
+ visibleOnly: true
8280
+ };
8281
+ const capturedAt = /* @__PURE__ */ new Date();
8282
+ const rawBuffer = await captureExpandedFullPageScreenshot(page, captureOptions);
8283
+ let outputBuffer = rawBuffer;
8284
+ if (screenshotWatermarkify.enabled) {
8285
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8286
+ ...screenshotWatermarkify,
8287
+ capturedAt
8003
8288
  });
8004
- let outputBuffer = rawBuffer;
8005
- if (screenshotWatermarkify.enabled) {
8006
- const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8007
- ...screenshotWatermarkify,
8008
- capturedAt
8009
- });
8010
- outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
8011
- }
8012
- return await compressScreenshotBufferToBase64(outputBuffer, compression);
8013
- } finally {
8014
- if (restore) {
8015
- await page.evaluate(() => {
8016
- document.querySelectorAll(".__pk_expanded__").forEach((el) => {
8017
- el.style.overflow = el.dataset.pkOrigOverflow || "";
8018
- el.style.height = el.dataset.pkOrigHeight || "";
8019
- el.style.maxHeight = el.dataset.pkOrigMaxHeight || "";
8020
- delete el.dataset.pkOrigOverflow;
8021
- delete el.dataset.pkOrigHeight;
8022
- delete el.dataset.pkOrigMaxHeight;
8023
- el.classList.remove("__pk_expanded__");
8024
- });
8025
- });
8026
- await page.setViewportSize(originalViewport);
8027
- }
8289
+ outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
8028
8290
  }
8291
+ return await compressImageBufferToBase64(outputBuffer, compression);
8029
8292
  }
8030
8293
  };
8031
8294