@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.js
CHANGED
|
@@ -408,6 +408,33 @@ function createInternalLogger(moduleName, explicitLogger) {
|
|
|
408
408
|
};
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
// src/internals/viewport.js
|
|
412
|
+
var toPositiveInt = (value) => {
|
|
413
|
+
const number = Math.round(Number(value) || 0);
|
|
414
|
+
return number > 0 ? number : 0;
|
|
415
|
+
};
|
|
416
|
+
var resolveCurrentViewportSize = async (page, fallback = {}) => {
|
|
417
|
+
const directViewport = page?.viewportSize?.();
|
|
418
|
+
const directWidth = toPositiveInt(directViewport?.width);
|
|
419
|
+
const directHeight = toPositiveInt(directViewport?.height);
|
|
420
|
+
if (directWidth && directHeight) {
|
|
421
|
+
return {
|
|
422
|
+
width: directWidth,
|
|
423
|
+
height: directHeight
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
const measuredViewport = await page?.evaluate?.(() => ({
|
|
427
|
+
width: window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0,
|
|
428
|
+
height: window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0
|
|
429
|
+
})).catch(() => null);
|
|
430
|
+
const fallbackWidth = toPositiveInt(fallback?.width);
|
|
431
|
+
const fallbackHeight = toPositiveInt(fallback?.height);
|
|
432
|
+
return {
|
|
433
|
+
width: toPositiveInt(measuredViewport?.width) || fallbackWidth || 1,
|
|
434
|
+
height: toPositiveInt(measuredViewport?.height) || fallbackHeight || 1
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
|
|
411
438
|
// src/internals/screenshot.js
|
|
412
439
|
var logger = createInternalLogger("Screenshot");
|
|
413
440
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
@@ -434,7 +461,7 @@ var normalizeQuality = (value, type) => {
|
|
|
434
461
|
};
|
|
435
462
|
var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
436
463
|
const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
|
|
437
|
-
const width = Math.max(1, Math.ceil(
|
|
464
|
+
const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
|
|
438
465
|
let height = Math.max(1, Math.ceil(contentSize?.height || viewport.height || 1));
|
|
439
466
|
if (maxClipHeight > 0) {
|
|
440
467
|
height = Math.min(height, maxClipHeight);
|
|
@@ -471,7 +498,7 @@ var capturePageScreenshot = async (page, options = {}) => {
|
|
|
471
498
|
const session = await context.newCDPSession(page);
|
|
472
499
|
try {
|
|
473
500
|
const metrics = await session.send("Page.getLayoutMetrics");
|
|
474
|
-
const viewport = page
|
|
501
|
+
const viewport = await resolveCurrentViewportSize(page);
|
|
475
502
|
const captureParams = {
|
|
476
503
|
format: type,
|
|
477
504
|
fromSurface: true,
|
|
@@ -924,6 +951,9 @@ var ProxyMeterRuntime = {
|
|
|
924
951
|
getProxyMeterSnapshot
|
|
925
952
|
};
|
|
926
953
|
|
|
954
|
+
// src/internals/constants.js
|
|
955
|
+
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
956
|
+
|
|
927
957
|
// src/runtime-env.js
|
|
928
958
|
var BROWSER_PROFILE_SCHEMA_VERSION = 1;
|
|
929
959
|
var rememberedRuntimeState = null;
|
|
@@ -1430,6 +1460,7 @@ var RuntimeEnv = {
|
|
|
1430
1460
|
parseInput(input = {}, actor = "") {
|
|
1431
1461
|
const runtime2 = tryParseJSON(input?.runtime) || {};
|
|
1432
1462
|
const resolvedActor = String(actor || input?.actor || "").trim();
|
|
1463
|
+
const query = String(input?.query || "").trim();
|
|
1433
1464
|
const cookies = normalizeCookies(runtime2?.cookies);
|
|
1434
1465
|
const cookieMap = buildCookieMap(cookies);
|
|
1435
1466
|
const localStorage = normalizeLocalStorage(runtime2?.local_storage);
|
|
@@ -1453,6 +1484,7 @@ var RuntimeEnv = {
|
|
|
1453
1484
|
actor: resolvedActor,
|
|
1454
1485
|
runtime: normalizedRuntime,
|
|
1455
1486
|
envId,
|
|
1487
|
+
query,
|
|
1456
1488
|
auth,
|
|
1457
1489
|
cookies,
|
|
1458
1490
|
cookieMap,
|
|
@@ -1520,6 +1552,12 @@ var RuntimeEnv = {
|
|
|
1520
1552
|
async applyToPage(page, source = {}, options = {}) {
|
|
1521
1553
|
if (!page) return;
|
|
1522
1554
|
const state = normalizeRuntimeState(source, options?.actor || "");
|
|
1555
|
+
Object.defineProperty(page, PageRuntimeStateKey, {
|
|
1556
|
+
configurable: true,
|
|
1557
|
+
enumerable: false,
|
|
1558
|
+
writable: true,
|
|
1559
|
+
value: state
|
|
1560
|
+
});
|
|
1523
1561
|
const localStorage = state.localStorage || {};
|
|
1524
1562
|
const sessionStorage = state.sessionStorage || {};
|
|
1525
1563
|
const cookies = (state.cookies || []).map((cookie) => {
|
|
@@ -4521,7 +4559,7 @@ var Logger = {
|
|
|
4521
4559
|
import delay2 from "delay";
|
|
4522
4560
|
|
|
4523
4561
|
// src/internals/watermarkify.js
|
|
4524
|
-
|
|
4562
|
+
import sharp from "sharp";
|
|
4525
4563
|
var DEFAULT_TIMEZONE_OFFSET = 8;
|
|
4526
4564
|
var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
|
|
4527
4565
|
var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
|
|
@@ -4532,6 +4570,26 @@ var DEFAULT_WATERMARK_CELL_HEIGHT = 330;
|
|
|
4532
4570
|
var DEFAULT_STRIP_LOGO_URL = "https://static.heartbitai.com/geo/icon/favicon.png";
|
|
4533
4571
|
var DEFAULT_IP_LOOKUP_URL = "http://myip.ipip.net";
|
|
4534
4572
|
var DEFAULT_LOGO_FETCH_TIMEOUT_MS = 2500;
|
|
4573
|
+
var DEFAULT_STRIP_ONE_LINE_HEIGHT = 78;
|
|
4574
|
+
var DEFAULT_STRIP_WRAPPED_MIN_HEIGHT = 108;
|
|
4575
|
+
var DEFAULT_STRIP_PADDING_LEFT = 22;
|
|
4576
|
+
var DEFAULT_STRIP_PADDING_RIGHT = 28;
|
|
4577
|
+
var DEFAULT_STRIP_GAP = 18;
|
|
4578
|
+
var DEFAULT_STRIP_LABEL_WIDTH = 56;
|
|
4579
|
+
var DEFAULT_STRIP_PROMPT_MAX_SAFE_CHARS = 180;
|
|
4580
|
+
var DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH = 320;
|
|
4581
|
+
var DEFAULT_STRIP_PROMPT_PREFERRED_WIDTH_RATIO = 0.58;
|
|
4582
|
+
var DEFAULT_STRIP_ZONE_GAP = 18;
|
|
4583
|
+
var DEFAULT_STRIP_PROMPT_TRAILING_PADDING = 16;
|
|
4584
|
+
var DEFAULT_STRIP_LABEL_FONT_SIZE = 14.5;
|
|
4585
|
+
var DEFAULT_STRIP_VALUE_FONT_SIZE = 15.5;
|
|
4586
|
+
var DEFAULT_STRIP_VALUE_PADDING = 10;
|
|
4587
|
+
var DEFAULT_STRIP_LABEL_PADDING = 14;
|
|
4588
|
+
var DEFAULT_STRIP_SECTION_GAP = DEFAULT_STRIP_GAP + 16;
|
|
4589
|
+
var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
|
|
4590
|
+
var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
|
|
4591
|
+
var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
|
|
4592
|
+
var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
|
|
4535
4593
|
var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
|
|
4536
4594
|
var LOCATION_NETWORK_SUFFIX_PATTERNS = [
|
|
4537
4595
|
/(?:中国)?移动$/i,
|
|
@@ -4556,6 +4614,7 @@ var LOCATION_NETWORK_SUFFIX_PATTERNS = [
|
|
|
4556
4614
|
/digitalocean$/i
|
|
4557
4615
|
];
|
|
4558
4616
|
var cachedStripLogoSrcPromise = null;
|
|
4617
|
+
var cachedEnrichmentByContext = /* @__PURE__ */ new WeakMap();
|
|
4559
4618
|
var normalizeText = (value) => String(value || "").trim();
|
|
4560
4619
|
var toInline = (value, maxLen = 200) => {
|
|
4561
4620
|
const text = normalizeText(value);
|
|
@@ -4567,12 +4626,14 @@ var shortenTail = (value, maxLen = 80) => {
|
|
|
4567
4626
|
if (!text || text.length <= maxLen) return text;
|
|
4568
4627
|
return `${text.slice(0, Math.max(0, maxLen - 1)).trimEnd()}\u2026`;
|
|
4569
4628
|
};
|
|
4570
|
-
var
|
|
4571
|
-
const text =
|
|
4572
|
-
if (!text
|
|
4573
|
-
const
|
|
4574
|
-
|
|
4575
|
-
|
|
4629
|
+
var shortenByCharacters = (value, maxChars = 80) => {
|
|
4630
|
+
const text = normalizeWhitespace(value);
|
|
4631
|
+
if (!text) return "";
|
|
4632
|
+
const chars = Array.from(text);
|
|
4633
|
+
if (chars.length <= maxChars) {
|
|
4634
|
+
return text;
|
|
4635
|
+
}
|
|
4636
|
+
return `${chars.slice(0, Math.max(0, maxChars - 1)).join("").trimEnd()}\u2026`;
|
|
4576
4637
|
};
|
|
4577
4638
|
var padDatePart = (value) => String(value).padStart(2, "0");
|
|
4578
4639
|
var formatUtcOffsetLabel = (offsetHours = DEFAULT_TIMEZONE_OFFSET) => {
|
|
@@ -4646,6 +4707,29 @@ var fillEnrichment = (target, source) => {
|
|
|
4646
4707
|
}
|
|
4647
4708
|
return target;
|
|
4648
4709
|
};
|
|
4710
|
+
var readCachedEnrichment = (page) => {
|
|
4711
|
+
const context = page && typeof page.context === "function" ? page.context() : null;
|
|
4712
|
+
if (!context) {
|
|
4713
|
+
return null;
|
|
4714
|
+
}
|
|
4715
|
+
const cached = cachedEnrichmentByContext.get(context);
|
|
4716
|
+
return cached && typeof cached === "object" ? cached : null;
|
|
4717
|
+
};
|
|
4718
|
+
var writeCachedEnrichment = (page, source) => {
|
|
4719
|
+
const context = page && typeof page.context === "function" ? page.context() : null;
|
|
4720
|
+
if (!context || !source || typeof source !== "object") {
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
const current = cachedEnrichmentByContext.get(context) || {};
|
|
4724
|
+
const next = {
|
|
4725
|
+
ip: toInline(source.ip || current.ip, 80),
|
|
4726
|
+
location: toInline(source.location || current.location, 80)
|
|
4727
|
+
};
|
|
4728
|
+
if (!next.ip && !next.location) {
|
|
4729
|
+
return;
|
|
4730
|
+
}
|
|
4731
|
+
cachedEnrichmentByContext.set(context, next);
|
|
4732
|
+
};
|
|
4649
4733
|
var getHostname = (url) => {
|
|
4650
4734
|
try {
|
|
4651
4735
|
const parsed = new URL(url);
|
|
@@ -4749,8 +4833,8 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
|
|
|
4749
4833
|
url: baseMeta.url,
|
|
4750
4834
|
hostname: baseMeta.hostname,
|
|
4751
4835
|
title: baseMeta.title,
|
|
4836
|
+
prompt: baseMeta.prompt,
|
|
4752
4837
|
query: baseMeta.query,
|
|
4753
|
-
taskId: baseMeta.taskId,
|
|
4754
4838
|
serverAddr,
|
|
4755
4839
|
signal: controller?.signal
|
|
4756
4840
|
})).catch(() => null),
|
|
@@ -4775,44 +4859,43 @@ var openProbePage = async (page) => {
|
|
|
4775
4859
|
if (!context) {
|
|
4776
4860
|
return null;
|
|
4777
4861
|
}
|
|
4862
|
+
const browser = typeof context.browser === "function" ? context.browser() : null;
|
|
4863
|
+
if (browser && typeof browser.newContext === "function") {
|
|
4864
|
+
const probeContext = await browser.newContext().catch(() => null);
|
|
4865
|
+
if (probeContext && typeof probeContext.newPage === "function") {
|
|
4866
|
+
const probePage = await probeContext.newPage().catch(async () => {
|
|
4867
|
+
await probeContext.close().catch(() => {
|
|
4868
|
+
});
|
|
4869
|
+
return null;
|
|
4870
|
+
});
|
|
4871
|
+
if (probePage) {
|
|
4872
|
+
return {
|
|
4873
|
+
page: probePage,
|
|
4874
|
+
close: async () => {
|
|
4875
|
+
await probeContext.close().catch(() => {
|
|
4876
|
+
});
|
|
4877
|
+
}
|
|
4878
|
+
};
|
|
4879
|
+
}
|
|
4880
|
+
} else {
|
|
4881
|
+
await probeContext?.close?.().catch(() => {
|
|
4882
|
+
});
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4778
4885
|
if (typeof context.newPage === "function") {
|
|
4779
4886
|
try {
|
|
4780
|
-
const
|
|
4887
|
+
const probePage = await context.newPage();
|
|
4781
4888
|
return {
|
|
4782
|
-
page:
|
|
4889
|
+
page: probePage,
|
|
4783
4890
|
close: async () => {
|
|
4784
|
-
await
|
|
4891
|
+
await probePage.close().catch(() => {
|
|
4785
4892
|
});
|
|
4786
4893
|
}
|
|
4787
4894
|
};
|
|
4788
4895
|
} catch {
|
|
4789
4896
|
}
|
|
4790
4897
|
}
|
|
4791
|
-
|
|
4792
|
-
if (!browser || typeof browser.newContext !== "function") {
|
|
4793
|
-
return null;
|
|
4794
|
-
}
|
|
4795
|
-
const probeContext = await browser.newContext().catch(() => null);
|
|
4796
|
-
if (!probeContext || typeof probeContext.newPage !== "function") {
|
|
4797
|
-
await probeContext?.close?.().catch(() => {
|
|
4798
|
-
});
|
|
4799
|
-
return null;
|
|
4800
|
-
}
|
|
4801
|
-
const probePage = await probeContext.newPage().catch(async () => {
|
|
4802
|
-
await probeContext.close().catch(() => {
|
|
4803
|
-
});
|
|
4804
|
-
return null;
|
|
4805
|
-
});
|
|
4806
|
-
if (!probePage) {
|
|
4807
|
-
return null;
|
|
4808
|
-
}
|
|
4809
|
-
return {
|
|
4810
|
-
page: probePage,
|
|
4811
|
-
close: async () => {
|
|
4812
|
-
await probeContext.close().catch(() => {
|
|
4813
|
-
});
|
|
4814
|
-
}
|
|
4815
|
-
};
|
|
4898
|
+
return null;
|
|
4816
4899
|
};
|
|
4817
4900
|
var resolveWithIpLookup = async (page, options = {}) => {
|
|
4818
4901
|
if (!page || typeof page.context !== "function" || options.ipLookup === false) {
|
|
@@ -4857,10 +4940,14 @@ var resolveWithIpLookup = async (page, options = {}) => {
|
|
|
4857
4940
|
};
|
|
4858
4941
|
var resolveEnrichment = async (page, baseMeta, options) => {
|
|
4859
4942
|
const response = options.response && typeof options.response === "object" ? options.response : null;
|
|
4943
|
+
const cached = readCachedEnrichment(page);
|
|
4860
4944
|
const merged = {
|
|
4861
4945
|
ip: toInline(options.ip, 80),
|
|
4862
4946
|
location: toInline(options.location, 80)
|
|
4863
4947
|
};
|
|
4948
|
+
if (!merged.ip || !merged.location) {
|
|
4949
|
+
fillEnrichment(merged, cached);
|
|
4950
|
+
}
|
|
4864
4951
|
if (!merged.ip || !merged.location) {
|
|
4865
4952
|
fillEnrichment(
|
|
4866
4953
|
merged,
|
|
@@ -4884,24 +4971,31 @@ var resolveEnrichment = async (page, baseMeta, options) => {
|
|
|
4884
4971
|
merged.location = headerLocation || merged.location;
|
|
4885
4972
|
}
|
|
4886
4973
|
}
|
|
4974
|
+
writeCachedEnrichment(page, merged);
|
|
4887
4975
|
return merged;
|
|
4888
4976
|
};
|
|
4889
|
-
var buildWatermarkStamp = ({
|
|
4977
|
+
var buildWatermarkStamp = ({ prompt, captureTime, ip, location }) => {
|
|
4890
4978
|
const parts = [
|
|
4891
|
-
`
|
|
4979
|
+
`Prompt ${shortenTail(prompt, 40) || "-"}`,
|
|
4892
4980
|
`Time ${captureTime}`,
|
|
4893
4981
|
`Loc ${shortenTail(location, 20) || "-"}`,
|
|
4894
4982
|
`IP ${toInline(ip, 24) || "-"}`
|
|
4895
4983
|
];
|
|
4896
4984
|
return parts.join(" | ");
|
|
4897
4985
|
};
|
|
4898
|
-
var buildStripSegments = ({
|
|
4986
|
+
var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
|
|
4987
|
+
const promptValue = shortenByCharacters(
|
|
4988
|
+
normalizeWhitespace(prompt) || "-",
|
|
4989
|
+
DEFAULT_STRIP_PROMPT_MAX_SAFE_CHARS
|
|
4990
|
+
) || "-";
|
|
4991
|
+
const ipValue = normalizeWhitespace(ip) || "-";
|
|
4992
|
+
const locationValue = normalizeWhitespace(location) || "-";
|
|
4899
4993
|
return [
|
|
4900
4994
|
{
|
|
4901
|
-
kind: "
|
|
4902
|
-
label: "
|
|
4903
|
-
value:
|
|
4904
|
-
rawValue:
|
|
4995
|
+
kind: "prompt",
|
|
4996
|
+
label: "Prompt",
|
|
4997
|
+
value: promptValue,
|
|
4998
|
+
rawValue: promptValue
|
|
4905
4999
|
},
|
|
4906
5000
|
{
|
|
4907
5001
|
kind: "time",
|
|
@@ -4912,25 +5006,50 @@ var buildStripSegments = ({ taskId, captureTime, ip, location }) => {
|
|
|
4912
5006
|
{
|
|
4913
5007
|
kind: "location",
|
|
4914
5008
|
label: "Loc",
|
|
4915
|
-
value:
|
|
4916
|
-
rawValue:
|
|
5009
|
+
value: locationValue,
|
|
5010
|
+
rawValue: locationValue
|
|
4917
5011
|
},
|
|
4918
5012
|
{
|
|
4919
5013
|
kind: "ip",
|
|
4920
5014
|
label: "IP",
|
|
4921
|
-
value:
|
|
4922
|
-
rawValue:
|
|
5015
|
+
value: ipValue,
|
|
5016
|
+
rawValue: ipValue
|
|
4923
5017
|
}
|
|
4924
5018
|
];
|
|
4925
5019
|
};
|
|
5020
|
+
var escapeXml = (value) => String(value || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5021
|
+
var estimateTextWidth = (value, fontSize = 16) => {
|
|
5022
|
+
const text = String(value || "");
|
|
5023
|
+
let width = 0;
|
|
5024
|
+
for (const char of text) {
|
|
5025
|
+
if (/\s/.test(char)) {
|
|
5026
|
+
width += fontSize * 0.34;
|
|
5027
|
+
} else if (/[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u30ff\uac00-\ud7af]/.test(char)) {
|
|
5028
|
+
width += fontSize * 0.92;
|
|
5029
|
+
} else if (/[A-Z0-9]/.test(char)) {
|
|
5030
|
+
width += fontSize * 0.62;
|
|
5031
|
+
} else {
|
|
5032
|
+
width += fontSize * 0.56;
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return Math.ceil(width);
|
|
5036
|
+
};
|
|
5037
|
+
var resolvePromptFields = (options = {}, fallbackTitle = "") => {
|
|
5038
|
+
const query = normalizeText(options.query);
|
|
5039
|
+
const prompt = query || normalizeText(options.prompt) || normalizeText(fallbackTitle) || "\u672A\u63D0\u4F9B Prompt";
|
|
5040
|
+
return {
|
|
5041
|
+
prompt,
|
|
5042
|
+
query: query || prompt
|
|
5043
|
+
};
|
|
5044
|
+
};
|
|
4926
5045
|
var createBaseWatermarkifyOptions = () => ({
|
|
4927
5046
|
enabled: true,
|
|
4928
5047
|
timezoneOffsetHours: DEFAULT_TIMEZONE_OFFSET,
|
|
4929
5048
|
response: null,
|
|
4930
5049
|
ip: "",
|
|
4931
5050
|
location: "",
|
|
5051
|
+
prompt: "",
|
|
4932
5052
|
query: "",
|
|
4933
|
-
taskId: "",
|
|
4934
5053
|
ipLookup: true,
|
|
4935
5054
|
ipLookupTimeoutMs: DEFAULT_IP_LOOKUP_TIMEOUT_MS,
|
|
4936
5055
|
resolver: null,
|
|
@@ -4973,8 +5092,8 @@ var normalizeScreenshotWatermarkify = (value) => {
|
|
|
4973
5092
|
response: source.response ?? null,
|
|
4974
5093
|
ip: normalizeText(source.ip),
|
|
4975
5094
|
location: normalizeText(source.location),
|
|
4976
|
-
|
|
4977
|
-
|
|
5095
|
+
prompt: normalizeWhitespace(source.prompt),
|
|
5096
|
+
query: normalizeWhitespace(source.query),
|
|
4978
5097
|
ipLookup: source.ipLookup !== false,
|
|
4979
5098
|
ipLookupTimeoutMs: Number.isFinite(ipLookupTimeoutMsRaw) ? ipLookupTimeoutMsRaw : DEFAULT_IP_LOOKUP_TIMEOUT_MS,
|
|
4980
5099
|
resolver: typeof source.resolver === "function" ? source.resolver : null,
|
|
@@ -4993,16 +5112,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
4993
5112
|
const url = normalizeText(page?.url?.()) || "about:blank";
|
|
4994
5113
|
const title = normalizeText(await page.title().catch(() => "")) || "\u672A\u547D\u540D\u9875\u9762";
|
|
4995
5114
|
const hostname = getHostname(url);
|
|
4996
|
-
const query =
|
|
4997
|
-
const
|
|
4998
|
-
const captureTime = formatTimestampForUtcOffset(
|
|
5115
|
+
const { prompt, query } = resolvePromptFields(options, title);
|
|
5116
|
+
const capturedAt = options.capturedAt instanceof Date ? options.capturedAt : new Date(options.capturedAt || Date.now());
|
|
5117
|
+
const captureTime = formatTimestampForUtcOffset(capturedAt, timezoneOffsetHours);
|
|
4999
5118
|
const [enrichment, stripLogoSrc] = await Promise.all([
|
|
5000
5119
|
resolveEnrichment(page, {
|
|
5001
5120
|
url,
|
|
5002
5121
|
hostname,
|
|
5003
5122
|
title,
|
|
5004
|
-
|
|
5005
|
-
|
|
5123
|
+
prompt,
|
|
5124
|
+
query
|
|
5006
5125
|
}, options),
|
|
5007
5126
|
resolveStripLogoSrc()
|
|
5008
5127
|
]);
|
|
@@ -5010,13 +5129,13 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
5010
5129
|
const location = enrichment.location || "-";
|
|
5011
5130
|
return {
|
|
5012
5131
|
watermarkText: buildWatermarkStamp({
|
|
5013
|
-
|
|
5132
|
+
prompt,
|
|
5014
5133
|
captureTime,
|
|
5015
5134
|
ip,
|
|
5016
5135
|
location
|
|
5017
5136
|
}),
|
|
5018
5137
|
stripSegments: buildStripSegments({
|
|
5019
|
-
|
|
5138
|
+
prompt,
|
|
5020
5139
|
captureTime,
|
|
5021
5140
|
ip,
|
|
5022
5141
|
location
|
|
@@ -5026,396 +5145,509 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
5026
5145
|
stripLogoSrc
|
|
5027
5146
|
};
|
|
5028
5147
|
};
|
|
5029
|
-
var
|
|
5030
|
-
|
|
5031
|
-
const
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5148
|
+
var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
|
|
5149
|
+
var buildStripSegmentLayout = (segment, options = {}) => {
|
|
5150
|
+
const label = normalizeWhitespace(segment?.label || "");
|
|
5151
|
+
const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
|
|
5152
|
+
const labelFontSize = DEFAULT_STRIP_LABEL_FONT_SIZE;
|
|
5153
|
+
const valueFontSize = DEFAULT_STRIP_VALUE_FONT_SIZE;
|
|
5154
|
+
const labelWidth = Math.max(
|
|
5155
|
+
DEFAULT_STRIP_LABEL_WIDTH,
|
|
5156
|
+
estimateTextWidth(label, labelFontSize) + DEFAULT_STRIP_LABEL_PADDING
|
|
5157
|
+
);
|
|
5158
|
+
const rawValueWidth = Math.max(
|
|
5159
|
+
24,
|
|
5160
|
+
estimateTextWidth(rawValue, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING
|
|
5161
|
+
);
|
|
5162
|
+
const maxValueWidth = Math.max(0, Number(options.valueMaxWidth) || 0);
|
|
5163
|
+
const renderValue = maxValueWidth > 0 ? fitTextWithEllipsis(rawValue, Math.max(18, maxValueWidth - DEFAULT_STRIP_VALUE_PADDING), valueFontSize) : rawValue;
|
|
5164
|
+
const valueWidth = maxValueWidth > 0 ? Math.max(24, Math.min(maxValueWidth, estimateTextWidth(renderValue, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING)) : rawValueWidth;
|
|
5165
|
+
return {
|
|
5166
|
+
...segment,
|
|
5167
|
+
label,
|
|
5168
|
+
rawValue,
|
|
5169
|
+
renderValue,
|
|
5170
|
+
labelFontSize,
|
|
5171
|
+
valueFontSize,
|
|
5172
|
+
labelWidth,
|
|
5173
|
+
valueWidth,
|
|
5174
|
+
segmentWidth: labelWidth + valueWidth,
|
|
5175
|
+
rowHeight: Math.round(Math.max(labelFontSize, valueFontSize) * 1.42)
|
|
5176
|
+
};
|
|
5177
|
+
};
|
|
5178
|
+
var buildStripRowLayout = (segments, overrides = {}) => {
|
|
5179
|
+
const safeSegments = Array.isArray(segments) ? segments : [];
|
|
5180
|
+
const sectionGap = DEFAULT_STRIP_SECTION_GAP;
|
|
5181
|
+
const layouts = safeSegments.map((segment, index) => buildStripSegmentLayout(segment, {
|
|
5182
|
+
valueMaxWidth: overrides?.valueMaxWidths?.[index]
|
|
5183
|
+
}));
|
|
5184
|
+
const totalWidth = layouts.reduce((sum, segment) => sum + segment.segmentWidth, 0) + Math.max(0, layouts.length - 1) * sectionGap;
|
|
5185
|
+
const rowHeight = layouts.reduce((max, segment) => Math.max(max, segment.rowHeight || 0), 0);
|
|
5186
|
+
return {
|
|
5187
|
+
sectionGap,
|
|
5188
|
+
layouts,
|
|
5189
|
+
totalWidth,
|
|
5190
|
+
rowHeight
|
|
5191
|
+
};
|
|
5192
|
+
};
|
|
5193
|
+
var fitTextWithEllipsis = (chars, maxWidth, fontSize) => {
|
|
5194
|
+
const safeChars = Array.isArray(chars) ? chars.slice() : Array.from(String(chars || ""));
|
|
5195
|
+
if (!safeChars.length) {
|
|
5196
|
+
return "-";
|
|
5197
|
+
}
|
|
5198
|
+
if (estimateTextWidth(safeChars.join(""), fontSize) <= maxWidth) {
|
|
5199
|
+
return safeChars.join("").trim() || "-";
|
|
5035
5200
|
}
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5201
|
+
while (safeChars.length > 1 && estimateTextWidth(`${safeChars.join("").trimEnd()}\u2026`, fontSize) > maxWidth) {
|
|
5202
|
+
safeChars.pop();
|
|
5203
|
+
}
|
|
5204
|
+
return `${safeChars.join("").trimEnd()}\u2026` || "\u2026";
|
|
5205
|
+
};
|
|
5206
|
+
var splitTextToLines = (value, maxWidth, fontSize, maxLines = 2) => {
|
|
5207
|
+
const chars = Array.from(normalizeWhitespace(value) || "-");
|
|
5208
|
+
const safeMaxWidth = Math.max(18, maxWidth - DEFAULT_STRIP_TEXT_WIDTH_SAFETY);
|
|
5209
|
+
if (!chars.length) {
|
|
5210
|
+
return { lines: ["-"], truncated: false };
|
|
5211
|
+
}
|
|
5212
|
+
const lines = [];
|
|
5213
|
+
let cursor = 0;
|
|
5214
|
+
let truncated = false;
|
|
5215
|
+
while (cursor < chars.length && lines.length < maxLines) {
|
|
5216
|
+
while (cursor < chars.length && chars[cursor] === " ") {
|
|
5217
|
+
cursor += 1;
|
|
5040
5218
|
}
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
const
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
host.style.width = "100vw";
|
|
5055
|
-
host.style.height = "100vh";
|
|
5056
|
-
host.style.pointerEvents = "none";
|
|
5057
|
-
host.style.zIndex = "2147483646";
|
|
5058
|
-
const shadow = host.attachShadow({ mode: "open" });
|
|
5059
|
-
const style = document.createElement("style");
|
|
5060
|
-
style.textContent = `
|
|
5061
|
-
:host {
|
|
5062
|
-
all: initial;
|
|
5063
|
-
position: fixed;
|
|
5064
|
-
inset: 0;
|
|
5065
|
-
width: 100vw;
|
|
5066
|
-
height: 100vh;
|
|
5067
|
-
pointer-events: none;
|
|
5068
|
-
z-index: 2147483646;
|
|
5069
|
-
}
|
|
5070
|
-
|
|
5071
|
-
.root {
|
|
5072
|
-
position: absolute;
|
|
5073
|
-
inset: 0;
|
|
5074
|
-
width: 100%;
|
|
5075
|
-
height: 100%;
|
|
5076
|
-
overflow: hidden;
|
|
5077
|
-
pointer-events: none;
|
|
5078
|
-
font-family: MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
|
|
5079
|
-
}
|
|
5080
|
-
|
|
5081
|
-
.watermark {
|
|
5082
|
-
position: absolute;
|
|
5083
|
-
inset: 0;
|
|
5084
|
-
overflow: hidden;
|
|
5085
|
-
pointer-events: none;
|
|
5086
|
-
}
|
|
5087
|
-
|
|
5088
|
-
.wmStamp {
|
|
5089
|
-
position: absolute;
|
|
5090
|
-
left: 0;
|
|
5091
|
-
top: 0;
|
|
5092
|
-
transform-origin: left center;
|
|
5093
|
-
pointer-events: none;
|
|
5094
|
-
white-space: nowrap;
|
|
5095
|
-
}
|
|
5096
|
-
|
|
5097
|
-
.wmStampText {
|
|
5098
|
-
color: rgba(17, 17, 17, var(--wm-opacity, 0.15));
|
|
5099
|
-
font-size: 19px;
|
|
5100
|
-
font-weight: 720;
|
|
5101
|
-
line-height: 1;
|
|
5102
|
-
letter-spacing: 0.032em;
|
|
5103
|
-
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.44);
|
|
5104
|
-
-webkit-text-stroke: 0.22px rgba(255, 255, 255, 0.12);
|
|
5105
|
-
font-variant-numeric: tabular-nums;
|
|
5106
|
-
filter: saturate(0.92);
|
|
5107
|
-
}
|
|
5108
|
-
|
|
5109
|
-
.strip {
|
|
5110
|
-
position: absolute;
|
|
5111
|
-
left: 0;
|
|
5112
|
-
right: 0;
|
|
5113
|
-
bottom: 0;
|
|
5114
|
-
min-height: 78px;
|
|
5115
|
-
padding: 0 22px 0 20px;
|
|
5116
|
-
display: flex;
|
|
5117
|
-
align-items: center;
|
|
5118
|
-
overflow: hidden;
|
|
5119
|
-
border-top: 1px solid rgba(17, 17, 17, 0.1);
|
|
5120
|
-
background:
|
|
5121
|
-
linear-gradient(180deg, rgba(255, 255, 255, 0.995) 0%, rgba(248, 248, 247, 0.985) 100%);
|
|
5122
|
-
box-shadow:
|
|
5123
|
-
0 -22px 48px rgba(15, 23, 42, 0.1),
|
|
5124
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.92);
|
|
5125
|
-
backdrop-filter: blur(16px);
|
|
5126
|
-
-webkit-backdrop-filter: blur(16px);
|
|
5127
|
-
}
|
|
5128
|
-
|
|
5129
|
-
.strip::before {
|
|
5130
|
-
content: "";
|
|
5131
|
-
position: absolute;
|
|
5132
|
-
left: 20px;
|
|
5133
|
-
right: 52%;
|
|
5134
|
-
top: 0;
|
|
5135
|
-
height: 2px;
|
|
5136
|
-
border-radius: 999px;
|
|
5137
|
-
background: linear-gradient(
|
|
5138
|
-
90deg,
|
|
5139
|
-
rgba(17, 17, 17, 0.98) 0%,
|
|
5140
|
-
rgba(17, 17, 17, 0.68) 24%,
|
|
5141
|
-
rgba(17, 17, 17, 0.08) 58%,
|
|
5142
|
-
rgba(17, 17, 17, 0) 100%
|
|
5143
|
-
);
|
|
5144
|
-
}
|
|
5145
|
-
|
|
5146
|
-
.stripInner {
|
|
5147
|
-
position: relative;
|
|
5148
|
-
z-index: 1;
|
|
5149
|
-
display: flex;
|
|
5150
|
-
align-items: center;
|
|
5151
|
-
gap: 16px;
|
|
5152
|
-
width: 100%;
|
|
5153
|
-
min-width: 0;
|
|
5154
|
-
}
|
|
5155
|
-
|
|
5156
|
-
.stripLogo {
|
|
5157
|
-
position: relative;
|
|
5158
|
-
width: 28px;
|
|
5159
|
-
height: 28px;
|
|
5160
|
-
flex: none;
|
|
5161
|
-
display: flex;
|
|
5162
|
-
align-items: center;
|
|
5163
|
-
justify-content: center;
|
|
5164
|
-
}
|
|
5165
|
-
|
|
5166
|
-
.stripLogoImg {
|
|
5167
|
-
width: 28px;
|
|
5168
|
-
height: 28px;
|
|
5169
|
-
object-fit: contain;
|
|
5170
|
-
display: block;
|
|
5171
|
-
}
|
|
5172
|
-
|
|
5173
|
-
.segments {
|
|
5174
|
-
display: flex;
|
|
5175
|
-
align-items: center;
|
|
5176
|
-
gap: 0;
|
|
5177
|
-
flex: 1 1 auto;
|
|
5178
|
-
min-width: 0;
|
|
5179
|
-
white-space: nowrap;
|
|
5180
|
-
}
|
|
5181
|
-
|
|
5182
|
-
.segment {
|
|
5183
|
-
position: relative;
|
|
5184
|
-
display: inline-flex;
|
|
5185
|
-
align-items: center;
|
|
5186
|
-
gap: 10px;
|
|
5187
|
-
min-width: 0;
|
|
5188
|
-
flex: none;
|
|
5189
|
-
padding-right: 16px;
|
|
5190
|
-
margin-right: 16px;
|
|
5191
|
-
}
|
|
5192
|
-
|
|
5193
|
-
.segment:not(:last-child)::after {
|
|
5194
|
-
content: "";
|
|
5195
|
-
position: absolute;
|
|
5196
|
-
top: 50%;
|
|
5197
|
-
right: 0;
|
|
5198
|
-
width: 1px;
|
|
5199
|
-
height: 25px;
|
|
5200
|
-
transform: translateY(-50%);
|
|
5201
|
-
background: linear-gradient(
|
|
5202
|
-
180deg,
|
|
5203
|
-
rgba(148, 163, 184, 0) 0%,
|
|
5204
|
-
rgba(148, 163, 184, 0.34) 24%,
|
|
5205
|
-
rgba(148, 163, 184, 0.34) 76%,
|
|
5206
|
-
rgba(148, 163, 184, 0) 100%
|
|
5207
|
-
);
|
|
5208
|
-
}
|
|
5209
|
-
|
|
5210
|
-
.segmentTaskId {
|
|
5211
|
-
flex: 1 1 auto;
|
|
5212
|
-
max-width: none;
|
|
5213
|
-
min-width: 0;
|
|
5214
|
-
}
|
|
5215
|
-
|
|
5216
|
-
.label {
|
|
5217
|
-
width: 52px;
|
|
5218
|
-
color: rgba(17, 17, 17, 0.42);
|
|
5219
|
-
font-size: 12px;
|
|
5220
|
-
font-weight: 600;
|
|
5221
|
-
line-height: 1;
|
|
5222
|
-
letter-spacing: 0.01em;
|
|
5223
|
-
flex: none;
|
|
5224
|
-
display: inline-flex;
|
|
5225
|
-
align-items: center;
|
|
5226
|
-
justify-content: flex-start;
|
|
5227
|
-
}
|
|
5228
|
-
|
|
5229
|
-
.value {
|
|
5230
|
-
color: #111111;
|
|
5231
|
-
font-size: 18px;
|
|
5232
|
-
font-weight: 710;
|
|
5233
|
-
line-height: 1;
|
|
5234
|
-
min-width: 0;
|
|
5235
|
-
overflow: hidden;
|
|
5236
|
-
text-overflow: ellipsis;
|
|
5237
|
-
font-variant-numeric: tabular-nums;
|
|
5238
|
-
display: inline-flex;
|
|
5239
|
-
align-items: center;
|
|
5240
|
-
}
|
|
5241
|
-
|
|
5242
|
-
.segmentTaskId .value {
|
|
5243
|
-
color: #101010;
|
|
5244
|
-
font-size: 15px;
|
|
5245
|
-
font-weight: 760;
|
|
5246
|
-
letter-spacing: -0.01em;
|
|
5247
|
-
}
|
|
5248
|
-
|
|
5249
|
-
.segmentTime .value {
|
|
5250
|
-
color: #202020;
|
|
5251
|
-
font-size: 17px;
|
|
5252
|
-
font-weight: 700;
|
|
5253
|
-
}
|
|
5254
|
-
|
|
5255
|
-
.segmentLocation .value,
|
|
5256
|
-
.segmentIp .value {
|
|
5257
|
-
color: #2a2a2a;
|
|
5258
|
-
font-size: 17px;
|
|
5259
|
-
font-weight: 700;
|
|
5260
|
-
}
|
|
5261
|
-
|
|
5262
|
-
`;
|
|
5263
|
-
const root = createNode("div", "root");
|
|
5264
|
-
const watermarkNode = createNode("div", "watermark");
|
|
5265
|
-
const stripNode = createNode("div", "strip");
|
|
5266
|
-
const stripInner = createNode("div", "stripInner");
|
|
5267
|
-
const stripLogo = createNode("div", "stripLogo");
|
|
5268
|
-
const stripLogoImg = createNode("img", "stripLogoImg");
|
|
5269
|
-
const stripSegmentsNode = createNode("div", "segments");
|
|
5270
|
-
stripLogoImg.alt = "";
|
|
5271
|
-
stripLogoImg.decoding = "async";
|
|
5272
|
-
stripLogoImg.referrerPolicy = "no-referrer";
|
|
5273
|
-
stripLogoImg.src = safeText(watermarkifyMeta?.stripLogoSrc) || defaults.logoUrl;
|
|
5274
|
-
stripLogo.appendChild(stripLogoImg);
|
|
5275
|
-
stripInner.appendChild(stripLogo);
|
|
5276
|
-
stripInner.appendChild(stripSegmentsNode);
|
|
5277
|
-
stripNode.appendChild(stripInner);
|
|
5278
|
-
root.appendChild(watermarkNode);
|
|
5279
|
-
root.appendChild(stripNode);
|
|
5280
|
-
shadow.appendChild(style);
|
|
5281
|
-
shadow.appendChild(root);
|
|
5282
|
-
mountPoint.appendChild(host);
|
|
5283
|
-
const buildSegmentNode = (segment) => {
|
|
5284
|
-
const kind = String(segment?.kind || "").trim();
|
|
5285
|
-
const label = String(segment?.label || "").trim();
|
|
5286
|
-
const value = String(segment?.value || "").trim();
|
|
5287
|
-
const rawValue = String(segment?.rawValue || value).trim();
|
|
5288
|
-
const classSuffix = kind ? ` segment${kind.slice(0, 1).toUpperCase()}${kind.slice(1)}` : "";
|
|
5289
|
-
const segmentNode = createNode("span", `segment${classSuffix}`);
|
|
5290
|
-
const labelNode = createNode("span", "label");
|
|
5291
|
-
const valueNode = createNode("span", "value");
|
|
5292
|
-
labelNode.textContent = label;
|
|
5293
|
-
valueNode.textContent = value;
|
|
5294
|
-
segmentNode.title = rawValue ? `${label} ${rawValue}` : label;
|
|
5295
|
-
segmentNode.appendChild(labelNode);
|
|
5296
|
-
segmentNode.appendChild(valueNode);
|
|
5297
|
-
return segmentNode;
|
|
5298
|
-
};
|
|
5299
|
-
const renderStrip = () => {
|
|
5300
|
-
const stripSegments = Array.isArray(watermarkifyMeta?.stripSegments) ? watermarkifyMeta.stripSegments : [];
|
|
5301
|
-
if (!watermarkifyMeta?.strip?.enabled || stripSegments.length === 0) {
|
|
5302
|
-
stripNode.remove();
|
|
5303
|
-
return;
|
|
5304
|
-
}
|
|
5305
|
-
const fragment = document.createDocumentFragment();
|
|
5306
|
-
for (const segment of stripSegments) {
|
|
5307
|
-
fragment.appendChild(buildSegmentNode(segment));
|
|
5308
|
-
}
|
|
5309
|
-
stripSegmentsNode.replaceChildren(fragment);
|
|
5310
|
-
};
|
|
5311
|
-
const waitForLogo = async () => {
|
|
5312
|
-
if (!stripLogoImg.getAttribute("src")) {
|
|
5313
|
-
return;
|
|
5314
|
-
}
|
|
5315
|
-
await new Promise((resolve) => {
|
|
5316
|
-
let settled = false;
|
|
5317
|
-
const done = () => {
|
|
5318
|
-
if (settled) return;
|
|
5319
|
-
settled = true;
|
|
5320
|
-
resolve();
|
|
5321
|
-
};
|
|
5322
|
-
const fail = () => {
|
|
5323
|
-
if (settled) return;
|
|
5324
|
-
stripLogo.remove();
|
|
5325
|
-
done();
|
|
5326
|
-
};
|
|
5327
|
-
const timeoutDone = () => {
|
|
5328
|
-
if (settled) return;
|
|
5329
|
-
done();
|
|
5330
|
-
};
|
|
5331
|
-
if (stripLogoImg.complete && stripLogoImg.naturalWidth > 0) {
|
|
5332
|
-
done();
|
|
5333
|
-
return;
|
|
5334
|
-
}
|
|
5335
|
-
if (stripLogoImg.complete && stripLogoImg.naturalWidth === 0) {
|
|
5336
|
-
fail();
|
|
5337
|
-
return;
|
|
5338
|
-
}
|
|
5339
|
-
stripLogoImg.addEventListener("load", done, { once: true });
|
|
5340
|
-
stripLogoImg.addEventListener("error", fail, { once: true });
|
|
5341
|
-
setTimeout(timeoutDone, 2500);
|
|
5342
|
-
});
|
|
5343
|
-
};
|
|
5344
|
-
const renderWatermark = () => {
|
|
5345
|
-
const stampText = safeText(watermarkifyMeta?.watermarkText);
|
|
5346
|
-
if (!watermarkifyMeta?.watermark?.enabled || !stampText) {
|
|
5347
|
-
watermarkNode.remove();
|
|
5348
|
-
return;
|
|
5349
|
-
}
|
|
5350
|
-
const cellWidth = Math.max(680, Number(watermarkifyMeta.watermark.cellWidth) || defaults.cellWidth);
|
|
5351
|
-
const cellHeight = Math.max(260, Number(watermarkifyMeta.watermark.cellHeight) || defaults.cellHeight);
|
|
5352
|
-
const rotateDeg = Number(watermarkifyMeta.watermark.rotateDeg) || defaults.rotateDeg;
|
|
5353
|
-
const opacity = Math.min(0.22, Math.max(0.05, Number(watermarkifyMeta.watermark.opacity) || defaults.opacity));
|
|
5354
|
-
const width = watermarkNode.clientWidth || window.innerWidth || document.documentElement.clientWidth || cellWidth;
|
|
5355
|
-
const height = watermarkNode.clientHeight || window.innerHeight || document.documentElement.clientHeight || cellHeight;
|
|
5356
|
-
const rowOffset = Math.round(cellWidth * 0.24);
|
|
5357
|
-
const startX = -Math.round(cellWidth * 0.16);
|
|
5358
|
-
const startY = -Math.round(cellHeight * 0.12);
|
|
5359
|
-
const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
|
|
5360
|
-
const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
|
|
5361
|
-
const fragment = document.createDocumentFragment();
|
|
5362
|
-
for (let row = 0; row < rows; row += 1) {
|
|
5363
|
-
for (let col = 0; col < cols; col += 1) {
|
|
5364
|
-
const stamp = createNode("div", "wmStamp");
|
|
5365
|
-
const stampTextNode = createNode("div", "wmStampText");
|
|
5366
|
-
const x = startX + col * cellWidth + (row % 2 ? rowOffset : 0);
|
|
5367
|
-
const y = startY + row * cellHeight + (row % 2 ? 14 : -8);
|
|
5368
|
-
stamp.style.transform = `translate(${x}px, ${y}px) rotate(${rotateDeg}deg)`;
|
|
5369
|
-
stampTextNode.style.setProperty("--wm-opacity", String(opacity));
|
|
5370
|
-
stampTextNode.textContent = stampText;
|
|
5371
|
-
stamp.appendChild(stampTextNode);
|
|
5372
|
-
fragment.appendChild(stamp);
|
|
5373
|
-
}
|
|
5219
|
+
if (cursor >= chars.length) {
|
|
5220
|
+
break;
|
|
5221
|
+
}
|
|
5222
|
+
const isLastLine = lines.length === maxLines - 1;
|
|
5223
|
+
const lineChars = [];
|
|
5224
|
+
while (cursor < chars.length) {
|
|
5225
|
+
const nextChars = [...lineChars, chars[cursor]];
|
|
5226
|
+
const remaining = cursor < chars.length - 1;
|
|
5227
|
+
const previewText = nextChars.join("") + (isLastLine && remaining ? "\u2026" : "");
|
|
5228
|
+
if (estimateTextWidth(previewText, fontSize) <= safeMaxWidth || lineChars.length === 0) {
|
|
5229
|
+
lineChars.push(chars[cursor]);
|
|
5230
|
+
cursor += 1;
|
|
5231
|
+
continue;
|
|
5374
5232
|
}
|
|
5375
|
-
|
|
5376
|
-
}
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5233
|
+
break;
|
|
5234
|
+
}
|
|
5235
|
+
while (cursor < chars.length && chars[cursor] === " ") {
|
|
5236
|
+
cursor += 1;
|
|
5237
|
+
}
|
|
5238
|
+
if (isLastLine && cursor < chars.length) {
|
|
5239
|
+
lines.push(fitTextWithEllipsis([...lineChars, ...chars.slice(cursor)], safeMaxWidth, fontSize));
|
|
5240
|
+
truncated = true;
|
|
5241
|
+
cursor = chars.length;
|
|
5242
|
+
continue;
|
|
5243
|
+
}
|
|
5244
|
+
lines.push(lineChars.join("").trim() || "-");
|
|
5245
|
+
}
|
|
5246
|
+
return {
|
|
5247
|
+
lines: lines.length > 0 ? lines : ["-"],
|
|
5248
|
+
truncated
|
|
5249
|
+
};
|
|
5250
|
+
};
|
|
5251
|
+
var resolveMetadataMinValueWidth = (segment) => {
|
|
5252
|
+
switch (segment?.kind) {
|
|
5253
|
+
case "time":
|
|
5254
|
+
return Math.max(148, estimateTextWidth("2026-04-23 21:27:16 UTC+8", DEFAULT_STRIP_VALUE_FONT_SIZE) + 8);
|
|
5255
|
+
case "ip":
|
|
5256
|
+
return Math.max(108, estimateTextWidth("255.255.255.255", DEFAULT_STRIP_VALUE_FONT_SIZE) + 8);
|
|
5257
|
+
case "location":
|
|
5258
|
+
return 76;
|
|
5259
|
+
default:
|
|
5260
|
+
return 56;
|
|
5261
|
+
}
|
|
5262
|
+
};
|
|
5263
|
+
var buildMetadataRowLayout = (segments, contentWidth) => {
|
|
5264
|
+
const safeSegments = Array.isArray(segments) ? segments.filter(Boolean) : [];
|
|
5265
|
+
const naturalRow = buildStripRowLayout(safeSegments);
|
|
5266
|
+
if (!safeSegments.length || naturalRow.totalWidth <= contentWidth) {
|
|
5267
|
+
return naturalRow;
|
|
5268
|
+
}
|
|
5269
|
+
const sectionGap = naturalRow.sectionGap;
|
|
5270
|
+
const totalLabelWidth = naturalRow.layouts.reduce((sum, segment) => sum + segment.labelWidth, 0);
|
|
5271
|
+
const availableValueWidth = Math.max(
|
|
5272
|
+
72,
|
|
5273
|
+
Math.floor(contentWidth - totalLabelWidth - Math.max(0, safeSegments.length - 1) * sectionGap)
|
|
5274
|
+
);
|
|
5275
|
+
const minValueWidths = naturalRow.layouts.map((segment) => resolveMetadataMinValueWidth(segment));
|
|
5276
|
+
const naturalValueWidths = naturalRow.layouts.map((segment) => segment.valueWidth);
|
|
5277
|
+
const valueWidths = naturalValueWidths.slice();
|
|
5278
|
+
let overflow = naturalRow.totalWidth - contentWidth;
|
|
5279
|
+
const shrinkOrder = ["location", "ip", "time"];
|
|
5280
|
+
shrinkOrder.forEach((kind) => {
|
|
5281
|
+
if (overflow <= 0) return;
|
|
5282
|
+
naturalRow.layouts.forEach((segment, index) => {
|
|
5283
|
+
if (overflow <= 0 || segment.kind !== kind) return;
|
|
5284
|
+
const minWidth = minValueWidths[index];
|
|
5285
|
+
const reducible = Math.max(0, valueWidths[index] - minWidth);
|
|
5286
|
+
if (!reducible) return;
|
|
5287
|
+
const reduction = Math.min(reducible, overflow);
|
|
5288
|
+
valueWidths[index] -= reduction;
|
|
5289
|
+
overflow -= reduction;
|
|
5290
|
+
});
|
|
5291
|
+
});
|
|
5292
|
+
if (overflow > 0) {
|
|
5293
|
+
const minTotalWidth = minValueWidths.reduce((sum, width) => sum + width, 0);
|
|
5294
|
+
if (minTotalWidth > availableValueWidth) {
|
|
5295
|
+
const flexibleIndexes = naturalRow.layouts.map((segment, index) => ({ segment, index })).filter(({ segment }) => segment.kind !== "time");
|
|
5296
|
+
let extraOverflow = minTotalWidth - availableValueWidth;
|
|
5297
|
+
flexibleIndexes.forEach(({ index }) => {
|
|
5298
|
+
if (extraOverflow <= 0) return;
|
|
5299
|
+
const minFloor = 40;
|
|
5300
|
+
const reducible = Math.max(0, minValueWidths[index] - minFloor);
|
|
5301
|
+
if (!reducible) return;
|
|
5302
|
+
const reduction = Math.min(reducible, extraOverflow);
|
|
5303
|
+
valueWidths[index] -= reduction;
|
|
5304
|
+
extraOverflow -= reduction;
|
|
5383
5305
|
});
|
|
5384
|
-
};
|
|
5385
|
-
const handleResize = () => {
|
|
5386
|
-
queueWatermarkRender();
|
|
5387
|
-
};
|
|
5388
|
-
host.__pkCleanup = () => {
|
|
5389
|
-
cancelAnimationFrame(resizeFrame);
|
|
5390
|
-
window.removeEventListener("resize", handleResize);
|
|
5391
|
-
};
|
|
5392
|
-
renderStrip();
|
|
5393
|
-
renderWatermark();
|
|
5394
|
-
queueWatermarkRender();
|
|
5395
|
-
window.addEventListener("resize", handleResize, { passive: true });
|
|
5396
|
-
return waitForLogo();
|
|
5397
|
-
}, {
|
|
5398
|
-
hostId: SCREENSHOT_WATERMARKIFY_HOST_ID,
|
|
5399
|
-
watermarkifyMeta: meta,
|
|
5400
|
-
defaults: {
|
|
5401
|
-
opacity: DEFAULT_WATERMARK_OPACITY,
|
|
5402
|
-
rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
|
|
5403
|
-
cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
|
|
5404
|
-
cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT,
|
|
5405
|
-
logoUrl: DEFAULT_STRIP_LOGO_URL
|
|
5406
5306
|
}
|
|
5307
|
+
}
|
|
5308
|
+
return buildStripRowLayout(safeSegments, {
|
|
5309
|
+
valueMaxWidths: valueWidths
|
|
5407
5310
|
});
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5311
|
+
};
|
|
5312
|
+
var buildPromptWrapLayout = (segment, contentWidth) => {
|
|
5313
|
+
const label = normalizeWhitespace(segment?.label || "Prompt") || "Prompt";
|
|
5314
|
+
const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
|
|
5315
|
+
const labelFontSize = DEFAULT_STRIP_LABEL_FONT_SIZE;
|
|
5316
|
+
const valueFontSize = DEFAULT_STRIP_VALUE_FONT_SIZE;
|
|
5317
|
+
const labelWidth = Math.max(
|
|
5318
|
+
DEFAULT_STRIP_LABEL_WIDTH,
|
|
5319
|
+
estimateTextWidth(label, labelFontSize) + DEFAULT_STRIP_LABEL_PADDING
|
|
5320
|
+
);
|
|
5321
|
+
const safeTotalWidth = Math.max(labelWidth + 56, Number(contentWidth) || 0);
|
|
5322
|
+
const valueWidth = Math.max(
|
|
5323
|
+
56,
|
|
5324
|
+
safeTotalWidth - labelWidth - DEFAULT_STRIP_CONTENT_SAFE_PADDING_X
|
|
5325
|
+
);
|
|
5326
|
+
const result = splitTextToLines(rawValue, valueWidth, valueFontSize, DEFAULT_STRIP_PROMPT_MAX_LINES);
|
|
5327
|
+
const lineHeight = Math.max(18, Math.round(valueFontSize * DEFAULT_STRIP_LINE_HEIGHT_RATIO));
|
|
5328
|
+
const lineWidths = result.lines.map((line) => estimateTextWidth(line, valueFontSize) + DEFAULT_STRIP_VALUE_PADDING);
|
|
5329
|
+
const measuredValueWidth = Math.min(
|
|
5330
|
+
valueWidth,
|
|
5331
|
+
Math.max(56, ...lineWidths)
|
|
5332
|
+
);
|
|
5333
|
+
const rowHeight = Math.round(Math.max(labelFontSize, valueFontSize) * 1.42);
|
|
5334
|
+
return {
|
|
5335
|
+
mode: result.lines.length === 1 ? "single" : "wrapped",
|
|
5336
|
+
label,
|
|
5337
|
+
rawValue,
|
|
5338
|
+
labelFontSize,
|
|
5339
|
+
labelWidth,
|
|
5340
|
+
valueFontSize,
|
|
5341
|
+
valueWidth,
|
|
5342
|
+
lines: result.lines,
|
|
5343
|
+
truncated: result.truncated,
|
|
5344
|
+
lineHeight,
|
|
5345
|
+
blockHeight: result.lines.length === 1 ? rowHeight : Math.max(lineHeight, result.lines.length * lineHeight),
|
|
5346
|
+
totalWidth: labelWidth + measuredValueWidth
|
|
5347
|
+
};
|
|
5348
|
+
};
|
|
5349
|
+
var buildStripLayout = (segments, contentWidth) => {
|
|
5350
|
+
const safeSegments = Array.isArray(segments) ? segments.filter(Boolean) : [];
|
|
5351
|
+
const promptSegment = safeSegments.find((segment) => segment.kind === "prompt") || safeSegments[0] || null;
|
|
5352
|
+
const metadataSegments = safeSegments.filter((segment) => segment !== promptSegment);
|
|
5353
|
+
const zoneGap = DEFAULT_STRIP_ZONE_GAP;
|
|
5354
|
+
let metadataRow = buildMetadataRowLayout(
|
|
5355
|
+
metadataSegments,
|
|
5356
|
+
Math.max(220, contentWidth)
|
|
5357
|
+
);
|
|
5358
|
+
let metadataStartX = Math.max(0, contentWidth - (metadataRow?.totalWidth || 0));
|
|
5359
|
+
let promptAvailableWidth = Math.max(
|
|
5360
|
+
220,
|
|
5361
|
+
metadataStartX - zoneGap - DEFAULT_STRIP_PROMPT_TRAILING_PADDING
|
|
5362
|
+
);
|
|
5363
|
+
if (promptAvailableWidth < DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH && metadataSegments.length > 0) {
|
|
5364
|
+
const tighterMetadataWidth = Math.max(180, contentWidth - DEFAULT_STRIP_PROMPT_MIN_TOTAL_WIDTH - zoneGap);
|
|
5365
|
+
metadataRow = buildMetadataRowLayout(metadataSegments, tighterMetadataWidth);
|
|
5366
|
+
metadataStartX = Math.max(0, contentWidth - (metadataRow?.totalWidth || 0));
|
|
5367
|
+
promptAvailableWidth = Math.max(
|
|
5368
|
+
220,
|
|
5369
|
+
metadataStartX - zoneGap - DEFAULT_STRIP_PROMPT_TRAILING_PADDING
|
|
5370
|
+
);
|
|
5371
|
+
}
|
|
5372
|
+
const preferredPromptWidth = Math.min(
|
|
5373
|
+
promptAvailableWidth,
|
|
5374
|
+
Math.max(280, Math.round(contentWidth * DEFAULT_STRIP_PROMPT_PREFERRED_WIDTH_RATIO))
|
|
5375
|
+
);
|
|
5376
|
+
let promptRow = buildPromptWrapLayout(promptSegment, preferredPromptWidth);
|
|
5377
|
+
if (promptRow?.truncated && promptAvailableWidth > preferredPromptWidth + 24) {
|
|
5378
|
+
promptRow = buildPromptWrapLayout(promptSegment, promptAvailableWidth);
|
|
5379
|
+
}
|
|
5380
|
+
const contentHeight = Math.max(
|
|
5381
|
+
promptRow?.blockHeight || 0,
|
|
5382
|
+
metadataRow?.rowHeight || 0,
|
|
5383
|
+
24
|
|
5384
|
+
);
|
|
5385
|
+
const verticalPadding = contentHeight > (metadataRow?.rowHeight || 0) ? 18 : 16;
|
|
5386
|
+
const stripHeight = Math.max(
|
|
5387
|
+
contentHeight > (metadataRow?.rowHeight || 0) ? DEFAULT_STRIP_WRAPPED_MIN_HEIGHT : DEFAULT_STRIP_ONE_LINE_HEIGHT,
|
|
5388
|
+
Math.ceil(contentHeight + verticalPadding * 2)
|
|
5389
|
+
);
|
|
5390
|
+
return {
|
|
5391
|
+
mode: "zoned",
|
|
5392
|
+
height: stripHeight,
|
|
5393
|
+
contentHeight,
|
|
5394
|
+
promptRow,
|
|
5395
|
+
promptStartX: 0,
|
|
5396
|
+
metadataRow,
|
|
5397
|
+
metadataStartX
|
|
5417
5398
|
};
|
|
5418
5399
|
};
|
|
5400
|
+
var renderStripRow = (row, options = {}) => {
|
|
5401
|
+
const startX = Number(options.startX) || 0;
|
|
5402
|
+
const centerY = Number(options.centerY) || 0;
|
|
5403
|
+
const fontFamily = String(options.fontFamily || "");
|
|
5404
|
+
const showDividers = options.showDividers !== false;
|
|
5405
|
+
const layouts = Array.isArray(row?.layouts) ? row.layouts : [];
|
|
5406
|
+
if (!layouts.length) {
|
|
5407
|
+
return "";
|
|
5408
|
+
}
|
|
5409
|
+
const rowHeight = Math.max(18, Number(row?.rowHeight) || 18);
|
|
5410
|
+
const dividerHalfHeight = Math.max(12, Math.round(rowHeight * 0.56));
|
|
5411
|
+
const sectionGap = Math.max(0, Number(row?.sectionGap) || 0);
|
|
5412
|
+
const svgSegments = [];
|
|
5413
|
+
let currentX = startX;
|
|
5414
|
+
layouts.forEach((segment, index) => {
|
|
5415
|
+
const label = escapeXml(segment.label || "");
|
|
5416
|
+
const value = escapeXml(segment.renderValue || "-");
|
|
5417
|
+
const labelX = currentX;
|
|
5418
|
+
const valueX = currentX + segment.labelWidth;
|
|
5419
|
+
svgSegments.push(`
|
|
5420
|
+
<text
|
|
5421
|
+
x="${labelX}"
|
|
5422
|
+
y="${centerY}"
|
|
5423
|
+
fill="#111111"
|
|
5424
|
+
fill-opacity="0.54"
|
|
5425
|
+
font-family="${fontFamily}"
|
|
5426
|
+
font-size="${segment.labelFontSize}"
|
|
5427
|
+
font-weight="650"
|
|
5428
|
+
dominant-baseline="middle"
|
|
5429
|
+
>${label}</text>
|
|
5430
|
+
<text
|
|
5431
|
+
x="${valueX}"
|
|
5432
|
+
y="${centerY}"
|
|
5433
|
+
fill="#111111"
|
|
5434
|
+
font-family="${fontFamily}"
|
|
5435
|
+
font-size="${segment.valueFontSize}"
|
|
5436
|
+
font-weight="${segment.kind === "prompt" ? 760 : 710}"
|
|
5437
|
+
dominant-baseline="middle"
|
|
5438
|
+
>${value}</text>
|
|
5439
|
+
`);
|
|
5440
|
+
currentX += segment.segmentWidth;
|
|
5441
|
+
if (showDividers && index < layouts.length - 1) {
|
|
5442
|
+
const lineX = currentX + Math.round(sectionGap / 2);
|
|
5443
|
+
svgSegments.push(`
|
|
5444
|
+
<line
|
|
5445
|
+
x1="${lineX}"
|
|
5446
|
+
y1="${centerY - dividerHalfHeight}"
|
|
5447
|
+
x2="${lineX}"
|
|
5448
|
+
y2="${centerY + dividerHalfHeight}"
|
|
5449
|
+
stroke="#94a3b8"
|
|
5450
|
+
stroke-opacity="0.34"
|
|
5451
|
+
stroke-width="1"
|
|
5452
|
+
/>
|
|
5453
|
+
`);
|
|
5454
|
+
currentX += sectionGap;
|
|
5455
|
+
}
|
|
5456
|
+
});
|
|
5457
|
+
return svgSegments.join("");
|
|
5458
|
+
};
|
|
5459
|
+
var renderStripDivider = (x, centerY, height) => {
|
|
5460
|
+
const safeX = Number(x) || 0;
|
|
5461
|
+
const safeCenterY = Number(centerY) || 0;
|
|
5462
|
+
const safeHeight = Math.max(18, Number(height) || 18);
|
|
5463
|
+
const halfHeight = Math.max(12, Math.round(safeHeight * 0.56));
|
|
5464
|
+
return `
|
|
5465
|
+
<line
|
|
5466
|
+
x1="${safeX}"
|
|
5467
|
+
y1="${safeCenterY - halfHeight}"
|
|
5468
|
+
x2="${safeX}"
|
|
5469
|
+
y2="${safeCenterY + halfHeight}"
|
|
5470
|
+
stroke="#94a3b8"
|
|
5471
|
+
stroke-opacity="0.34"
|
|
5472
|
+
stroke-width="1"
|
|
5473
|
+
/>
|
|
5474
|
+
`;
|
|
5475
|
+
};
|
|
5476
|
+
var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
|
|
5477
|
+
const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
|
|
5478
|
+
const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
|
|
5479
|
+
if (!hasWatermark && !hasStrip) {
|
|
5480
|
+
return "";
|
|
5481
|
+
}
|
|
5482
|
+
const width = Math.max(1, Number(imageWidth) || 1);
|
|
5483
|
+
const height = Math.max(1, Number(imageHeight) || 1);
|
|
5484
|
+
const fontFamily = escapeXml(buildFontFamily());
|
|
5485
|
+
const parts = [];
|
|
5486
|
+
if (hasWatermark) {
|
|
5487
|
+
const stampText = escapeXml(normalizeText(meta.watermarkText));
|
|
5488
|
+
const cellWidth = Math.max(680, Number(meta.watermark?.cellWidth) || DEFAULT_WATERMARK_CELL_WIDTH);
|
|
5489
|
+
const cellHeight = Math.max(260, Number(meta.watermark?.cellHeight) || DEFAULT_WATERMARK_CELL_HEIGHT);
|
|
5490
|
+
const rotateDeg = Number(meta.watermark?.rotateDeg) || DEFAULT_WATERMARK_ROTATE_DEG;
|
|
5491
|
+
const opacity = Math.min(0.22, Math.max(0.05, Number(meta.watermark?.opacity) || DEFAULT_WATERMARK_OPACITY));
|
|
5492
|
+
const rowOffset = Math.round(cellWidth * 0.24);
|
|
5493
|
+
const startX = -Math.round(cellWidth * 0.16);
|
|
5494
|
+
const startY = -Math.round(cellHeight * 0.12);
|
|
5495
|
+
const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
|
|
5496
|
+
const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
|
|
5497
|
+
const stamps = [];
|
|
5498
|
+
for (let row = 0; row < rows; row += 1) {
|
|
5499
|
+
for (let col = 0; col < cols; col += 1) {
|
|
5500
|
+
const x = startX + col * cellWidth + (row % 2 ? rowOffset : 0);
|
|
5501
|
+
const y = startY + row * cellHeight + (row % 2 ? 14 : -8);
|
|
5502
|
+
stamps.push(`
|
|
5503
|
+
<g transform="translate(${x} ${y}) rotate(${rotateDeg})">
|
|
5504
|
+
<text
|
|
5505
|
+
x="0"
|
|
5506
|
+
y="0"
|
|
5507
|
+
fill="#111111"
|
|
5508
|
+
fill-opacity="${opacity}"
|
|
5509
|
+
stroke="#ffffff"
|
|
5510
|
+
stroke-opacity="0.12"
|
|
5511
|
+
stroke-width="0.22"
|
|
5512
|
+
font-family="${fontFamily}"
|
|
5513
|
+
font-size="19"
|
|
5514
|
+
font-weight="720"
|
|
5515
|
+
letter-spacing="0.6"
|
|
5516
|
+
>${stampText}</text>
|
|
5517
|
+
</g>
|
|
5518
|
+
`);
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
|
|
5522
|
+
}
|
|
5523
|
+
if (hasStrip) {
|
|
5524
|
+
const logoSize = 28;
|
|
5525
|
+
const logoX = DEFAULT_STRIP_PADDING_LEFT;
|
|
5526
|
+
const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
|
|
5527
|
+
const contentWidth = width - contentStartX - DEFAULT_STRIP_PADDING_RIGHT;
|
|
5528
|
+
const stripLayout = buildStripLayout(meta.stripSegments, contentWidth);
|
|
5529
|
+
const stripHeight = stripLayout.height;
|
|
5530
|
+
const stripY = height - stripHeight;
|
|
5531
|
+
const logoY = Number((stripY + (stripHeight - logoSize) / 2).toFixed(2));
|
|
5532
|
+
let stripContentSvg = "";
|
|
5533
|
+
const centerY = stripY + stripHeight / 2 + 1;
|
|
5534
|
+
const promptRow = stripLayout.promptRow;
|
|
5535
|
+
const metadataRow = stripLayout.metadataRow;
|
|
5536
|
+
const promptParts = [];
|
|
5537
|
+
const hasPrompt = Boolean(promptRow?.label);
|
|
5538
|
+
const hasMetadata = Array.isArray(metadataRow?.layouts) && metadataRow.layouts.length > 0;
|
|
5539
|
+
const zoneDividerX = hasPrompt && hasMetadata ? contentStartX + stripLayout.metadataStartX - DEFAULT_STRIP_ZONE_GAP / 2 : null;
|
|
5540
|
+
if (promptRow?.mode === "single") {
|
|
5541
|
+
promptParts.push(renderStripRow({
|
|
5542
|
+
layouts: [
|
|
5543
|
+
{
|
|
5544
|
+
kind: "prompt",
|
|
5545
|
+
label: promptRow.label,
|
|
5546
|
+
renderValue: promptRow.lines[0] || "-",
|
|
5547
|
+
labelFontSize: promptRow.labelFontSize,
|
|
5548
|
+
valueFontSize: promptRow.valueFontSize,
|
|
5549
|
+
labelWidth: promptRow.labelWidth,
|
|
5550
|
+
segmentWidth: promptRow.labelWidth + promptRow.valueWidth
|
|
5551
|
+
}
|
|
5552
|
+
],
|
|
5553
|
+
sectionGap: 0,
|
|
5554
|
+
rowHeight: promptRow.blockHeight
|
|
5555
|
+
}, {
|
|
5556
|
+
startX: contentStartX + stripLayout.promptStartX,
|
|
5557
|
+
centerY,
|
|
5558
|
+
fontFamily,
|
|
5559
|
+
showDividers: false
|
|
5560
|
+
}));
|
|
5561
|
+
} else if (promptRow) {
|
|
5562
|
+
const promptStartX = contentStartX + stripLayout.promptStartX;
|
|
5563
|
+
const labelX = promptStartX;
|
|
5564
|
+
const valueX = promptStartX + promptRow.labelWidth;
|
|
5565
|
+
const blockTop = centerY - promptRow.blockHeight / 2;
|
|
5566
|
+
const labelY = centerY;
|
|
5567
|
+
promptParts.push(`
|
|
5568
|
+
<text
|
|
5569
|
+
x="${labelX}"
|
|
5570
|
+
y="${labelY}"
|
|
5571
|
+
fill="#111111"
|
|
5572
|
+
fill-opacity="0.54"
|
|
5573
|
+
font-family="${fontFamily}"
|
|
5574
|
+
font-size="${promptRow.labelFontSize}"
|
|
5575
|
+
font-weight="650"
|
|
5576
|
+
dominant-baseline="middle"
|
|
5577
|
+
>${escapeXml(promptRow.label)}</text>
|
|
5578
|
+
`);
|
|
5579
|
+
promptRow.lines.forEach((line, index) => {
|
|
5580
|
+
const lineY = blockTop + index * promptRow.lineHeight + promptRow.lineHeight / 2;
|
|
5581
|
+
promptParts.push(`
|
|
5582
|
+
<text
|
|
5583
|
+
x="${valueX}"
|
|
5584
|
+
y="${lineY}"
|
|
5585
|
+
fill="#111111"
|
|
5586
|
+
font-family="${fontFamily}"
|
|
5587
|
+
font-size="${promptRow.valueFontSize}"
|
|
5588
|
+
font-weight="760"
|
|
5589
|
+
dominant-baseline="middle"
|
|
5590
|
+
>${escapeXml(line)}</text>
|
|
5591
|
+
`);
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
stripContentSvg = [
|
|
5595
|
+
promptParts.join(""),
|
|
5596
|
+
zoneDividerX == null ? "" : renderStripDivider(
|
|
5597
|
+
zoneDividerX,
|
|
5598
|
+
centerY,
|
|
5599
|
+
Math.max(promptRow?.blockHeight || 0, metadataRow?.rowHeight || 0)
|
|
5600
|
+
),
|
|
5601
|
+
renderStripRow(metadataRow, {
|
|
5602
|
+
startX: contentStartX + stripLayout.metadataStartX,
|
|
5603
|
+
centerY,
|
|
5604
|
+
fontFamily,
|
|
5605
|
+
showDividers: true
|
|
5606
|
+
})
|
|
5607
|
+
].join("");
|
|
5608
|
+
parts.push(`
|
|
5609
|
+
<g id="strip">
|
|
5610
|
+
<rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
|
|
5611
|
+
<rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
|
|
5612
|
+
<rect x="${DEFAULT_STRIP_PADDING_LEFT}" y="${stripY}" width="${Math.max(120, Math.round(width * 0.42))}" height="2" fill="url(#stripAccent)" />
|
|
5613
|
+
${meta.stripLogoSrc ? `<image href="${escapeXml(meta.stripLogoSrc)}" x="${logoX}" y="${logoY}" width="${logoSize}" height="${logoSize}" />` : ""}
|
|
5614
|
+
${stripContentSvg}
|
|
5615
|
+
</g>
|
|
5616
|
+
`);
|
|
5617
|
+
}
|
|
5618
|
+
return `
|
|
5619
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
5620
|
+
<defs>
|
|
5621
|
+
<linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
5622
|
+
<stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
|
|
5623
|
+
<stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
|
|
5624
|
+
<stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
|
|
5625
|
+
<stop offset="100%" stop-color="#111111" stop-opacity="0" />
|
|
5626
|
+
</linearGradient>
|
|
5627
|
+
</defs>
|
|
5628
|
+
${parts.join("")}
|
|
5629
|
+
</svg>
|
|
5630
|
+
`;
|
|
5631
|
+
};
|
|
5632
|
+
var watermarkifyScreenshotBuffer = async (buffer, meta) => {
|
|
5633
|
+
const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
|
|
5634
|
+
const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
|
|
5635
|
+
if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
|
|
5636
|
+
return buffer;
|
|
5637
|
+
}
|
|
5638
|
+
const image = sharp(buffer, { failOn: "none" });
|
|
5639
|
+
const metadata = await image.metadata().catch(() => null);
|
|
5640
|
+
const width = Math.max(1, Number(metadata?.width) || 0);
|
|
5641
|
+
const height = Math.max(1, Number(metadata?.height) || 0);
|
|
5642
|
+
if (!width || !height) {
|
|
5643
|
+
return buffer;
|
|
5644
|
+
}
|
|
5645
|
+
const overlaySvg = buildWatermarkifySvg(meta, width, height);
|
|
5646
|
+
if (!overlaySvg) {
|
|
5647
|
+
return buffer;
|
|
5648
|
+
}
|
|
5649
|
+
return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
|
|
5650
|
+
};
|
|
5419
5651
|
|
|
5420
5652
|
// src/share.js
|
|
5421
5653
|
var logger11 = createInternalLogger("Share");
|
|
@@ -5495,6 +5727,20 @@ var normalizeShare = (share) => {
|
|
|
5495
5727
|
xurl: normalizeXurl(source.xurl)
|
|
5496
5728
|
};
|
|
5497
5729
|
};
|
|
5730
|
+
var resolveCaptureScreenWatermarkify = (page, optionValue) => {
|
|
5731
|
+
if (optionValue === false) {
|
|
5732
|
+
return normalizeScreenshotWatermarkify(false);
|
|
5733
|
+
}
|
|
5734
|
+
const runtimeQuery = String(page?.[PageRuntimeStateKey]?.query || "").trim();
|
|
5735
|
+
if (optionValue == null || optionValue === true) {
|
|
5736
|
+
return normalizeScreenshotWatermarkify(runtimeQuery ? { query: runtimeQuery } : true);
|
|
5737
|
+
}
|
|
5738
|
+
const optionSource = optionValue && typeof optionValue === "object" ? optionValue : {};
|
|
5739
|
+
return normalizeScreenshotWatermarkify({
|
|
5740
|
+
...runtimeQuery ? { query: runtimeQuery } : {},
|
|
5741
|
+
...optionSource
|
|
5742
|
+
});
|
|
5743
|
+
};
|
|
5498
5744
|
var getByPathSegments = (source, pathSegments) => {
|
|
5499
5745
|
if (!Array.isArray(pathSegments) || pathSegments.length === 0) return void 0;
|
|
5500
5746
|
let current = source;
|
|
@@ -5818,14 +6064,12 @@ var Share = {
|
|
|
5818
6064
|
* @returns {Promise<string>} base64 png
|
|
5819
6065
|
*/
|
|
5820
6066
|
async captureScreen(page, options = {}) {
|
|
5821
|
-
const originalViewport = page
|
|
5822
|
-
const defaultBuffer = Math.round((originalViewport
|
|
6067
|
+
const originalViewport = await resolveCurrentViewportSize(page);
|
|
6068
|
+
const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
|
|
5823
6069
|
const buffer = options.buffer ?? defaultBuffer;
|
|
5824
6070
|
const restore = options.restore ?? false;
|
|
5825
6071
|
const maxHeight = options.maxHeight ?? 8e3;
|
|
5826
|
-
const screenshotWatermarkify =
|
|
5827
|
-
let cleanupScreenshotWatermarkify = async () => {
|
|
5828
|
-
};
|
|
6072
|
+
const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
|
|
5829
6073
|
try {
|
|
5830
6074
|
const maxScrollHeight = await page.evaluate(() => {
|
|
5831
6075
|
let maxHeight2 = document.body.scrollHeight;
|
|
@@ -5849,23 +6093,26 @@ var Share = {
|
|
|
5849
6093
|
});
|
|
5850
6094
|
const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
|
|
5851
6095
|
await page.setViewportSize({
|
|
5852
|
-
width: originalViewport
|
|
6096
|
+
width: originalViewport.width,
|
|
5853
6097
|
height: targetHeight
|
|
5854
6098
|
});
|
|
5855
6099
|
await delay2(1e3);
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
cleanupScreenshotWatermarkify = await installScreenshotWatermarkify(page, watermarkifyMeta);
|
|
5859
|
-
await delay2(120);
|
|
5860
|
-
}
|
|
5861
|
-
const buffer_ = await capturePageScreenshot(page, {
|
|
6100
|
+
const capturedAt = /* @__PURE__ */ new Date();
|
|
6101
|
+
const rawBuffer = await capturePageScreenshot(page, {
|
|
5862
6102
|
fullPage: true,
|
|
5863
6103
|
type: "png",
|
|
5864
6104
|
maxClipHeight: targetHeight
|
|
5865
6105
|
});
|
|
6106
|
+
if (!screenshotWatermarkify.enabled) {
|
|
6107
|
+
return rawBuffer.toString("base64");
|
|
6108
|
+
}
|
|
6109
|
+
const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
|
|
6110
|
+
...screenshotWatermarkify,
|
|
6111
|
+
capturedAt
|
|
6112
|
+
});
|
|
6113
|
+
const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
|
|
5866
6114
|
return buffer_.toString("base64");
|
|
5867
6115
|
} finally {
|
|
5868
|
-
await cleanupScreenshotWatermarkify();
|
|
5869
6116
|
if (restore) {
|
|
5870
6117
|
await page.evaluate(() => {
|
|
5871
6118
|
document.querySelectorAll(".__pk_expanded__").forEach((el) => {
|
|
@@ -5878,9 +6125,7 @@ var Share = {
|
|
|
5878
6125
|
el.classList.remove("__pk_expanded__");
|
|
5879
6126
|
});
|
|
5880
6127
|
});
|
|
5881
|
-
|
|
5882
|
-
await page.setViewportSize(originalViewport);
|
|
5883
|
-
}
|
|
6128
|
+
await page.setViewportSize(originalViewport);
|
|
5884
6129
|
}
|
|
5885
6130
|
}
|
|
5886
6131
|
}
|