@skrillex1224/playwright-toolkit 2.1.209 → 2.1.211
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/README.md +3 -2
- package/dist/browser.js +11 -0
- package/dist/browser.js.map +3 -3
- package/dist/index.cjs +702 -457
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +702 -457
- package/dist/index.js.map +4 -4
- package/index.d.ts +5 -2
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -435,6 +435,33 @@ function createInternalLogger(moduleName, explicitLogger) {
|
|
|
435
435
|
};
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
+
// src/internals/viewport.js
|
|
439
|
+
var toPositiveInt = (value) => {
|
|
440
|
+
const number = Math.round(Number(value) || 0);
|
|
441
|
+
return number > 0 ? number : 0;
|
|
442
|
+
};
|
|
443
|
+
var resolveCurrentViewportSize = async (page, fallback = {}) => {
|
|
444
|
+
const directViewport = page?.viewportSize?.();
|
|
445
|
+
const directWidth = toPositiveInt(directViewport?.width);
|
|
446
|
+
const directHeight = toPositiveInt(directViewport?.height);
|
|
447
|
+
if (directWidth && directHeight) {
|
|
448
|
+
return {
|
|
449
|
+
width: directWidth,
|
|
450
|
+
height: directHeight
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const measuredViewport = await page?.evaluate?.(() => ({
|
|
454
|
+
width: window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0,
|
|
455
|
+
height: window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0
|
|
456
|
+
})).catch(() => null);
|
|
457
|
+
const fallbackWidth = toPositiveInt(fallback?.width);
|
|
458
|
+
const fallbackHeight = toPositiveInt(fallback?.height);
|
|
459
|
+
return {
|
|
460
|
+
width: toPositiveInt(measuredViewport?.width) || fallbackWidth || 1,
|
|
461
|
+
height: toPositiveInt(measuredViewport?.height) || fallbackHeight || 1
|
|
462
|
+
};
|
|
463
|
+
};
|
|
464
|
+
|
|
438
465
|
// src/internals/screenshot.js
|
|
439
466
|
var logger = createInternalLogger("Screenshot");
|
|
440
467
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
@@ -461,7 +488,7 @@ var normalizeQuality = (value, type) => {
|
|
|
461
488
|
};
|
|
462
489
|
var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
463
490
|
const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
|
|
464
|
-
const width = Math.max(1, Math.ceil(
|
|
491
|
+
const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
|
|
465
492
|
let height = Math.max(1, Math.ceil(contentSize?.height || viewport.height || 1));
|
|
466
493
|
if (maxClipHeight > 0) {
|
|
467
494
|
height = Math.min(height, maxClipHeight);
|
|
@@ -498,7 +525,7 @@ var capturePageScreenshot = async (page, options = {}) => {
|
|
|
498
525
|
const session = await context.newCDPSession(page);
|
|
499
526
|
try {
|
|
500
527
|
const metrics = await session.send("Page.getLayoutMetrics");
|
|
501
|
-
const viewport = page
|
|
528
|
+
const viewport = await resolveCurrentViewportSize(page);
|
|
502
529
|
const captureParams = {
|
|
503
530
|
format: type,
|
|
504
531
|
fromSurface: true,
|
|
@@ -952,6 +979,9 @@ var ProxyMeterRuntime = {
|
|
|
952
979
|
getProxyMeterSnapshot
|
|
953
980
|
};
|
|
954
981
|
|
|
982
|
+
// src/internals/constants.js
|
|
983
|
+
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
984
|
+
|
|
955
985
|
// src/runtime-env.js
|
|
956
986
|
var BROWSER_PROFILE_SCHEMA_VERSION = 1;
|
|
957
987
|
var rememberedRuntimeState = null;
|
|
@@ -1458,6 +1488,7 @@ var RuntimeEnv = {
|
|
|
1458
1488
|
parseInput(input = {}, actor = "") {
|
|
1459
1489
|
const runtime2 = tryParseJSON(input?.runtime) || {};
|
|
1460
1490
|
const resolvedActor = String(actor || input?.actor || "").trim();
|
|
1491
|
+
const query = String(input?.query || "").trim();
|
|
1461
1492
|
const cookies = normalizeCookies(runtime2?.cookies);
|
|
1462
1493
|
const cookieMap = buildCookieMap(cookies);
|
|
1463
1494
|
const localStorage = normalizeLocalStorage(runtime2?.local_storage);
|
|
@@ -1481,6 +1512,7 @@ var RuntimeEnv = {
|
|
|
1481
1512
|
actor: resolvedActor,
|
|
1482
1513
|
runtime: normalizedRuntime,
|
|
1483
1514
|
envId,
|
|
1515
|
+
query,
|
|
1484
1516
|
auth,
|
|
1485
1517
|
cookies,
|
|
1486
1518
|
cookieMap,
|
|
@@ -1548,6 +1580,12 @@ var RuntimeEnv = {
|
|
|
1548
1580
|
async applyToPage(page, source = {}, options = {}) {
|
|
1549
1581
|
if (!page) return;
|
|
1550
1582
|
const state = normalizeRuntimeState(source, options?.actor || "");
|
|
1583
|
+
Object.defineProperty(page, PageRuntimeStateKey, {
|
|
1584
|
+
configurable: true,
|
|
1585
|
+
enumerable: false,
|
|
1586
|
+
writable: true,
|
|
1587
|
+
value: state
|
|
1588
|
+
});
|
|
1551
1589
|
const localStorage = state.localStorage || {};
|
|
1552
1590
|
const sessionStorage = state.sessionStorage || {};
|
|
1553
1591
|
const cookies = (state.cookies || []).map((cookie) => {
|
|
@@ -4549,7 +4587,7 @@ var Logger = {
|
|
|
4549
4587
|
var import_delay2 = __toESM(require("delay"), 1);
|
|
4550
4588
|
|
|
4551
4589
|
// src/internals/watermarkify.js
|
|
4552
|
-
var
|
|
4590
|
+
var import_sharp = __toESM(require("sharp"), 1);
|
|
4553
4591
|
var DEFAULT_TIMEZONE_OFFSET = 8;
|
|
4554
4592
|
var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
|
|
4555
4593
|
var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
|
|
@@ -4560,6 +4598,26 @@ var DEFAULT_WATERMARK_CELL_HEIGHT = 330;
|
|
|
4560
4598
|
var DEFAULT_STRIP_LOGO_URL = "https://static.heartbitai.com/geo/icon/favicon.png";
|
|
4561
4599
|
var DEFAULT_IP_LOOKUP_URL = "http://myip.ipip.net";
|
|
4562
4600
|
var DEFAULT_LOGO_FETCH_TIMEOUT_MS = 2500;
|
|
4601
|
+
var DEFAULT_STRIP_ONE_LINE_HEIGHT = 78;
|
|
4602
|
+
var DEFAULT_STRIP_WRAPPED_MIN_HEIGHT = 108;
|
|
4603
|
+
var DEFAULT_STRIP_PADDING_LEFT = 22;
|
|
4604
|
+
var DEFAULT_STRIP_PADDING_RIGHT = 28;
|
|
4605
|
+
var DEFAULT_STRIP_GAP = 18;
|
|
4606
|
+
var DEFAULT_STRIP_LABEL_WIDTH = 56;
|
|
4607
|
+
var DEFAULT_STRIP_PROMPT_MAX_SAFE_CHARS = 180;
|
|
4608
|
+
var DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH = 320;
|
|
4609
|
+
var DEFAULT_STRIP_PROMPT_PREFERRED_WIDTH_RATIO = 0.58;
|
|
4610
|
+
var DEFAULT_STRIP_ZONE_GAP = 18;
|
|
4611
|
+
var DEFAULT_STRIP_PROMPT_TRAILING_PADDING = 16;
|
|
4612
|
+
var DEFAULT_STRIP_LABEL_FONT_SIZE = 14.5;
|
|
4613
|
+
var DEFAULT_STRIP_VALUE_FONT_SIZE = 15.5;
|
|
4614
|
+
var DEFAULT_STRIP_VALUE_PADDING = 10;
|
|
4615
|
+
var DEFAULT_STRIP_LABEL_PADDING = 14;
|
|
4616
|
+
var DEFAULT_STRIP_SECTION_GAP = DEFAULT_STRIP_GAP + 16;
|
|
4617
|
+
var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
|
|
4618
|
+
var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
|
|
4619
|
+
var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
|
|
4620
|
+
var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
|
|
4563
4621
|
var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
|
|
4564
4622
|
var LOCATION_NETWORK_SUFFIX_PATTERNS = [
|
|
4565
4623
|
/(?:中国)?移动$/i,
|
|
@@ -4584,6 +4642,7 @@ var LOCATION_NETWORK_SUFFIX_PATTERNS = [
|
|
|
4584
4642
|
/digitalocean$/i
|
|
4585
4643
|
];
|
|
4586
4644
|
var cachedStripLogoSrcPromise = null;
|
|
4645
|
+
var cachedEnrichmentByContext = /* @__PURE__ */ new WeakMap();
|
|
4587
4646
|
var normalizeText = (value) => String(value || "").trim();
|
|
4588
4647
|
var toInline = (value, maxLen = 200) => {
|
|
4589
4648
|
const text = normalizeText(value);
|
|
@@ -4595,12 +4654,14 @@ var shortenTail = (value, maxLen = 80) => {
|
|
|
4595
4654
|
if (!text || text.length <= maxLen) return text;
|
|
4596
4655
|
return `${text.slice(0, Math.max(0, maxLen - 1)).trimEnd()}\u2026`;
|
|
4597
4656
|
};
|
|
4598
|
-
var
|
|
4599
|
-
const text =
|
|
4600
|
-
if (!text
|
|
4601
|
-
const
|
|
4602
|
-
|
|
4603
|
-
|
|
4657
|
+
var shortenByCharacters = (value, maxChars = 80) => {
|
|
4658
|
+
const text = normalizeWhitespace(value);
|
|
4659
|
+
if (!text) return "";
|
|
4660
|
+
const chars = Array.from(text);
|
|
4661
|
+
if (chars.length <= maxChars) {
|
|
4662
|
+
return text;
|
|
4663
|
+
}
|
|
4664
|
+
return `${chars.slice(0, Math.max(0, maxChars - 1)).join("").trimEnd()}\u2026`;
|
|
4604
4665
|
};
|
|
4605
4666
|
var padDatePart = (value) => String(value).padStart(2, "0");
|
|
4606
4667
|
var formatUtcOffsetLabel = (offsetHours = DEFAULT_TIMEZONE_OFFSET) => {
|
|
@@ -4674,6 +4735,29 @@ var fillEnrichment = (target, source) => {
|
|
|
4674
4735
|
}
|
|
4675
4736
|
return target;
|
|
4676
4737
|
};
|
|
4738
|
+
var readCachedEnrichment = (page) => {
|
|
4739
|
+
const context = page && typeof page.context === "function" ? page.context() : null;
|
|
4740
|
+
if (!context) {
|
|
4741
|
+
return null;
|
|
4742
|
+
}
|
|
4743
|
+
const cached = cachedEnrichmentByContext.get(context);
|
|
4744
|
+
return cached && typeof cached === "object" ? cached : null;
|
|
4745
|
+
};
|
|
4746
|
+
var writeCachedEnrichment = (page, source) => {
|
|
4747
|
+
const context = page && typeof page.context === "function" ? page.context() : null;
|
|
4748
|
+
if (!context || !source || typeof source !== "object") {
|
|
4749
|
+
return;
|
|
4750
|
+
}
|
|
4751
|
+
const current = cachedEnrichmentByContext.get(context) || {};
|
|
4752
|
+
const next = {
|
|
4753
|
+
ip: toInline(source.ip || current.ip, 80),
|
|
4754
|
+
location: toInline(source.location || current.location, 80)
|
|
4755
|
+
};
|
|
4756
|
+
if (!next.ip && !next.location) {
|
|
4757
|
+
return;
|
|
4758
|
+
}
|
|
4759
|
+
cachedEnrichmentByContext.set(context, next);
|
|
4760
|
+
};
|
|
4677
4761
|
var getHostname = (url) => {
|
|
4678
4762
|
try {
|
|
4679
4763
|
const parsed = new URL(url);
|
|
@@ -4777,8 +4861,8 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
|
|
|
4777
4861
|
url: baseMeta.url,
|
|
4778
4862
|
hostname: baseMeta.hostname,
|
|
4779
4863
|
title: baseMeta.title,
|
|
4864
|
+
prompt: baseMeta.prompt,
|
|
4780
4865
|
query: baseMeta.query,
|
|
4781
|
-
taskId: baseMeta.taskId,
|
|
4782
4866
|
serverAddr,
|
|
4783
4867
|
signal: controller?.signal
|
|
4784
4868
|
})).catch(() => null),
|
|
@@ -4803,44 +4887,43 @@ var openProbePage = async (page) => {
|
|
|
4803
4887
|
if (!context) {
|
|
4804
4888
|
return null;
|
|
4805
4889
|
}
|
|
4890
|
+
const browser = typeof context.browser === "function" ? context.browser() : null;
|
|
4891
|
+
if (browser && typeof browser.newContext === "function") {
|
|
4892
|
+
const probeContext = await browser.newContext().catch(() => null);
|
|
4893
|
+
if (probeContext && typeof probeContext.newPage === "function") {
|
|
4894
|
+
const probePage = await probeContext.newPage().catch(async () => {
|
|
4895
|
+
await probeContext.close().catch(() => {
|
|
4896
|
+
});
|
|
4897
|
+
return null;
|
|
4898
|
+
});
|
|
4899
|
+
if (probePage) {
|
|
4900
|
+
return {
|
|
4901
|
+
page: probePage,
|
|
4902
|
+
close: async () => {
|
|
4903
|
+
await probeContext.close().catch(() => {
|
|
4904
|
+
});
|
|
4905
|
+
}
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4908
|
+
} else {
|
|
4909
|
+
await probeContext?.close?.().catch(() => {
|
|
4910
|
+
});
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4806
4913
|
if (typeof context.newPage === "function") {
|
|
4807
4914
|
try {
|
|
4808
|
-
const
|
|
4915
|
+
const probePage = await context.newPage();
|
|
4809
4916
|
return {
|
|
4810
|
-
page:
|
|
4917
|
+
page: probePage,
|
|
4811
4918
|
close: async () => {
|
|
4812
|
-
await
|
|
4919
|
+
await probePage.close().catch(() => {
|
|
4813
4920
|
});
|
|
4814
4921
|
}
|
|
4815
4922
|
};
|
|
4816
4923
|
} catch {
|
|
4817
4924
|
}
|
|
4818
4925
|
}
|
|
4819
|
-
|
|
4820
|
-
if (!browser || typeof browser.newContext !== "function") {
|
|
4821
|
-
return null;
|
|
4822
|
-
}
|
|
4823
|
-
const probeContext = await browser.newContext().catch(() => null);
|
|
4824
|
-
if (!probeContext || typeof probeContext.newPage !== "function") {
|
|
4825
|
-
await probeContext?.close?.().catch(() => {
|
|
4826
|
-
});
|
|
4827
|
-
return null;
|
|
4828
|
-
}
|
|
4829
|
-
const probePage = await probeContext.newPage().catch(async () => {
|
|
4830
|
-
await probeContext.close().catch(() => {
|
|
4831
|
-
});
|
|
4832
|
-
return null;
|
|
4833
|
-
});
|
|
4834
|
-
if (!probePage) {
|
|
4835
|
-
return null;
|
|
4836
|
-
}
|
|
4837
|
-
return {
|
|
4838
|
-
page: probePage,
|
|
4839
|
-
close: async () => {
|
|
4840
|
-
await probeContext.close().catch(() => {
|
|
4841
|
-
});
|
|
4842
|
-
}
|
|
4843
|
-
};
|
|
4926
|
+
return null;
|
|
4844
4927
|
};
|
|
4845
4928
|
var resolveWithIpLookup = async (page, options = {}) => {
|
|
4846
4929
|
if (!page || typeof page.context !== "function" || options.ipLookup === false) {
|
|
@@ -4885,10 +4968,14 @@ var resolveWithIpLookup = async (page, options = {}) => {
|
|
|
4885
4968
|
};
|
|
4886
4969
|
var resolveEnrichment = async (page, baseMeta, options) => {
|
|
4887
4970
|
const response = options.response && typeof options.response === "object" ? options.response : null;
|
|
4971
|
+
const cached = readCachedEnrichment(page);
|
|
4888
4972
|
const merged = {
|
|
4889
4973
|
ip: toInline(options.ip, 80),
|
|
4890
4974
|
location: toInline(options.location, 80)
|
|
4891
4975
|
};
|
|
4976
|
+
if (!merged.ip || !merged.location) {
|
|
4977
|
+
fillEnrichment(merged, cached);
|
|
4978
|
+
}
|
|
4892
4979
|
if (!merged.ip || !merged.location) {
|
|
4893
4980
|
fillEnrichment(
|
|
4894
4981
|
merged,
|
|
@@ -4912,24 +4999,31 @@ var resolveEnrichment = async (page, baseMeta, options) => {
|
|
|
4912
4999
|
merged.location = headerLocation || merged.location;
|
|
4913
5000
|
}
|
|
4914
5001
|
}
|
|
5002
|
+
writeCachedEnrichment(page, merged);
|
|
4915
5003
|
return merged;
|
|
4916
5004
|
};
|
|
4917
|
-
var buildWatermarkStamp = ({
|
|
5005
|
+
var buildWatermarkStamp = ({ prompt, captureTime, ip, location }) => {
|
|
4918
5006
|
const parts = [
|
|
4919
|
-
`
|
|
5007
|
+
`Prompt ${shortenTail(prompt, 40) || "-"}`,
|
|
4920
5008
|
`Time ${captureTime}`,
|
|
4921
5009
|
`Loc ${shortenTail(location, 20) || "-"}`,
|
|
4922
5010
|
`IP ${toInline(ip, 24) || "-"}`
|
|
4923
5011
|
];
|
|
4924
5012
|
return parts.join(" | ");
|
|
4925
5013
|
};
|
|
4926
|
-
var buildStripSegments = ({
|
|
5014
|
+
var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
|
|
5015
|
+
const promptValue = shortenByCharacters(
|
|
5016
|
+
normalizeWhitespace(prompt) || "-",
|
|
5017
|
+
DEFAULT_STRIP_PROMPT_MAX_SAFE_CHARS
|
|
5018
|
+
) || "-";
|
|
5019
|
+
const ipValue = normalizeWhitespace(ip) || "-";
|
|
5020
|
+
const locationValue = normalizeWhitespace(location) || "-";
|
|
4927
5021
|
return [
|
|
4928
5022
|
{
|
|
4929
|
-
kind: "
|
|
4930
|
-
label: "
|
|
4931
|
-
value:
|
|
4932
|
-
rawValue:
|
|
5023
|
+
kind: "prompt",
|
|
5024
|
+
label: "Prompt",
|
|
5025
|
+
value: promptValue,
|
|
5026
|
+
rawValue: promptValue
|
|
4933
5027
|
},
|
|
4934
5028
|
{
|
|
4935
5029
|
kind: "time",
|
|
@@ -4940,25 +5034,50 @@ var buildStripSegments = ({ taskId, captureTime, ip, location }) => {
|
|
|
4940
5034
|
{
|
|
4941
5035
|
kind: "location",
|
|
4942
5036
|
label: "Loc",
|
|
4943
|
-
value:
|
|
4944
|
-
rawValue:
|
|
5037
|
+
value: locationValue,
|
|
5038
|
+
rawValue: locationValue
|
|
4945
5039
|
},
|
|
4946
5040
|
{
|
|
4947
5041
|
kind: "ip",
|
|
4948
5042
|
label: "IP",
|
|
4949
|
-
value:
|
|
4950
|
-
rawValue:
|
|
5043
|
+
value: ipValue,
|
|
5044
|
+
rawValue: ipValue
|
|
4951
5045
|
}
|
|
4952
5046
|
];
|
|
4953
5047
|
};
|
|
5048
|
+
var escapeXml = (value) => String(value || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5049
|
+
var estimateTextWidth = (value, fontSize = 16) => {
|
|
5050
|
+
const text = String(value || "");
|
|
5051
|
+
let width = 0;
|
|
5052
|
+
for (const char of text) {
|
|
5053
|
+
if (/\s/.test(char)) {
|
|
5054
|
+
width += fontSize * 0.34;
|
|
5055
|
+
} else if (/[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u30ff\uac00-\ud7af]/.test(char)) {
|
|
5056
|
+
width += fontSize * 0.92;
|
|
5057
|
+
} else if (/[A-Z0-9]/.test(char)) {
|
|
5058
|
+
width += fontSize * 0.62;
|
|
5059
|
+
} else {
|
|
5060
|
+
width += fontSize * 0.56;
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
return Math.ceil(width);
|
|
5064
|
+
};
|
|
5065
|
+
var resolvePromptFields = (options = {}, fallbackTitle = "") => {
|
|
5066
|
+
const query = normalizeText(options.query);
|
|
5067
|
+
const prompt = query || normalizeText(options.prompt) || normalizeText(fallbackTitle) || "\u672A\u63D0\u4F9B Prompt";
|
|
5068
|
+
return {
|
|
5069
|
+
prompt,
|
|
5070
|
+
query: query || prompt
|
|
5071
|
+
};
|
|
5072
|
+
};
|
|
4954
5073
|
var createBaseWatermarkifyOptions = () => ({
|
|
4955
5074
|
enabled: true,
|
|
4956
5075
|
timezoneOffsetHours: DEFAULT_TIMEZONE_OFFSET,
|
|
4957
5076
|
response: null,
|
|
4958
5077
|
ip: "",
|
|
4959
5078
|
location: "",
|
|
5079
|
+
prompt: "",
|
|
4960
5080
|
query: "",
|
|
4961
|
-
taskId: "",
|
|
4962
5081
|
ipLookup: true,
|
|
4963
5082
|
ipLookupTimeoutMs: DEFAULT_IP_LOOKUP_TIMEOUT_MS,
|
|
4964
5083
|
resolver: null,
|
|
@@ -5001,8 +5120,8 @@ var normalizeScreenshotWatermarkify = (value) => {
|
|
|
5001
5120
|
response: source.response ?? null,
|
|
5002
5121
|
ip: normalizeText(source.ip),
|
|
5003
5122
|
location: normalizeText(source.location),
|
|
5004
|
-
|
|
5005
|
-
|
|
5123
|
+
prompt: normalizeWhitespace(source.prompt),
|
|
5124
|
+
query: normalizeWhitespace(source.query),
|
|
5006
5125
|
ipLookup: source.ipLookup !== false,
|
|
5007
5126
|
ipLookupTimeoutMs: Number.isFinite(ipLookupTimeoutMsRaw) ? ipLookupTimeoutMsRaw : DEFAULT_IP_LOOKUP_TIMEOUT_MS,
|
|
5008
5127
|
resolver: typeof source.resolver === "function" ? source.resolver : null,
|
|
@@ -5021,16 +5140,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
5021
5140
|
const url = normalizeText(page?.url?.()) || "about:blank";
|
|
5022
5141
|
const title = normalizeText(await page.title().catch(() => "")) || "\u672A\u547D\u540D\u9875\u9762";
|
|
5023
5142
|
const hostname = getHostname(url);
|
|
5024
|
-
const query =
|
|
5025
|
-
const
|
|
5026
|
-
const captureTime = formatTimestampForUtcOffset(
|
|
5143
|
+
const { prompt, query } = resolvePromptFields(options, title);
|
|
5144
|
+
const capturedAt = options.capturedAt instanceof Date ? options.capturedAt : new Date(options.capturedAt || Date.now());
|
|
5145
|
+
const captureTime = formatTimestampForUtcOffset(capturedAt, timezoneOffsetHours);
|
|
5027
5146
|
const [enrichment, stripLogoSrc] = await Promise.all([
|
|
5028
5147
|
resolveEnrichment(page, {
|
|
5029
5148
|
url,
|
|
5030
5149
|
hostname,
|
|
5031
5150
|
title,
|
|
5032
|
-
|
|
5033
|
-
|
|
5151
|
+
prompt,
|
|
5152
|
+
query
|
|
5034
5153
|
}, options),
|
|
5035
5154
|
resolveStripLogoSrc()
|
|
5036
5155
|
]);
|
|
@@ -5038,13 +5157,13 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
5038
5157
|
const location = enrichment.location || "-";
|
|
5039
5158
|
return {
|
|
5040
5159
|
watermarkText: buildWatermarkStamp({
|
|
5041
|
-
|
|
5160
|
+
prompt,
|
|
5042
5161
|
captureTime,
|
|
5043
5162
|
ip,
|
|
5044
5163
|
location
|
|
5045
5164
|
}),
|
|
5046
5165
|
stripSegments: buildStripSegments({
|
|
5047
|
-
|
|
5166
|
+
prompt,
|
|
5048
5167
|
captureTime,
|
|
5049
5168
|
ip,
|
|
5050
5169
|
location
|
|
@@ -5054,396 +5173,509 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
5054
5173
|
stripLogoSrc
|
|
5055
5174
|
};
|
|
5056
5175
|
};
|
|
5057
|
-
var
|
|
5058
|
-
|
|
5059
|
-
const
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5176
|
+
var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
|
|
5177
|
+
var buildStripSegmentLayout = (segment, options = {}) => {
|
|
5178
|
+
const label = normalizeWhitespace(segment?.label || "");
|
|
5179
|
+
const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
|
|
5180
|
+
const labelFontSize = DEFAULT_STRIP_LABEL_FONT_SIZE;
|
|
5181
|
+
const valueFontSize = DEFAULT_STRIP_VALUE_FONT_SIZE;
|
|
5182
|
+
const labelWidth = Math.max(
|
|
5183
|
+
DEFAULT_STRIP_LABEL_WIDTH,
|
|
5184
|
+
estimateTextWidth(label, labelFontSize) + DEFAULT_STRIP_LABEL_PADDING
|
|
5185
|
+
);
|
|
5186
|
+
const rawValueWidth = Math.max(
|
|
5187
|
+
24,
|
|
5188
|
+
estimateTextWidth(rawValue, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING
|
|
5189
|
+
);
|
|
5190
|
+
const maxValueWidth = Math.max(0, Number(options.valueMaxWidth) || 0);
|
|
5191
|
+
const renderValue = maxValueWidth > 0 ? fitTextWithEllipsis(rawValue, Math.max(18, maxValueWidth - DEFAULT_STRIP_VALUE_PADDING), valueFontSize) : rawValue;
|
|
5192
|
+
const valueWidth = maxValueWidth > 0 ? Math.max(24, Math.min(maxValueWidth, estimateTextWidth(renderValue, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING)) : rawValueWidth;
|
|
5193
|
+
return {
|
|
5194
|
+
...segment,
|
|
5195
|
+
label,
|
|
5196
|
+
rawValue,
|
|
5197
|
+
renderValue,
|
|
5198
|
+
labelFontSize,
|
|
5199
|
+
valueFontSize,
|
|
5200
|
+
labelWidth,
|
|
5201
|
+
valueWidth,
|
|
5202
|
+
segmentWidth: labelWidth + valueWidth,
|
|
5203
|
+
rowHeight: Math.round(Math.max(labelFontSize, valueFontSize) * 1.42)
|
|
5204
|
+
};
|
|
5205
|
+
};
|
|
5206
|
+
var buildStripRowLayout = (segments, overrides = {}) => {
|
|
5207
|
+
const safeSegments = Array.isArray(segments) ? segments : [];
|
|
5208
|
+
const sectionGap = DEFAULT_STRIP_SECTION_GAP;
|
|
5209
|
+
const layouts = safeSegments.map((segment, index) => buildStripSegmentLayout(segment, {
|
|
5210
|
+
valueMaxWidth: overrides?.valueMaxWidths?.[index]
|
|
5211
|
+
}));
|
|
5212
|
+
const totalWidth = layouts.reduce((sum, segment) => sum + segment.segmentWidth, 0) + Math.max(0, layouts.length - 1) * sectionGap;
|
|
5213
|
+
const rowHeight = layouts.reduce((max, segment) => Math.max(max, segment.rowHeight || 0), 0);
|
|
5214
|
+
return {
|
|
5215
|
+
sectionGap,
|
|
5216
|
+
layouts,
|
|
5217
|
+
totalWidth,
|
|
5218
|
+
rowHeight
|
|
5219
|
+
};
|
|
5220
|
+
};
|
|
5221
|
+
var fitTextWithEllipsis = (chars, maxWidth, fontSize) => {
|
|
5222
|
+
const safeChars = Array.isArray(chars) ? chars.slice() : Array.from(String(chars || ""));
|
|
5223
|
+
if (!safeChars.length) {
|
|
5224
|
+
return "-";
|
|
5225
|
+
}
|
|
5226
|
+
if (estimateTextWidth(safeChars.join(""), fontSize) <= maxWidth) {
|
|
5227
|
+
return safeChars.join("").trim() || "-";
|
|
5063
5228
|
}
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5229
|
+
while (safeChars.length > 1 && estimateTextWidth(`${safeChars.join("").trimEnd()}\u2026`, fontSize) > maxWidth) {
|
|
5230
|
+
safeChars.pop();
|
|
5231
|
+
}
|
|
5232
|
+
return `${safeChars.join("").trimEnd()}\u2026` || "\u2026";
|
|
5233
|
+
};
|
|
5234
|
+
var splitTextToLines = (value, maxWidth, fontSize, maxLines = 2) => {
|
|
5235
|
+
const chars = Array.from(normalizeWhitespace(value) || "-");
|
|
5236
|
+
const safeMaxWidth = Math.max(18, maxWidth - DEFAULT_STRIP_TEXT_WIDTH_SAFETY);
|
|
5237
|
+
if (!chars.length) {
|
|
5238
|
+
return { lines: ["-"], truncated: false };
|
|
5239
|
+
}
|
|
5240
|
+
const lines = [];
|
|
5241
|
+
let cursor = 0;
|
|
5242
|
+
let truncated = false;
|
|
5243
|
+
while (cursor < chars.length && lines.length < maxLines) {
|
|
5244
|
+
while (cursor < chars.length && chars[cursor] === " ") {
|
|
5245
|
+
cursor += 1;
|
|
5068
5246
|
}
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
const
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
host.style.width = "100vw";
|
|
5083
|
-
host.style.height = "100vh";
|
|
5084
|
-
host.style.pointerEvents = "none";
|
|
5085
|
-
host.style.zIndex = "2147483646";
|
|
5086
|
-
const shadow = host.attachShadow({ mode: "open" });
|
|
5087
|
-
const style = document.createElement("style");
|
|
5088
|
-
style.textContent = `
|
|
5089
|
-
:host {
|
|
5090
|
-
all: initial;
|
|
5091
|
-
position: fixed;
|
|
5092
|
-
inset: 0;
|
|
5093
|
-
width: 100vw;
|
|
5094
|
-
height: 100vh;
|
|
5095
|
-
pointer-events: none;
|
|
5096
|
-
z-index: 2147483646;
|
|
5097
|
-
}
|
|
5098
|
-
|
|
5099
|
-
.root {
|
|
5100
|
-
position: absolute;
|
|
5101
|
-
inset: 0;
|
|
5102
|
-
width: 100%;
|
|
5103
|
-
height: 100%;
|
|
5104
|
-
overflow: hidden;
|
|
5105
|
-
pointer-events: none;
|
|
5106
|
-
font-family: MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
|
|
5107
|
-
}
|
|
5108
|
-
|
|
5109
|
-
.watermark {
|
|
5110
|
-
position: absolute;
|
|
5111
|
-
inset: 0;
|
|
5112
|
-
overflow: hidden;
|
|
5113
|
-
pointer-events: none;
|
|
5114
|
-
}
|
|
5115
|
-
|
|
5116
|
-
.wmStamp {
|
|
5117
|
-
position: absolute;
|
|
5118
|
-
left: 0;
|
|
5119
|
-
top: 0;
|
|
5120
|
-
transform-origin: left center;
|
|
5121
|
-
pointer-events: none;
|
|
5122
|
-
white-space: nowrap;
|
|
5123
|
-
}
|
|
5124
|
-
|
|
5125
|
-
.wmStampText {
|
|
5126
|
-
color: rgba(17, 17, 17, var(--wm-opacity, 0.15));
|
|
5127
|
-
font-size: 19px;
|
|
5128
|
-
font-weight: 720;
|
|
5129
|
-
line-height: 1;
|
|
5130
|
-
letter-spacing: 0.032em;
|
|
5131
|
-
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.44);
|
|
5132
|
-
-webkit-text-stroke: 0.22px rgba(255, 255, 255, 0.12);
|
|
5133
|
-
font-variant-numeric: tabular-nums;
|
|
5134
|
-
filter: saturate(0.92);
|
|
5135
|
-
}
|
|
5136
|
-
|
|
5137
|
-
.strip {
|
|
5138
|
-
position: absolute;
|
|
5139
|
-
left: 0;
|
|
5140
|
-
right: 0;
|
|
5141
|
-
bottom: 0;
|
|
5142
|
-
min-height: 78px;
|
|
5143
|
-
padding: 0 22px 0 20px;
|
|
5144
|
-
display: flex;
|
|
5145
|
-
align-items: center;
|
|
5146
|
-
overflow: hidden;
|
|
5147
|
-
border-top: 1px solid rgba(17, 17, 17, 0.1);
|
|
5148
|
-
background:
|
|
5149
|
-
linear-gradient(180deg, rgba(255, 255, 255, 0.995) 0%, rgba(248, 248, 247, 0.985) 100%);
|
|
5150
|
-
box-shadow:
|
|
5151
|
-
0 -22px 48px rgba(15, 23, 42, 0.1),
|
|
5152
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.92);
|
|
5153
|
-
backdrop-filter: blur(16px);
|
|
5154
|
-
-webkit-backdrop-filter: blur(16px);
|
|
5155
|
-
}
|
|
5156
|
-
|
|
5157
|
-
.strip::before {
|
|
5158
|
-
content: "";
|
|
5159
|
-
position: absolute;
|
|
5160
|
-
left: 20px;
|
|
5161
|
-
right: 52%;
|
|
5162
|
-
top: 0;
|
|
5163
|
-
height: 2px;
|
|
5164
|
-
border-radius: 999px;
|
|
5165
|
-
background: linear-gradient(
|
|
5166
|
-
90deg,
|
|
5167
|
-
rgba(17, 17, 17, 0.98) 0%,
|
|
5168
|
-
rgba(17, 17, 17, 0.68) 24%,
|
|
5169
|
-
rgba(17, 17, 17, 0.08) 58%,
|
|
5170
|
-
rgba(17, 17, 17, 0) 100%
|
|
5171
|
-
);
|
|
5172
|
-
}
|
|
5173
|
-
|
|
5174
|
-
.stripInner {
|
|
5175
|
-
position: relative;
|
|
5176
|
-
z-index: 1;
|
|
5177
|
-
display: flex;
|
|
5178
|
-
align-items: center;
|
|
5179
|
-
gap: 16px;
|
|
5180
|
-
width: 100%;
|
|
5181
|
-
min-width: 0;
|
|
5182
|
-
}
|
|
5183
|
-
|
|
5184
|
-
.stripLogo {
|
|
5185
|
-
position: relative;
|
|
5186
|
-
width: 28px;
|
|
5187
|
-
height: 28px;
|
|
5188
|
-
flex: none;
|
|
5189
|
-
display: flex;
|
|
5190
|
-
align-items: center;
|
|
5191
|
-
justify-content: center;
|
|
5192
|
-
}
|
|
5193
|
-
|
|
5194
|
-
.stripLogoImg {
|
|
5195
|
-
width: 28px;
|
|
5196
|
-
height: 28px;
|
|
5197
|
-
object-fit: contain;
|
|
5198
|
-
display: block;
|
|
5199
|
-
}
|
|
5200
|
-
|
|
5201
|
-
.segments {
|
|
5202
|
-
display: flex;
|
|
5203
|
-
align-items: center;
|
|
5204
|
-
gap: 0;
|
|
5205
|
-
flex: 1 1 auto;
|
|
5206
|
-
min-width: 0;
|
|
5207
|
-
white-space: nowrap;
|
|
5208
|
-
}
|
|
5209
|
-
|
|
5210
|
-
.segment {
|
|
5211
|
-
position: relative;
|
|
5212
|
-
display: inline-flex;
|
|
5213
|
-
align-items: center;
|
|
5214
|
-
gap: 10px;
|
|
5215
|
-
min-width: 0;
|
|
5216
|
-
flex: none;
|
|
5217
|
-
padding-right: 16px;
|
|
5218
|
-
margin-right: 16px;
|
|
5219
|
-
}
|
|
5220
|
-
|
|
5221
|
-
.segment:not(:last-child)::after {
|
|
5222
|
-
content: "";
|
|
5223
|
-
position: absolute;
|
|
5224
|
-
top: 50%;
|
|
5225
|
-
right: 0;
|
|
5226
|
-
width: 1px;
|
|
5227
|
-
height: 25px;
|
|
5228
|
-
transform: translateY(-50%);
|
|
5229
|
-
background: linear-gradient(
|
|
5230
|
-
180deg,
|
|
5231
|
-
rgba(148, 163, 184, 0) 0%,
|
|
5232
|
-
rgba(148, 163, 184, 0.34) 24%,
|
|
5233
|
-
rgba(148, 163, 184, 0.34) 76%,
|
|
5234
|
-
rgba(148, 163, 184, 0) 100%
|
|
5235
|
-
);
|
|
5236
|
-
}
|
|
5237
|
-
|
|
5238
|
-
.segmentTaskId {
|
|
5239
|
-
flex: 1 1 auto;
|
|
5240
|
-
max-width: none;
|
|
5241
|
-
min-width: 0;
|
|
5242
|
-
}
|
|
5243
|
-
|
|
5244
|
-
.label {
|
|
5245
|
-
width: 52px;
|
|
5246
|
-
color: rgba(17, 17, 17, 0.42);
|
|
5247
|
-
font-size: 12px;
|
|
5248
|
-
font-weight: 600;
|
|
5249
|
-
line-height: 1;
|
|
5250
|
-
letter-spacing: 0.01em;
|
|
5251
|
-
flex: none;
|
|
5252
|
-
display: inline-flex;
|
|
5253
|
-
align-items: center;
|
|
5254
|
-
justify-content: flex-start;
|
|
5255
|
-
}
|
|
5256
|
-
|
|
5257
|
-
.value {
|
|
5258
|
-
color: #111111;
|
|
5259
|
-
font-size: 18px;
|
|
5260
|
-
font-weight: 710;
|
|
5261
|
-
line-height: 1;
|
|
5262
|
-
min-width: 0;
|
|
5263
|
-
overflow: hidden;
|
|
5264
|
-
text-overflow: ellipsis;
|
|
5265
|
-
font-variant-numeric: tabular-nums;
|
|
5266
|
-
display: inline-flex;
|
|
5267
|
-
align-items: center;
|
|
5268
|
-
}
|
|
5269
|
-
|
|
5270
|
-
.segmentTaskId .value {
|
|
5271
|
-
color: #101010;
|
|
5272
|
-
font-size: 15px;
|
|
5273
|
-
font-weight: 760;
|
|
5274
|
-
letter-spacing: -0.01em;
|
|
5275
|
-
}
|
|
5276
|
-
|
|
5277
|
-
.segmentTime .value {
|
|
5278
|
-
color: #202020;
|
|
5279
|
-
font-size: 17px;
|
|
5280
|
-
font-weight: 700;
|
|
5281
|
-
}
|
|
5282
|
-
|
|
5283
|
-
.segmentLocation .value,
|
|
5284
|
-
.segmentIp .value {
|
|
5285
|
-
color: #2a2a2a;
|
|
5286
|
-
font-size: 17px;
|
|
5287
|
-
font-weight: 700;
|
|
5288
|
-
}
|
|
5289
|
-
|
|
5290
|
-
`;
|
|
5291
|
-
const root = createNode("div", "root");
|
|
5292
|
-
const watermarkNode = createNode("div", "watermark");
|
|
5293
|
-
const stripNode = createNode("div", "strip");
|
|
5294
|
-
const stripInner = createNode("div", "stripInner");
|
|
5295
|
-
const stripLogo = createNode("div", "stripLogo");
|
|
5296
|
-
const stripLogoImg = createNode("img", "stripLogoImg");
|
|
5297
|
-
const stripSegmentsNode = createNode("div", "segments");
|
|
5298
|
-
stripLogoImg.alt = "";
|
|
5299
|
-
stripLogoImg.decoding = "async";
|
|
5300
|
-
stripLogoImg.referrerPolicy = "no-referrer";
|
|
5301
|
-
stripLogoImg.src = safeText(watermarkifyMeta?.stripLogoSrc) || defaults.logoUrl;
|
|
5302
|
-
stripLogo.appendChild(stripLogoImg);
|
|
5303
|
-
stripInner.appendChild(stripLogo);
|
|
5304
|
-
stripInner.appendChild(stripSegmentsNode);
|
|
5305
|
-
stripNode.appendChild(stripInner);
|
|
5306
|
-
root.appendChild(watermarkNode);
|
|
5307
|
-
root.appendChild(stripNode);
|
|
5308
|
-
shadow.appendChild(style);
|
|
5309
|
-
shadow.appendChild(root);
|
|
5310
|
-
mountPoint.appendChild(host);
|
|
5311
|
-
const buildSegmentNode = (segment) => {
|
|
5312
|
-
const kind = String(segment?.kind || "").trim();
|
|
5313
|
-
const label = String(segment?.label || "").trim();
|
|
5314
|
-
const value = String(segment?.value || "").trim();
|
|
5315
|
-
const rawValue = String(segment?.rawValue || value).trim();
|
|
5316
|
-
const classSuffix = kind ? ` segment${kind.slice(0, 1).toUpperCase()}${kind.slice(1)}` : "";
|
|
5317
|
-
const segmentNode = createNode("span", `segment${classSuffix}`);
|
|
5318
|
-
const labelNode = createNode("span", "label");
|
|
5319
|
-
const valueNode = createNode("span", "value");
|
|
5320
|
-
labelNode.textContent = label;
|
|
5321
|
-
valueNode.textContent = value;
|
|
5322
|
-
segmentNode.title = rawValue ? `${label} ${rawValue}` : label;
|
|
5323
|
-
segmentNode.appendChild(labelNode);
|
|
5324
|
-
segmentNode.appendChild(valueNode);
|
|
5325
|
-
return segmentNode;
|
|
5326
|
-
};
|
|
5327
|
-
const renderStrip = () => {
|
|
5328
|
-
const stripSegments = Array.isArray(watermarkifyMeta?.stripSegments) ? watermarkifyMeta.stripSegments : [];
|
|
5329
|
-
if (!watermarkifyMeta?.strip?.enabled || stripSegments.length === 0) {
|
|
5330
|
-
stripNode.remove();
|
|
5331
|
-
return;
|
|
5332
|
-
}
|
|
5333
|
-
const fragment = document.createDocumentFragment();
|
|
5334
|
-
for (const segment of stripSegments) {
|
|
5335
|
-
fragment.appendChild(buildSegmentNode(segment));
|
|
5336
|
-
}
|
|
5337
|
-
stripSegmentsNode.replaceChildren(fragment);
|
|
5338
|
-
};
|
|
5339
|
-
const waitForLogo = async () => {
|
|
5340
|
-
if (!stripLogoImg.getAttribute("src")) {
|
|
5341
|
-
return;
|
|
5342
|
-
}
|
|
5343
|
-
await new Promise((resolve) => {
|
|
5344
|
-
let settled = false;
|
|
5345
|
-
const done = () => {
|
|
5346
|
-
if (settled) return;
|
|
5347
|
-
settled = true;
|
|
5348
|
-
resolve();
|
|
5349
|
-
};
|
|
5350
|
-
const fail = () => {
|
|
5351
|
-
if (settled) return;
|
|
5352
|
-
stripLogo.remove();
|
|
5353
|
-
done();
|
|
5354
|
-
};
|
|
5355
|
-
const timeoutDone = () => {
|
|
5356
|
-
if (settled) return;
|
|
5357
|
-
done();
|
|
5358
|
-
};
|
|
5359
|
-
if (stripLogoImg.complete && stripLogoImg.naturalWidth > 0) {
|
|
5360
|
-
done();
|
|
5361
|
-
return;
|
|
5362
|
-
}
|
|
5363
|
-
if (stripLogoImg.complete && stripLogoImg.naturalWidth === 0) {
|
|
5364
|
-
fail();
|
|
5365
|
-
return;
|
|
5366
|
-
}
|
|
5367
|
-
stripLogoImg.addEventListener("load", done, { once: true });
|
|
5368
|
-
stripLogoImg.addEventListener("error", fail, { once: true });
|
|
5369
|
-
setTimeout(timeoutDone, 2500);
|
|
5370
|
-
});
|
|
5371
|
-
};
|
|
5372
|
-
const renderWatermark = () => {
|
|
5373
|
-
const stampText = safeText(watermarkifyMeta?.watermarkText);
|
|
5374
|
-
if (!watermarkifyMeta?.watermark?.enabled || !stampText) {
|
|
5375
|
-
watermarkNode.remove();
|
|
5376
|
-
return;
|
|
5377
|
-
}
|
|
5378
|
-
const cellWidth = Math.max(680, Number(watermarkifyMeta.watermark.cellWidth) || defaults.cellWidth);
|
|
5379
|
-
const cellHeight = Math.max(260, Number(watermarkifyMeta.watermark.cellHeight) || defaults.cellHeight);
|
|
5380
|
-
const rotateDeg = Number(watermarkifyMeta.watermark.rotateDeg) || defaults.rotateDeg;
|
|
5381
|
-
const opacity = Math.min(0.22, Math.max(0.05, Number(watermarkifyMeta.watermark.opacity) || defaults.opacity));
|
|
5382
|
-
const width = watermarkNode.clientWidth || window.innerWidth || document.documentElement.clientWidth || cellWidth;
|
|
5383
|
-
const height = watermarkNode.clientHeight || window.innerHeight || document.documentElement.clientHeight || cellHeight;
|
|
5384
|
-
const rowOffset = Math.round(cellWidth * 0.24);
|
|
5385
|
-
const startX = -Math.round(cellWidth * 0.16);
|
|
5386
|
-
const startY = -Math.round(cellHeight * 0.12);
|
|
5387
|
-
const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
|
|
5388
|
-
const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
|
|
5389
|
-
const fragment = document.createDocumentFragment();
|
|
5390
|
-
for (let row = 0; row < rows; row += 1) {
|
|
5391
|
-
for (let col = 0; col < cols; col += 1) {
|
|
5392
|
-
const stamp = createNode("div", "wmStamp");
|
|
5393
|
-
const stampTextNode = createNode("div", "wmStampText");
|
|
5394
|
-
const x = startX + col * cellWidth + (row % 2 ? rowOffset : 0);
|
|
5395
|
-
const y = startY + row * cellHeight + (row % 2 ? 14 : -8);
|
|
5396
|
-
stamp.style.transform = `translate(${x}px, ${y}px) rotate(${rotateDeg}deg)`;
|
|
5397
|
-
stampTextNode.style.setProperty("--wm-opacity", String(opacity));
|
|
5398
|
-
stampTextNode.textContent = stampText;
|
|
5399
|
-
stamp.appendChild(stampTextNode);
|
|
5400
|
-
fragment.appendChild(stamp);
|
|
5401
|
-
}
|
|
5247
|
+
if (cursor >= chars.length) {
|
|
5248
|
+
break;
|
|
5249
|
+
}
|
|
5250
|
+
const isLastLine = lines.length === maxLines - 1;
|
|
5251
|
+
const lineChars = [];
|
|
5252
|
+
while (cursor < chars.length) {
|
|
5253
|
+
const nextChars = [...lineChars, chars[cursor]];
|
|
5254
|
+
const remaining = cursor < chars.length - 1;
|
|
5255
|
+
const previewText = nextChars.join("") + (isLastLine && remaining ? "\u2026" : "");
|
|
5256
|
+
if (estimateTextWidth(previewText, fontSize) <= safeMaxWidth || lineChars.length === 0) {
|
|
5257
|
+
lineChars.push(chars[cursor]);
|
|
5258
|
+
cursor += 1;
|
|
5259
|
+
continue;
|
|
5402
5260
|
}
|
|
5403
|
-
|
|
5404
|
-
}
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5261
|
+
break;
|
|
5262
|
+
}
|
|
5263
|
+
while (cursor < chars.length && chars[cursor] === " ") {
|
|
5264
|
+
cursor += 1;
|
|
5265
|
+
}
|
|
5266
|
+
if (isLastLine && cursor < chars.length) {
|
|
5267
|
+
lines.push(fitTextWithEllipsis([...lineChars, ...chars.slice(cursor)], safeMaxWidth, fontSize));
|
|
5268
|
+
truncated = true;
|
|
5269
|
+
cursor = chars.length;
|
|
5270
|
+
continue;
|
|
5271
|
+
}
|
|
5272
|
+
lines.push(lineChars.join("").trim() || "-");
|
|
5273
|
+
}
|
|
5274
|
+
return {
|
|
5275
|
+
lines: lines.length > 0 ? lines : ["-"],
|
|
5276
|
+
truncated
|
|
5277
|
+
};
|
|
5278
|
+
};
|
|
5279
|
+
var resolveMetadataMinValueWidth = (segment) => {
|
|
5280
|
+
switch (segment?.kind) {
|
|
5281
|
+
case "time":
|
|
5282
|
+
return Math.max(148, estimateTextWidth("2026-04-23 21:27:16 UTC+8", DEFAULT_STRIP_VALUE_FONT_SIZE) + 8);
|
|
5283
|
+
case "ip":
|
|
5284
|
+
return Math.max(108, estimateTextWidth("255.255.255.255", DEFAULT_STRIP_VALUE_FONT_SIZE) + 8);
|
|
5285
|
+
case "location":
|
|
5286
|
+
return 76;
|
|
5287
|
+
default:
|
|
5288
|
+
return 56;
|
|
5289
|
+
}
|
|
5290
|
+
};
|
|
5291
|
+
var buildMetadataRowLayout = (segments, contentWidth) => {
|
|
5292
|
+
const safeSegments = Array.isArray(segments) ? segments.filter(Boolean) : [];
|
|
5293
|
+
const naturalRow = buildStripRowLayout(safeSegments);
|
|
5294
|
+
if (!safeSegments.length || naturalRow.totalWidth <= contentWidth) {
|
|
5295
|
+
return naturalRow;
|
|
5296
|
+
}
|
|
5297
|
+
const sectionGap = naturalRow.sectionGap;
|
|
5298
|
+
const totalLabelWidth = naturalRow.layouts.reduce((sum, segment) => sum + segment.labelWidth, 0);
|
|
5299
|
+
const availableValueWidth = Math.max(
|
|
5300
|
+
72,
|
|
5301
|
+
Math.floor(contentWidth - totalLabelWidth - Math.max(0, safeSegments.length - 1) * sectionGap)
|
|
5302
|
+
);
|
|
5303
|
+
const minValueWidths = naturalRow.layouts.map((segment) => resolveMetadataMinValueWidth(segment));
|
|
5304
|
+
const naturalValueWidths = naturalRow.layouts.map((segment) => segment.valueWidth);
|
|
5305
|
+
const valueWidths = naturalValueWidths.slice();
|
|
5306
|
+
let overflow = naturalRow.totalWidth - contentWidth;
|
|
5307
|
+
const shrinkOrder = ["location", "ip", "time"];
|
|
5308
|
+
shrinkOrder.forEach((kind) => {
|
|
5309
|
+
if (overflow <= 0) return;
|
|
5310
|
+
naturalRow.layouts.forEach((segment, index) => {
|
|
5311
|
+
if (overflow <= 0 || segment.kind !== kind) return;
|
|
5312
|
+
const minWidth = minValueWidths[index];
|
|
5313
|
+
const reducible = Math.max(0, valueWidths[index] - minWidth);
|
|
5314
|
+
if (!reducible) return;
|
|
5315
|
+
const reduction = Math.min(reducible, overflow);
|
|
5316
|
+
valueWidths[index] -= reduction;
|
|
5317
|
+
overflow -= reduction;
|
|
5318
|
+
});
|
|
5319
|
+
});
|
|
5320
|
+
if (overflow > 0) {
|
|
5321
|
+
const minTotalWidth = minValueWidths.reduce((sum, width) => sum + width, 0);
|
|
5322
|
+
if (minTotalWidth > availableValueWidth) {
|
|
5323
|
+
const flexibleIndexes = naturalRow.layouts.map((segment, index) => ({ segment, index })).filter(({ segment }) => segment.kind !== "time");
|
|
5324
|
+
let extraOverflow = minTotalWidth - availableValueWidth;
|
|
5325
|
+
flexibleIndexes.forEach(({ index }) => {
|
|
5326
|
+
if (extraOverflow <= 0) return;
|
|
5327
|
+
const minFloor = 40;
|
|
5328
|
+
const reducible = Math.max(0, minValueWidths[index] - minFloor);
|
|
5329
|
+
if (!reducible) return;
|
|
5330
|
+
const reduction = Math.min(reducible, extraOverflow);
|
|
5331
|
+
valueWidths[index] -= reduction;
|
|
5332
|
+
extraOverflow -= reduction;
|
|
5411
5333
|
});
|
|
5412
|
-
};
|
|
5413
|
-
const handleResize = () => {
|
|
5414
|
-
queueWatermarkRender();
|
|
5415
|
-
};
|
|
5416
|
-
host.__pkCleanup = () => {
|
|
5417
|
-
cancelAnimationFrame(resizeFrame);
|
|
5418
|
-
window.removeEventListener("resize", handleResize);
|
|
5419
|
-
};
|
|
5420
|
-
renderStrip();
|
|
5421
|
-
renderWatermark();
|
|
5422
|
-
queueWatermarkRender();
|
|
5423
|
-
window.addEventListener("resize", handleResize, { passive: true });
|
|
5424
|
-
return waitForLogo();
|
|
5425
|
-
}, {
|
|
5426
|
-
hostId: SCREENSHOT_WATERMARKIFY_HOST_ID,
|
|
5427
|
-
watermarkifyMeta: meta,
|
|
5428
|
-
defaults: {
|
|
5429
|
-
opacity: DEFAULT_WATERMARK_OPACITY,
|
|
5430
|
-
rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
|
|
5431
|
-
cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
|
|
5432
|
-
cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT,
|
|
5433
|
-
logoUrl: DEFAULT_STRIP_LOGO_URL
|
|
5434
5334
|
}
|
|
5335
|
+
}
|
|
5336
|
+
return buildStripRowLayout(safeSegments, {
|
|
5337
|
+
valueMaxWidths: valueWidths
|
|
5435
5338
|
});
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5339
|
+
};
|
|
5340
|
+
var buildPromptWrapLayout = (segment, contentWidth) => {
|
|
5341
|
+
const label = normalizeWhitespace(segment?.label || "Prompt") || "Prompt";
|
|
5342
|
+
const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
|
|
5343
|
+
const labelFontSize = DEFAULT_STRIP_LABEL_FONT_SIZE;
|
|
5344
|
+
const valueFontSize = DEFAULT_STRIP_VALUE_FONT_SIZE;
|
|
5345
|
+
const labelWidth = Math.max(
|
|
5346
|
+
DEFAULT_STRIP_LABEL_WIDTH,
|
|
5347
|
+
estimateTextWidth(label, labelFontSize) + DEFAULT_STRIP_LABEL_PADDING
|
|
5348
|
+
);
|
|
5349
|
+
const safeTotalWidth = Math.max(labelWidth + 56, Number(contentWidth) || 0);
|
|
5350
|
+
const valueWidth = Math.max(
|
|
5351
|
+
56,
|
|
5352
|
+
safeTotalWidth - labelWidth - DEFAULT_STRIP_CONTENT_SAFE_PADDING_X
|
|
5353
|
+
);
|
|
5354
|
+
const result = splitTextToLines(rawValue, valueWidth, valueFontSize, DEFAULT_STRIP_PROMPT_MAX_LINES);
|
|
5355
|
+
const lineHeight = Math.max(18, Math.round(valueFontSize * DEFAULT_STRIP_LINE_HEIGHT_RATIO));
|
|
5356
|
+
const lineWidths = result.lines.map((line) => estimateTextWidth(line, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING);
|
|
5357
|
+
const measuredValueWidth = Math.min(
|
|
5358
|
+
valueWidth,
|
|
5359
|
+
Math.max(56, ...lineWidths)
|
|
5360
|
+
);
|
|
5361
|
+
const rowHeight = Math.round(Math.max(labelFontSize, valueFontSize) * 1.42);
|
|
5362
|
+
return {
|
|
5363
|
+
mode: result.lines.length === 1 ? "single" : "wrapped",
|
|
5364
|
+
label,
|
|
5365
|
+
rawValue,
|
|
5366
|
+
labelFontSize,
|
|
5367
|
+
labelWidth,
|
|
5368
|
+
valueFontSize,
|
|
5369
|
+
valueWidth,
|
|
5370
|
+
lines: result.lines,
|
|
5371
|
+
truncated: result.truncated,
|
|
5372
|
+
lineHeight,
|
|
5373
|
+
blockHeight: result.lines.length === 1 ? rowHeight : Math.max(lineHeight, result.lines.length * lineHeight),
|
|
5374
|
+
totalWidth: labelWidth + measuredValueWidth
|
|
5375
|
+
};
|
|
5376
|
+
};
|
|
5377
|
+
var buildStripLayout = (segments, contentWidth) => {
|
|
5378
|
+
const safeSegments = Array.isArray(segments) ? segments.filter(Boolean) : [];
|
|
5379
|
+
const promptSegment = safeSegments.find((segment) => segment.kind === "prompt") || safeSegments[0] || null;
|
|
5380
|
+
const metadataSegments = safeSegments.filter((segment) => segment !== promptSegment);
|
|
5381
|
+
const zoneGap = DEFAULT_STRIP_ZONE_GAP;
|
|
5382
|
+
let metadataRow = buildMetadataRowLayout(
|
|
5383
|
+
metadataSegments,
|
|
5384
|
+
Math.max(220, contentWidth)
|
|
5385
|
+
);
|
|
5386
|
+
let metadataStartX = Math.max(0, contentWidth - (metadataRow?.totalWidth || 0));
|
|
5387
|
+
let promptAvailableWidth = Math.max(
|
|
5388
|
+
220,
|
|
5389
|
+
metadataStartX - zoneGap - DEFAULT_STRIP_PROMPT_TRAILING_PADDING
|
|
5390
|
+
);
|
|
5391
|
+
if (promptAvailableWidth < DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH && metadataSegments.length > 0) {
|
|
5392
|
+
const tighterMetadataWidth = Math.max(180, contentWidth - DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH - zoneGap);
|
|
5393
|
+
metadataRow = buildMetadataRowLayout(metadataSegments, tighterMetadataWidth);
|
|
5394
|
+
metadataStartX = Math.max(0, contentWidth - (metadataRow?.totalWidth || 0));
|
|
5395
|
+
promptAvailableWidth = Math.max(
|
|
5396
|
+
220,
|
|
5397
|
+
metadataStartX - zoneGap - DEFAULT_STRIP_PROMPT_TRAILING_PADDING
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
const preferredPromptWidth = Math.min(
|
|
5401
|
+
promptAvailableWidth,
|
|
5402
|
+
Math.max(280, Math.round(contentWidth * DEFAULT_STRIP_PROMPT_PREFERRED_WIDTH_RATIO))
|
|
5403
|
+
);
|
|
5404
|
+
let promptRow = buildPromptWrapLayout(promptSegment, preferredPromptWidth);
|
|
5405
|
+
if (promptRow?.truncated && promptAvailableWidth > preferredPromptWidth + 24) {
|
|
5406
|
+
promptRow = buildPromptWrapLayout(promptSegment, promptAvailableWidth);
|
|
5407
|
+
}
|
|
5408
|
+
const contentHeight = Math.max(
|
|
5409
|
+
promptRow?.blockHeight || 0,
|
|
5410
|
+
metadataRow?.rowHeight || 0,
|
|
5411
|
+
24
|
|
5412
|
+
);
|
|
5413
|
+
const verticalPadding = contentHeight > (metadataRow?.rowHeight || 0) ? 18 : 16;
|
|
5414
|
+
const stripHeight = Math.max(
|
|
5415
|
+
contentHeight > (metadataRow?.rowHeight || 0) ? DEFAULT_STRIP_WRAPPED_MIN_HEIGHT : DEFAULT_STRIP_ONE_LINE_HEIGHT,
|
|
5416
|
+
Math.ceil(contentHeight + verticalPadding * 2)
|
|
5417
|
+
);
|
|
5418
|
+
return {
|
|
5419
|
+
mode: "zoned",
|
|
5420
|
+
height: stripHeight,
|
|
5421
|
+
contentHeight,
|
|
5422
|
+
promptRow,
|
|
5423
|
+
promptStartX: 0,
|
|
5424
|
+
metadataRow,
|
|
5425
|
+
metadataStartX
|
|
5445
5426
|
};
|
|
5446
5427
|
};
|
|
5428
|
+
var renderStripRow = (row, options = {}) => {
|
|
5429
|
+
const startX = Number(options.startX) || 0;
|
|
5430
|
+
const centerY = Number(options.centerY) || 0;
|
|
5431
|
+
const fontFamily = String(options.fontFamily || "");
|
|
5432
|
+
const showDividers = options.showDividers !== false;
|
|
5433
|
+
const layouts = Array.isArray(row?.layouts) ? row.layouts : [];
|
|
5434
|
+
if (!layouts.length) {
|
|
5435
|
+
return "";
|
|
5436
|
+
}
|
|
5437
|
+
const rowHeight = Math.max(18, Number(row?.rowHeight) || 18);
|
|
5438
|
+
const dividerHalfHeight = Math.max(12, Math.round(rowHeight * 0.56));
|
|
5439
|
+
const sectionGap = Math.max(0, Number(row?.sectionGap) || 0);
|
|
5440
|
+
const svgSegments = [];
|
|
5441
|
+
let currentX = startX;
|
|
5442
|
+
layouts.forEach((segment, index) => {
|
|
5443
|
+
const label = escapeXml(segment.label || "");
|
|
5444
|
+
const value = escapeXml(segment.renderValue || "-");
|
|
5445
|
+
const labelX = currentX;
|
|
5446
|
+
const valueX = currentX + segment.labelWidth;
|
|
5447
|
+
svgSegments.push(`
|
|
5448
|
+
<text
|
|
5449
|
+
x="${labelX}"
|
|
5450
|
+
y="${centerY}"
|
|
5451
|
+
fill="#111111"
|
|
5452
|
+
fill-opacity="0.54"
|
|
5453
|
+
font-family="${fontFamily}"
|
|
5454
|
+
font-size="${segment.labelFontSize}"
|
|
5455
|
+
font-weight="650"
|
|
5456
|
+
dominant-baseline="middle"
|
|
5457
|
+
>${label}</text>
|
|
5458
|
+
<text
|
|
5459
|
+
x="${valueX}"
|
|
5460
|
+
y="${centerY}"
|
|
5461
|
+
fill="#111111"
|
|
5462
|
+
font-family="${fontFamily}"
|
|
5463
|
+
font-size="${segment.valueFontSize}"
|
|
5464
|
+
font-weight="${segment.kind === "prompt" ? 760 : 710}"
|
|
5465
|
+
dominant-baseline="middle"
|
|
5466
|
+
>${value}</text>
|
|
5467
|
+
`);
|
|
5468
|
+
currentX += segment.segmentWidth;
|
|
5469
|
+
if (showDividers && index < layouts.length - 1) {
|
|
5470
|
+
const lineX = currentX + Math.round(sectionGap / 2);
|
|
5471
|
+
svgSegments.push(`
|
|
5472
|
+
<line
|
|
5473
|
+
x1="${lineX}"
|
|
5474
|
+
y1="${centerY - dividerHalfHeight}"
|
|
5475
|
+
x2="${lineX}"
|
|
5476
|
+
y2="${centerY + dividerHalfHeight}"
|
|
5477
|
+
stroke="#94a3b8"
|
|
5478
|
+
stroke-opacity="0.34"
|
|
5479
|
+
stroke-width="1"
|
|
5480
|
+
/>
|
|
5481
|
+
`);
|
|
5482
|
+
currentX += sectionGap;
|
|
5483
|
+
}
|
|
5484
|
+
});
|
|
5485
|
+
return svgSegments.join("");
|
|
5486
|
+
};
|
|
5487
|
+
var renderStripDivider = (x, centerY, height) => {
|
|
5488
|
+
const safeX = Number(x) || 0;
|
|
5489
|
+
const safeCenterY = Number(centerY) || 0;
|
|
5490
|
+
const safeHeight = Math.max(18, Number(height) || 18);
|
|
5491
|
+
const halfHeight = Math.max(12, Math.round(safeHeight * 0.56));
|
|
5492
|
+
return `
|
|
5493
|
+
<line
|
|
5494
|
+
x1="${safeX}"
|
|
5495
|
+
y1="${safeCenterY - halfHeight}"
|
|
5496
|
+
x2="${safeX}"
|
|
5497
|
+
y2="${safeCenterY + halfHeight}"
|
|
5498
|
+
stroke="#94a3b8"
|
|
5499
|
+
stroke-opacity="0.34"
|
|
5500
|
+
stroke-width="1"
|
|
5501
|
+
/>
|
|
5502
|
+
`;
|
|
5503
|
+
};
|
|
5504
|
+
var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
|
|
5505
|
+
const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
|
|
5506
|
+
const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
|
|
5507
|
+
if (!hasWatermark && !hasStrip) {
|
|
5508
|
+
return "";
|
|
5509
|
+
}
|
|
5510
|
+
const width = Math.max(1, Number(imageWidth) || 1);
|
|
5511
|
+
const height = Math.max(1, Number(imageHeight) || 1);
|
|
5512
|
+
const fontFamily = escapeXml(buildFontFamily());
|
|
5513
|
+
const parts = [];
|
|
5514
|
+
if (hasWatermark) {
|
|
5515
|
+
const stampText = escapeXml(normalizeText(meta.watermarkText));
|
|
5516
|
+
const cellWidth = Math.max(680, Number(meta.watermark?.cellWidth) || DEFAULT_WATERMARK_CELL_WIDTH);
|
|
5517
|
+
const cellHeight = Math.max(260, Number(meta.watermark?.cellHeight) || DEFAULT_WATERMARK_CELL_HEIGHT);
|
|
5518
|
+
const rotateDeg = Number(meta.watermark?.rotateDeg) || DEFAULT_WATERMARK_ROTATE_DEG;
|
|
5519
|
+
const opacity = Math.min(0.22, Math.max(0.05, Number(meta.watermark?.opacity) || DEFAULT_WATERMARK_OPACITY));
|
|
5520
|
+
const rowOffset = Math.round(cellWidth * 0.24);
|
|
5521
|
+
const startX = -Math.round(cellWidth * 0.16);
|
|
5522
|
+
const startY = -Math.round(cellHeight * 0.12);
|
|
5523
|
+
const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
|
|
5524
|
+
const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
|
|
5525
|
+
const stamps = [];
|
|
5526
|
+
for (let row = 0; row < rows; row += 1) {
|
|
5527
|
+
for (let col = 0; col < cols; col += 1) {
|
|
5528
|
+
const x = startX + col * cellWidth + (row % 2 ? rowOffset : 0);
|
|
5529
|
+
const y = startY + row * cellHeight + (row % 2 ? 14 : -8);
|
|
5530
|
+
stamps.push(`
|
|
5531
|
+
<g transform="translate(${x} ${y}) rotate(${rotateDeg})">
|
|
5532
|
+
<text
|
|
5533
|
+
x="0"
|
|
5534
|
+
y="0"
|
|
5535
|
+
fill="#111111"
|
|
5536
|
+
fill-opacity="${opacity}"
|
|
5537
|
+
stroke="#ffffff"
|
|
5538
|
+
stroke-opacity="0.12"
|
|
5539
|
+
stroke-width="0.22"
|
|
5540
|
+
font-family="${fontFamily}"
|
|
5541
|
+
font-size="19"
|
|
5542
|
+
font-weight="720"
|
|
5543
|
+
letter-spacing="0.6"
|
|
5544
|
+
>${stampText}</text>
|
|
5545
|
+
</g>
|
|
5546
|
+
`);
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5549
|
+
parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
|
|
5550
|
+
}
|
|
5551
|
+
if (hasStrip) {
|
|
5552
|
+
const logoSize = 28;
|
|
5553
|
+
const logoX = DEFAULT_STRIP_PADDING_LEFT;
|
|
5554
|
+
const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
|
|
5555
|
+
const contentWidth = width - contentStartX - DEFAULT_STRIP_PADDING_RIGHT;
|
|
5556
|
+
const stripLayout = buildStripLayout(meta.stripSegments, contentWidth);
|
|
5557
|
+
const stripHeight = stripLayout.height;
|
|
5558
|
+
const stripY = height - stripHeight;
|
|
5559
|
+
const logoY = Number((stripY + (stripHeight - logoSize) / 2).toFixed(2));
|
|
5560
|
+
let stripContentSvg = "";
|
|
5561
|
+
const centerY = stripY + stripHeight / 2 + 1;
|
|
5562
|
+
const promptRow = stripLayout.promptRow;
|
|
5563
|
+
const metadataRow = stripLayout.metadataRow;
|
|
5564
|
+
const promptParts = [];
|
|
5565
|
+
const hasPrompt = Boolean(promptRow?.label);
|
|
5566
|
+
const hasMetadata = Array.isArray(metadataRow?.layouts) && metadataRow.layouts.length > 0;
|
|
5567
|
+
const zoneDividerX = hasPrompt && hasMetadata ? contentStartX + stripLayout.metadataStartX - DEFAULT_STRIP_ZONE_GAP / 2 : null;
|
|
5568
|
+
if (promptRow?.mode === "single") {
|
|
5569
|
+
promptParts.push(renderStripRow({
|
|
5570
|
+
layouts: [
|
|
5571
|
+
{
|
|
5572
|
+
kind: "prompt",
|
|
5573
|
+
label: promptRow.label,
|
|
5574
|
+
renderValue: promptRow.lines[0] || "-",
|
|
5575
|
+
labelFontSize: promptRow.labelFontSize,
|
|
5576
|
+
valueFontSize: promptRow.valueFontSize,
|
|
5577
|
+
labelWidth: promptRow.labelWidth,
|
|
5578
|
+
segmentWidth: promptRow.labelWidth + promptRow.valueWidth
|
|
5579
|
+
}
|
|
5580
|
+
],
|
|
5581
|
+
sectionGap: 0,
|
|
5582
|
+
rowHeight: promptRow.blockHeight
|
|
5583
|
+
}, {
|
|
5584
|
+
startX: contentStartX + stripLayout.promptStartX,
|
|
5585
|
+
centerY,
|
|
5586
|
+
fontFamily,
|
|
5587
|
+
showDividers: false
|
|
5588
|
+
}));
|
|
5589
|
+
} else if (promptRow) {
|
|
5590
|
+
const promptStartX = contentStartX + stripLayout.promptStartX;
|
|
5591
|
+
const labelX = promptStartX;
|
|
5592
|
+
const valueX = promptStartX + promptRow.labelWidth;
|
|
5593
|
+
const blockTop = centerY - promptRow.blockHeight / 2;
|
|
5594
|
+
const labelY = centerY;
|
|
5595
|
+
promptParts.push(`
|
|
5596
|
+
<text
|
|
5597
|
+
x="${labelX}"
|
|
5598
|
+
y="${labelY}"
|
|
5599
|
+
fill="#111111"
|
|
5600
|
+
fill-opacity="0.54"
|
|
5601
|
+
font-family="${fontFamily}"
|
|
5602
|
+
font-size="${promptRow.labelFontSize}"
|
|
5603
|
+
font-weight="650"
|
|
5604
|
+
dominant-baseline="middle"
|
|
5605
|
+
>${escapeXml(promptRow.label)}</text>
|
|
5606
|
+
`);
|
|
5607
|
+
promptRow.lines.forEach((line, index) => {
|
|
5608
|
+
const lineY = blockTop + index * promptRow.lineHeight + promptRow.lineHeight / 2;
|
|
5609
|
+
promptParts.push(`
|
|
5610
|
+
<text
|
|
5611
|
+
x="${valueX}"
|
|
5612
|
+
y="${lineY}"
|
|
5613
|
+
fill="#111111"
|
|
5614
|
+
font-family="${fontFamily}"
|
|
5615
|
+
font-size="${promptRow.valueFontSize}"
|
|
5616
|
+
font-weight="760"
|
|
5617
|
+
dominant-baseline="middle"
|
|
5618
|
+
>${escapeXml(line)}</text>
|
|
5619
|
+
`);
|
|
5620
|
+
});
|
|
5621
|
+
}
|
|
5622
|
+
stripContentSvg = [
|
|
5623
|
+
promptParts.join(""),
|
|
5624
|
+
zoneDividerX == null ? "" : renderStripDivider(
|
|
5625
|
+
zoneDividerX,
|
|
5626
|
+
centerY,
|
|
5627
|
+
Math.max(promptRow?.blockHeight || 0, metadataRow?.rowHeight || 0)
|
|
5628
|
+
),
|
|
5629
|
+
renderStripRow(metadataRow, {
|
|
5630
|
+
startX: contentStartX + stripLayout.metadataStartX,
|
|
5631
|
+
centerY,
|
|
5632
|
+
fontFamily,
|
|
5633
|
+
showDividers: true
|
|
5634
|
+
})
|
|
5635
|
+
].join("");
|
|
5636
|
+
parts.push(`
|
|
5637
|
+
<g id="strip">
|
|
5638
|
+
<rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
|
|
5639
|
+
<rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
|
|
5640
|
+
<rect x="${DEFAULT_STRIP_PADDING_LEFT}" y="${stripY}" width="${Math.max(120, Math.round(width * 0.42))}" height="2" fill="url(#stripAccent)" />
|
|
5641
|
+
${meta.stripLogoSrc ? `<image href="${escapeXml(meta.stripLogoSrc)}" x="${logoX}" y="${logoY}" width="${logoSize}" height="${logoSize}" />` : ""}
|
|
5642
|
+
${stripContentSvg}
|
|
5643
|
+
</g>
|
|
5644
|
+
`);
|
|
5645
|
+
}
|
|
5646
|
+
return `
|
|
5647
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
5648
|
+
<defs>
|
|
5649
|
+
<linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
5650
|
+
<stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
|
|
5651
|
+
<stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
|
|
5652
|
+
<stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
|
|
5653
|
+
<stop offset="100%" stop-color="#111111" stop-opacity="0" />
|
|
5654
|
+
</linearGradient>
|
|
5655
|
+
</defs>
|
|
5656
|
+
${parts.join("")}
|
|
5657
|
+
</svg>
|
|
5658
|
+
`;
|
|
5659
|
+
};
|
|
5660
|
+
var watermarkifyScreenshotBuffer = async (buffer, meta) => {
|
|
5661
|
+
const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
|
|
5662
|
+
const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
|
|
5663
|
+
if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
|
|
5664
|
+
return buffer;
|
|
5665
|
+
}
|
|
5666
|
+
const image = (0, import_sharp.default)(buffer, { failOn: "none" });
|
|
5667
|
+
const metadata = await image.metadata().catch(() => null);
|
|
5668
|
+
const width = Math.max(1, Number(metadata?.width) || 0);
|
|
5669
|
+
const height = Math.max(1, Number(metadata?.height) || 0);
|
|
5670
|
+
if (!width || !height) {
|
|
5671
|
+
return buffer;
|
|
5672
|
+
}
|
|
5673
|
+
const overlaySvg = buildWatermarkifySvg(meta, width, height);
|
|
5674
|
+
if (!overlaySvg) {
|
|
5675
|
+
return buffer;
|
|
5676
|
+
}
|
|
5677
|
+
return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
|
|
5678
|
+
};
|
|
5447
5679
|
|
|
5448
5680
|
// src/share.js
|
|
5449
5681
|
var logger11 = createInternalLogger("Share");
|
|
@@ -5523,6 +5755,20 @@ var normalizeShare = (share) => {
|
|
|
5523
5755
|
xurl: normalizeXurl(source.xurl)
|
|
5524
5756
|
};
|
|
5525
5757
|
};
|
|
5758
|
+
var resolveCaptureScreenWatermarkify = (page, optionValue) => {
|
|
5759
|
+
if (optionValue === false) {
|
|
5760
|
+
return normalizeScreenshotWatermarkify(false);
|
|
5761
|
+
}
|
|
5762
|
+
const runtimeQuery = String(page?.[PageRuntimeStateKey]?.query || "").trim();
|
|
5763
|
+
if (optionValue == null || optionValue === true) {
|
|
5764
|
+
return normalizeScreenshotWatermarkify(runtimeQuery ? { query: runtimeQuery } : true);
|
|
5765
|
+
}
|
|
5766
|
+
const optionSource = optionValue && typeof optionValue === "object" ? optionValue : {};
|
|
5767
|
+
return normalizeScreenshotWatermarkify({
|
|
5768
|
+
...runtimeQuery ? { query: runtimeQuery } : {},
|
|
5769
|
+
...optionSource
|
|
5770
|
+
});
|
|
5771
|
+
};
|
|
5526
5772
|
var getByPathSegments = (source, pathSegments) => {
|
|
5527
5773
|
if (!Array.isArray(pathSegments) || pathSegments.length === 0) return void 0;
|
|
5528
5774
|
let current = source;
|
|
@@ -5846,14 +6092,12 @@ var Share = {
|
|
|
5846
6092
|
* @returns {Promise<string>} base64 png
|
|
5847
6093
|
*/
|
|
5848
6094
|
async captureScreen(page, options = {}) {
|
|
5849
|
-
const originalViewport = page
|
|
5850
|
-
const defaultBuffer = Math.round((originalViewport
|
|
6095
|
+
const originalViewport = await resolveCurrentViewportSize(page);
|
|
6096
|
+
const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
|
|
5851
6097
|
const buffer = options.buffer ?? defaultBuffer;
|
|
5852
6098
|
const restore = options.restore ?? false;
|
|
5853
6099
|
const maxHeight = options.maxHeight ?? 8e3;
|
|
5854
|
-
const screenshotWatermarkify =
|
|
5855
|
-
let cleanupScreenshotWatermarkify = async () => {
|
|
5856
|
-
};
|
|
6100
|
+
const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
|
|
5857
6101
|
try {
|
|
5858
6102
|
const maxScrollHeight = await page.evaluate(() => {
|
|
5859
6103
|
let maxHeight2 = document.body.scrollHeight;
|
|
@@ -5877,23 +6121,26 @@ var Share = {
|
|
|
5877
6121
|
});
|
|
5878
6122
|
const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
|
|
5879
6123
|
await page.setViewportSize({
|
|
5880
|
-
width: originalViewport
|
|
6124
|
+
width: originalViewport.width,
|
|
5881
6125
|
height: targetHeight
|
|
5882
6126
|
});
|
|
5883
6127
|
await (0, import_delay2.default)(1e3);
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
cleanupScreenshotWatermarkify = await installScreenshotWatermarkify(page, watermarkifyMeta);
|
|
5887
|
-
await (0, import_delay2.default)(120);
|
|
5888
|
-
}
|
|
5889
|
-
const buffer_ = await capturePageScreenshot(page, {
|
|
6128
|
+
const capturedAt = /* @__PURE__ */ new Date();
|
|
6129
|
+
const rawBuffer = await capturePageScreenshot(page, {
|
|
5890
6130
|
fullPage: true,
|
|
5891
6131
|
type: "png",
|
|
5892
6132
|
maxClipHeight: targetHeight
|
|
5893
6133
|
});
|
|
6134
|
+
if (!screenshotWatermarkify.enabled) {
|
|
6135
|
+
return rawBuffer.toString("base64");
|
|
6136
|
+
}
|
|
6137
|
+
const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
|
|
6138
|
+
...screenshotWatermarkify,
|
|
6139
|
+
capturedAt
|
|
6140
|
+
});
|
|
6141
|
+
const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
|
|
5894
6142
|
return buffer_.toString("base64");
|
|
5895
6143
|
} finally {
|
|
5896
|
-
await cleanupScreenshotWatermarkify();
|
|
5897
6144
|
if (restore) {
|
|
5898
6145
|
await page.evaluate(() => {
|
|
5899
6146
|
document.querySelectorAll(".__pk_expanded__").forEach((el) => {
|
|
@@ -5906,9 +6153,7 @@ var Share = {
|
|
|
5906
6153
|
el.classList.remove("__pk_expanded__");
|
|
5907
6154
|
});
|
|
5908
6155
|
});
|
|
5909
|
-
|
|
5910
|
-
await page.setViewportSize(originalViewport);
|
|
5911
|
-
}
|
|
6156
|
+
await page.setViewportSize(originalViewport);
|
|
5912
6157
|
}
|
|
5913
6158
|
}
|
|
5914
6159
|
}
|