@skrillex1224/playwright-toolkit 2.1.227 → 2.1.229

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,15 @@ 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 = 78;
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 = 8;
6281
+ var MOBILE_STRIP_LABEL_FONT_SIZE = 12.5;
6282
+ var MOBILE_STRIP_VALUE_FONT_SIZE = 13.5;
6283
+ var MOBILE_STRIP_META_GAP = 16;
6284
+ var MOBILE_STRIP_VALUE_WIDTH_SAFETY = 10;
6118
6285
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
6119
6286
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
6120
6287
  /(?:中国)?移动$/i,
@@ -6511,9 +6678,10 @@ var readImageInfo = (buffer) => {
6511
6678
  height: 0
6512
6679
  };
6513
6680
  };
6514
- var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
6681
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height, imageHeight }) => {
6515
6682
  const safeWidth = Math.max(1, Number(width) || 1);
6516
6683
  const safeHeight = Math.max(1, Number(height) || 1);
6684
+ const safeImageHeight = Math.max(1, Number(imageHeight || height) || 1);
6517
6685
  return `
6518
6686
  <!doctype html>
6519
6687
  <html lang="zh-CN">
@@ -6542,10 +6710,11 @@ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
6542
6710
 
6543
6711
  #pk-base-image {
6544
6712
  position: absolute;
6545
- inset: 0;
6713
+ top: 0;
6714
+ left: 0;
6546
6715
  display: block;
6547
6716
  width: ${safeWidth}px;
6548
- height: ${safeHeight}px;
6717
+ height: ${safeImageHeight}px;
6549
6718
  }
6550
6719
 
6551
6720
  #pk-overlay {
@@ -6579,7 +6748,8 @@ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageI
6579
6748
  try {
6580
6749
  const renderPage = renderScope.page;
6581
6750
  const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
6582
- const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
6751
+ const safeImageHeight = Math.max(1, Number(imageInfo.imageHeight || imageInfo.height) || 1);
6752
+ const safeHeight = Math.max(safeImageHeight, Number(imageInfo.height) || safeImageHeight);
6583
6753
  const viewportHeight = Math.max(
6584
6754
  1,
6585
6755
  Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
@@ -6593,7 +6763,8 @@ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageI
6593
6763
  imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
6594
6764
  overlaySvg,
6595
6765
  width: safeWidth,
6596
- height: safeHeight
6766
+ height: safeHeight,
6767
+ imageHeight: safeImageHeight
6597
6768
  }), {
6598
6769
  waitUntil: "load"
6599
6770
  });
@@ -6899,10 +7070,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
6899
7070
  }),
6900
7071
  watermark: options.watermark,
6901
7072
  strip: options.strip,
6902
- stripLogoSrc
7073
+ stripLogoSrc,
7074
+ device: resolvePageDevice(page)
6903
7075
  };
6904
7076
  };
6905
7077
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7078
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7079
+ var findStripSegment = (segments, kind) => {
7080
+ const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7081
+ return found && typeof found === "object" ? found : {};
7082
+ };
6906
7083
  var buildStripSegmentLayout = (segment, options = {}) => {
6907
7084
  const label = normalizeWhitespace(segment?.label || "");
6908
7085
  const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
@@ -7230,6 +7407,123 @@ var renderStripDivider = (x, centerY, height) => {
7230
7407
  />
7231
7408
  `;
7232
7409
  };
7410
+ var renderMobileStripText = ({
7411
+ label,
7412
+ value,
7413
+ labelX,
7414
+ valueX,
7415
+ y,
7416
+ valueWidth,
7417
+ fontFamily
7418
+ }) => {
7419
+ const safeLabel = normalizeWhitespace(label) || "-";
7420
+ const safeValue = fitTextWithEllipsis(
7421
+ Array.from(normalizeWhitespace(value) || "-"),
7422
+ Math.max(18, valueWidth - MOBILE_STRIP_VALUE_WIDTH_SAFETY),
7423
+ MOBILE_STRIP_VALUE_FONT_SIZE
7424
+ );
7425
+ return `
7426
+ <text
7427
+ x="${labelX}"
7428
+ y="${y}"
7429
+ fill="#111111"
7430
+ fill-opacity="0.54"
7431
+ font-family="${fontFamily}"
7432
+ font-size="${MOBILE_STRIP_LABEL_FONT_SIZE}"
7433
+ font-weight="650"
7434
+ dominant-baseline="middle"
7435
+ >${escapeXml(safeLabel)}</text>
7436
+ <text
7437
+ x="${valueX}"
7438
+ y="${y}"
7439
+ fill="#111111"
7440
+ font-family="${fontFamily}"
7441
+ font-size="${MOBILE_STRIP_VALUE_FONT_SIZE}"
7442
+ font-weight="730"
7443
+ dominant-baseline="middle"
7444
+ >${escapeXml(safeValue)}</text>
7445
+ `;
7446
+ };
7447
+ var renderMobileStrip = ({ meta, width, baseHeight, fontFamily }) => {
7448
+ const stripHeight = MOBILE_STRIP_HEIGHT;
7449
+ const stripY = baseHeight;
7450
+ const contentX = MOBILE_STRIP_PADDING_X;
7451
+ const contentWidth = Math.max(1, width - MOBILE_STRIP_PADDING_X * 2);
7452
+ const prompt = findStripSegment(meta.stripSegments, "prompt");
7453
+ const time = findStripSegment(meta.stripSegments, "time");
7454
+ const location = findStripSegment(meta.stripSegments, "location");
7455
+ const ip = findStripSegment(meta.stripSegments, "ip");
7456
+ const row1Y = stripY + MOBILE_STRIP_PADDING_Y + MOBILE_STRIP_ROW_HEIGHT / 2;
7457
+ const row2Y = row1Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7458
+ const rightColumnX = Math.min(
7459
+ width - MOBILE_STRIP_PADDING_X - 112,
7460
+ Math.max(
7461
+ contentX + 200,
7462
+ contentX + Math.round(contentWidth * 0.62)
7463
+ )
7464
+ );
7465
+ const leftValueX = contentX + 48;
7466
+ const rightValueX = rightColumnX + 28;
7467
+ const promptValueWidth = Math.max(
7468
+ 28,
7469
+ rightColumnX - leftValueX - MOBILE_STRIP_META_GAP
7470
+ );
7471
+ const timeValueWidth = Math.max(
7472
+ 28,
7473
+ rightColumnX - leftValueX - MOBILE_STRIP_META_GAP
7474
+ );
7475
+ const locValueWidth = Math.max(
7476
+ 28,
7477
+ width - MOBILE_STRIP_PADDING_X - rightValueX
7478
+ );
7479
+ const ipValueWidth = Math.max(
7480
+ 28,
7481
+ width - MOBILE_STRIP_PADDING_X - rightValueX
7482
+ );
7483
+ return `
7484
+ <g id="strip">
7485
+ <rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
7486
+ <rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
7487
+ <rect x="${contentX}" y="${stripY}" width="${Math.max(96, Math.round(width * 0.34))}" height="2" fill="url(#stripAccent)" />
7488
+ ${renderMobileStripText({
7489
+ label: "Prompt",
7490
+ value: prompt.rawValue || prompt.value || "-",
7491
+ labelX: contentX,
7492
+ valueX: leftValueX,
7493
+ y: row1Y,
7494
+ valueWidth: promptValueWidth,
7495
+ fontFamily
7496
+ })}
7497
+ ${renderMobileStripText({
7498
+ label: "Loc",
7499
+ value: location.rawValue || location.value || "-",
7500
+ labelX: rightColumnX,
7501
+ valueX: rightValueX,
7502
+ y: row1Y,
7503
+ valueWidth: locValueWidth,
7504
+ fontFamily
7505
+ })}
7506
+ ${renderMobileStripText({
7507
+ label: "Time",
7508
+ value: time.rawValue || time.value || "-",
7509
+ labelX: contentX,
7510
+ valueX: leftValueX,
7511
+ y: row2Y,
7512
+ valueWidth: timeValueWidth,
7513
+ fontFamily
7514
+ })}
7515
+ ${renderMobileStripText({
7516
+ label: "IP",
7517
+ value: ip.rawValue || ip.value || "-",
7518
+ labelX: rightColumnX,
7519
+ valueX: rightValueX,
7520
+ y: row2Y,
7521
+ valueWidth: ipValueWidth,
7522
+ fontFamily
7523
+ })}
7524
+ </g>
7525
+ `;
7526
+ };
7233
7527
  var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7234
7528
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
7235
7529
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
@@ -7237,7 +7531,8 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7237
7531
  return "";
7238
7532
  }
7239
7533
  const width = Math.max(1, Number(imageWidth) || 1);
7240
- const height = Math.max(1, Number(imageHeight) || 1);
7534
+ const baseHeight = Math.max(1, Number(imageHeight) || 1);
7535
+ const canvasHeight = normalizeDevice(meta.device) === Device.Mobile && hasStrip ? baseHeight + MOBILE_STRIP_HEIGHT : baseHeight;
7241
7536
  const fontFamily = escapeXml(buildFontFamily());
7242
7537
  const parts = [];
7243
7538
  if (hasWatermark) {
@@ -7250,7 +7545,7 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7250
7545
  const startX = -Math.round(cellWidth * 0.16);
7251
7546
  const startY = -Math.round(cellHeight * 0.12);
7252
7547
  const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
7253
- const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
7548
+ const rows = Math.ceil((baseHeight + cellHeight * 0.9) / cellHeight) + 1;
7254
7549
  const stamps = [];
7255
7550
  for (let row = 0; row < rows; row += 1) {
7256
7551
  for (let col = 0; col < cols; col += 1) {
@@ -7278,13 +7573,34 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7278
7573
  parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
7279
7574
  }
7280
7575
  if (hasStrip) {
7576
+ if (normalizeDevice(meta.device) === Device.Mobile) {
7577
+ parts.push(renderMobileStrip({
7578
+ meta,
7579
+ width,
7580
+ baseHeight,
7581
+ fontFamily
7582
+ }));
7583
+ return `
7584
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${canvasHeight}" viewBox="0 0 ${width} ${canvasHeight}">
7585
+ <defs>
7586
+ <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7587
+ <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
7588
+ <stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
7589
+ <stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
7590
+ <stop offset="100%" stop-color="#111111" stop-opacity="0" />
7591
+ </linearGradient>
7592
+ </defs>
7593
+ ${parts.join("")}
7594
+ </svg>
7595
+ `;
7596
+ }
7281
7597
  const logoSize = 28;
7282
7598
  const logoX = DEFAULT_STRIP_PADDING_LEFT;
7283
7599
  const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
7284
7600
  const contentWidth = width - contentStartX - DEFAULT_STRIP_PADDING_RIGHT;
7285
7601
  const stripLayout = buildStripLayout(meta.stripSegments, contentWidth);
7286
7602
  const stripHeight = stripLayout.height;
7287
- const stripY = height - stripHeight;
7603
+ const stripY = baseHeight - stripHeight;
7288
7604
  const logoY = Number((stripY + (stripHeight - logoSize) / 2).toFixed(2));
7289
7605
  let stripContentSvg = "";
7290
7606
  const centerY = stripY + stripHeight / 2 + 1;
@@ -7373,7 +7689,7 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7373
7689
  `);
7374
7690
  }
7375
7691
  return `
7376
- <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7692
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${canvasHeight}" viewBox="0 0 ${width} ${canvasHeight}">
7377
7693
  <defs>
7378
7694
  <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7379
7695
  <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
@@ -7397,23 +7713,29 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
7397
7713
  logger13.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
7398
7714
  return buffer;
7399
7715
  }
7716
+ const isMobileStrip = normalizeDevice(meta.device) === Device.Mobile && hasStrip;
7717
+ const outputImageInfo = isMobileStrip ? {
7718
+ ...imageInfo,
7719
+ imageHeight: imageInfo.height,
7720
+ height: imageInfo.height + MOBILE_STRIP_HEIGHT
7721
+ } : imageInfo;
7400
7722
  const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
7401
7723
  if (!overlaySvg) {
7402
7724
  return buffer;
7403
7725
  }
7404
- return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
7726
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, outputImageInfo);
7405
7727
  };
7406
7728
 
7407
- // src/internals/screenshot-compression.js
7729
+ // src/internals/compression.js
7408
7730
  import { Jimp, JimpMime, ResizeStrategy } from "jimp";
7409
- var logger14 = createInternalLogger("ScreenshotCompression");
7731
+ var logger14 = createInternalLogger("Compression");
7410
7732
  var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
7411
7733
  var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
7412
7734
  var DEFAULT_SCREENSHOT_QUALITY = 0.72;
7413
7735
  var DEFAULT_SCREENSHOT_MIN_QUALITY = 0.38;
7414
7736
  var DEFAULT_SCREENSHOT_MIN_SCALE = 0.25;
7415
7737
  var SUPPORTED_SCREENSHOT_OUTPUT_TYPES = /* @__PURE__ */ new Set(["jpeg"]);
7416
- var toPositiveInteger = (value, fallback = 0) => {
7738
+ var toPositiveInteger2 = (value, fallback = 0) => {
7417
7739
  const number = Math.floor(Number(value) || 0);
7418
7740
  return number > 0 ? number : fallback;
7419
7741
  };
@@ -7435,7 +7757,7 @@ var normalizeScreenshotOutputType = (value) => {
7435
7757
  };
7436
7758
  var getBase64BytesFromBuffer = (buffer) => Math.ceil(buffer.length / 3) * 4;
7437
7759
  var toJpegQuality = (value) => Math.round(normalizeQuality2(value, DEFAULT_SCREENSHOT_QUALITY) * 100);
7438
- var resolveCaptureScreenCompression = (options = {}) => {
7760
+ var resolveImageCompression = (options = {}) => {
7439
7761
  const explicit = options.compression;
7440
7762
  const source = explicit && typeof explicit === "object" && !Array.isArray(explicit) ? explicit : {};
7441
7763
  const enabled = explicit !== false && source.enabled !== false && options.compress !== false;
@@ -7449,7 +7771,7 @@ var resolveCaptureScreenCompression = (options = {}) => {
7449
7771
  );
7450
7772
  return {
7451
7773
  enabled,
7452
- maxBytes: toPositiveInteger(
7774
+ maxBytes: toPositiveInteger2(
7453
7775
  source.maxBytes ?? source.maxBase64Bytes ?? options.maxBytes ?? options.maxBase64Bytes,
7454
7776
  DEFAULT_SCREENSHOT_MAX_BYTES
7455
7777
  ),
@@ -7486,7 +7808,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
7486
7808
  format: compression.outputType
7487
7809
  };
7488
7810
  };
7489
- var compressScreenshotBuffer = async (buffer, compression) => {
7811
+ var compressImageBuffer = async (buffer, compression) => {
7490
7812
  const sourceImage = await Jimp.read(buffer);
7491
7813
  const maxQuality = toJpegQuality(compression.quality);
7492
7814
  const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
@@ -7519,12 +7841,12 @@ var compressScreenshotBuffer = async (buffer, compression) => {
7519
7841
  const fallback = !smallest || finalCandidate.bytes < smallest.bytes ? finalCandidate : smallest;
7520
7842
  return { ...fallback, withinLimit: fallback.bytes <= compression.maxBytes };
7521
7843
  };
7522
- var compressScreenshotBufferToBase64 = async (buffer, compression) => {
7844
+ var compressImageBufferToBase64 = async (buffer, compression) => {
7523
7845
  const originalBytes = getBase64BytesFromBuffer(buffer);
7524
7846
  if (!compression.enabled || originalBytes <= compression.maxBytes) {
7525
7847
  return buffer.toString("base64");
7526
7848
  }
7527
- const result = await compressScreenshotBuffer(buffer, compression).catch((error) => {
7849
+ const result = await compressImageBuffer(buffer, compression).catch((error) => {
7528
7850
  logger14.warning(`captureScreen \u538B\u7F29\u5931\u8D25\uFF0C\u8FD4\u56DE\u539F\u56FE: ${error instanceof Error ? error.message : String(error)}`);
7529
7851
  return null;
7530
7852
  });
@@ -7923,7 +8245,7 @@ var Share = {
7923
8245
  );
7924
8246
  nextProgressLogTs = now + 5e3;
7925
8247
  }
7926
- await delay3(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
8248
+ await delay4(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
7927
8249
  }
7928
8250
  if (share.mode === "response" && stats.responseMatched === 0) {
7929
8251
  logger15.warning(
@@ -7961,71 +8283,27 @@ var Share = {
7961
8283
  * @returns {Promise<string>} base64 image
7962
8284
  */
7963
8285
  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
8286
  const restore = options.restore ?? false;
7968
- const maxHeight = options.maxHeight ?? 8e3;
7969
8287
  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
8288
+ const compression = resolveImageCompression(options);
8289
+ const captureOptions = {
8290
+ buffer: options.buffer ?? 0,
8291
+ restore,
8292
+ maxHeight: options.maxHeight,
8293
+ type: "png",
8294
+ visibleOnly: true
8295
+ };
8296
+ const capturedAt = /* @__PURE__ */ new Date();
8297
+ const rawBuffer = await captureExpandedFullPageScreenshot(page, captureOptions);
8298
+ let outputBuffer = rawBuffer;
8299
+ if (screenshotWatermarkify.enabled) {
8300
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8301
+ ...screenshotWatermarkify,
8302
+ capturedAt
8003
8303
  });
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
- }
8304
+ outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
8028
8305
  }
8306
+ return await compressImageBufferToBase64(outputBuffer, compression);
8029
8307
  }
8030
8308
  };
8031
8309