浏览代码

merge conflicts

yooper 1 年之前
父节点
当前提交
ced41fcee9
共有 6 个文件被更改,包括 117 次插入72 次删除
  1. 3 0
      README.MD
  2. 45 29
      lib/single-file-extension-background.js
  3. 14 14
      package-lock.json
  4. 1 1
      package.json
  5. 44 28
      src/core/bg/tabs.js
  6. 10 0
      src/ui/pages/help.html

+ 3 - 0
README.MD

@@ -212,6 +212,9 @@ Footnotes:
   https://github.com/ArchiveBox/ArchiveBox
 - htmls-to-datasette - Tool to index HTML files into a Sqlite database:
   https://github.com/pjamar/htmls-to-datasette
+- linkding - Bookmark manager that you can host yourself. It's designed be to
+  be minimal, fast, and easy to set up using Docker:
+  https://github.com/sissbruecker/linkding
 - obsidian-html-plugin - Plugin for reading HTML pages in Obsidian:
   https://github.com/nuthrash/obsidian-html-plugin
 - Petal Cite Web Importer - Browser extension to save PDFs and capture web pages

+ 45 - 29
lib/single-file-extension-background.js

@@ -6197,46 +6197,62 @@
 	}
 
 	async function captureTab(tabId, options) {
-		const { width, height } = options;
-		const canvas = new OffscreenCanvas(width, height);
-		const context = canvas.getContext("2d");
+		const { width, height, scale = 1 } = options;
+		const canvasWidth = Math.floor(width * scale);
+		const canvasHeight = Math.floor(height * scale);
 		const image = new Image();
-		let y = 0, scrollYStep, activeTabId;
+		let y = 0, canvas, canvasY = 0, scrollYStep, activeTabId;
 		if (browser.tabs.captureTab) {
 			scrollYStep = 4 * 1024;
 		} else {
 			scrollYStep = options.innerHeight;
 			activeTabId = (await browser.tabs.query({ active: true, currentWindow: true }))[0].id;
-			await browser.tabs.sendMessage(tabId, { method: "content.beginScrollTo" });
-		}
-		while (y < height) {
-			let imageSrc;
-			if (browser.tabs.captureTab) {
-				imageSrc = await browser.tabs.captureTab(tabId, {
-					format: "png",
-					rect: { x: 0, y, width, height: Math.min(height - y, scrollYStep) }
+		}
+		const canvasScrollStep = Math.floor(scrollYStep * scale);
+		await browser.tabs.sendMessage(tabId, { method: "content.beginScrollTo" });
+		try {
+			canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
+			const context = canvas.getContext("2d");
+			while (y < height) {
+				let imageSrc;
+				if (browser.tabs.captureTab) {
+					imageSrc = await browser.tabs.captureTab(tabId, {
+						format: "png",
+						rect: { x: 0, y, width, height: Math.min(height - y, scrollYStep) }
+					});
+				} else {
+					await browser.tabs.sendMessage(tabId, { method: "content.scrollTo", y });
+					await browser.tabs.update(tabId, { active: true });
+					imageSrc = await browser.tabs.captureVisibleTab(null, {
+						format: "png"
+					});
+				}
+				await new Promise((resolve, reject) => {
+					image.onload = resolve;
+					image.onerror = event => reject(new Error(event.detail));
+					image.src = imageSrc;
 				});
+				const imageHeight = Math.min(canvasHeight - canvasY, canvasScrollStep);
+				context.drawImage(image, 0, canvasY, canvasWidth, imageHeight);
+				y += scrollYStep;
+				canvasY += canvasScrollStep;
+			}
+			if (!browser.tabs.captureTab) {
+				await browser.tabs.update(activeTabId, { active: true });
+			}
+		} catch (error) {
+			if (scale > .1) {
+				options.scale = scale * .75;
+				return captureTab(tabId, options);
 			} else {
-				await browser.tabs.sendMessage(tabId, { method: "content.scrollTo", y });
-				await browser.tabs.update(tabId, { active: true });
-				imageSrc = await browser.tabs.captureVisibleTab(null, {
-					format: "png"
-				});
+				throw error;
 			}
-			await new Promise((resolve, reject) => {
-				image.onload = resolve;
-				image.onerror = event => reject(new Error(event.detail));
-				image.src = imageSrc;
-			});
-			context.drawImage(image, 0, y, width, Math.min(height - y, scrollYStep));
-			y += scrollYStep;
-		}
-		if (!browser.tabs.captureTab) {
-			await browser.tabs.update(activeTabId, { active: true });
+		} finally {
 			await browser.tabs.sendMessage(tabId, { method: "content.endScrollTo" });
 		}
-		const blob = await canvas.convertToBlob({ type: "image/png" });
-		return URL.createObjectURL(blob);
+		if (canvas) {
+			return URL.createObjectURL(await canvas.convertToBlob({ type: "image/png" }));
+		}
 	}
 
 	/*

+ 14 - 14
package-lock.json

@@ -9,7 +9,7 @@
 			"version": "1.2.2",
 			"license": "AGPL-3.0-or-later",
 			"dependencies": {
-				"single-file-core": "1.4.0"
+				"single-file-core": "1.4.2"
 			},
 			"devDependencies": {
 				"@rollup/plugin-node-resolve": "15.0.1",
@@ -31,21 +31,21 @@
 			}
 		},
 		"node_modules/@babel/helper-validator-identifier": {
-			"version": "7.22.20",
-			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
-			"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+			"version": "7.24.5",
+			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
+			"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
 			"dev": true,
 			"engines": {
 				"node": ">=6.9.0"
 			}
 		},
 		"node_modules/@babel/highlight": {
-			"version": "7.24.2",
-			"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
-			"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
+			"version": "7.24.5",
+			"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
+			"integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
 			"dev": true,
 			"dependencies": {
-				"@babel/helper-validator-identifier": "^7.22.20",
+				"@babel/helper-validator-identifier": "^7.24.5",
 				"chalk": "^2.4.2",
 				"js-tokens": "^4.0.0",
 				"picocolors": "^1.0.0"
@@ -166,9 +166,9 @@
 			"dev": true
 		},
 		"node_modules/@types/node": {
-			"version": "20.12.7",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
-			"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
+			"version": "20.12.9",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.9.tgz",
+			"integrity": "sha512-o93r47yu04MHumPBCFg0bMPBMNgtMg3jzbhl7e68z50+BMHmRMGDJv13eBlUgOdc9i/uoJXGMGYLtJV4ReTXEg==",
 			"dev": true,
 			"dependencies": {
 				"undici-types": "~5.26.4"
@@ -516,9 +516,9 @@
 			}
 		},
 		"node_modules/single-file-core": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/single-file-core/-/single-file-core-1.4.0.tgz",
-			"integrity": "sha512-NUx8+4EparS4cbpeLpNC2ByFK02KyDXKrycwbvDsRgsXfc1KF1I65tixiZDHZ18T4ljh9t9x2dNgG46aGfL2gw=="
+			"version": "1.4.2",
+			"resolved": "https://registry.npmjs.org/single-file-core/-/single-file-core-1.4.2.tgz",
+			"integrity": "sha512-fUqUAg9gJZV+jUYwmCu4tenWN3q67W91jxlSR3v0BUpidQOsNtOR6ZKevmW6SQLTbrO8Icx3cHEg5DLfLg/1hg=="
 		},
 		"node_modules/source-map": {
 			"version": "0.6.1",

+ 1 - 1
package.json

@@ -9,7 +9,7 @@
 		"build": "./build-extension.sh"
 	},
 	"dependencies": {
-		"single-file-core": "1.4.0"
+		"single-file-core": "1.4.2"
 	},
 	"devDependencies": {
 		"@rollup/plugin-node-resolve": "15.0.1",

+ 44 - 28
src/core/bg/tabs.js

@@ -113,44 +113,60 @@ function onTabRemoved(tabId) {
 }
 
 async function captureTab(tabId, options) {
-	const { width, height } = options;
-	const canvas = new OffscreenCanvas(width, height);
-	const context = canvas.getContext("2d");
+	const { width, height, scale = 1 } = options;
+	const canvasWidth = Math.floor(width * scale);
+	const canvasHeight = Math.floor(height * scale);
 	const image = new Image();
-	let y = 0, scrollYStep, activeTabId;
+	let y = 0, canvas, canvasY = 0, scrollYStep, activeTabId;
 	if (browser.tabs.captureTab) {
 		scrollYStep = 4 * 1024;
 	} else {
 		scrollYStep = options.innerHeight;
 		activeTabId = (await browser.tabs.query({ active: true, currentWindow: true }))[0].id;
-		await browser.tabs.sendMessage(tabId, { method: "content.beginScrollTo" });
 	}
-	while (y < height) {
-		let imageSrc;
-		if (browser.tabs.captureTab) {
-			imageSrc = await browser.tabs.captureTab(tabId, {
-				format: "png",
-				rect: { x: 0, y, width, height: Math.min(height - y, scrollYStep) }
+	const canvasScrollStep = Math.floor(scrollYStep * scale);
+	await browser.tabs.sendMessage(tabId, { method: "content.beginScrollTo" });
+	try {
+		canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
+		const context = canvas.getContext("2d");
+		while (y < height) {
+			let imageSrc;
+			if (browser.tabs.captureTab) {
+				imageSrc = await browser.tabs.captureTab(tabId, {
+					format: "png",
+					rect: { x: 0, y, width, height: Math.min(height - y, scrollYStep) }
+				});
+			} else {
+				await browser.tabs.sendMessage(tabId, { method: "content.scrollTo", y });
+				await browser.tabs.update(tabId, { active: true });
+				imageSrc = await browser.tabs.captureVisibleTab(null, {
+					format: "png"
+				});
+			}
+			await new Promise((resolve, reject) => {
+				image.onload = resolve;
+				image.onerror = event => reject(new Error(event.detail));
+				image.src = imageSrc;
 			});
+			const imageHeight = Math.min(canvasHeight - canvasY, canvasScrollStep);
+			context.drawImage(image, 0, canvasY, canvasWidth, imageHeight);
+			y += scrollYStep;
+			canvasY += canvasScrollStep;
+		}
+		if (!browser.tabs.captureTab) {
+			await browser.tabs.update(activeTabId, { active: true });
+		}
+	} catch (error) {
+		if (scale > .1) {
+			options.scale = scale * .75;
+			return captureTab(tabId, options);
 		} else {
-			await browser.tabs.sendMessage(tabId, { method: "content.scrollTo", y });
-			await browser.tabs.update(tabId, { active: true });
-			imageSrc = await browser.tabs.captureVisibleTab(null, {
-				format: "png"
-			});
+			throw error;
 		}
-		await new Promise((resolve, reject) => {
-			image.onload = resolve;
-			image.onerror = event => reject(new Error(event.detail));
-			image.src = imageSrc;
-		});
-		context.drawImage(image, 0, y, width, Math.min(height - y, scrollYStep));
-		y += scrollYStep;
-	}
-	if (!browser.tabs.captureTab) {
-		await browser.tabs.update(activeTabId, { active: true });
+	} finally {
 		await browser.tabs.sendMessage(tabId, { method: "content.endScrollTo" });
 	}
-	const blob = await canvas.convertToBlob({ type: "image/png" });
-	return URL.createObjectURL(blob);
+	if (canvas) {
+		return URL.createObjectURL(await canvas.convertToBlob({ type: "image/png" }));
+	}
 }

+ 10 - 0
src/ui/pages/help.html

@@ -854,6 +854,7 @@
 					`{page-title}[10ch]` to limit the title to 10 characters).
 				</p>
 				<ul>
+					<li><code>{navigator-language}</code>: the language of the browser</li>
 					<li><code>{page-title}</code>: the title of the page</li>
 					<li><code>{page-heading}</code>: the content of the H1 tag in the page</li>
 					<li><code>{page-language}</code>: the language of the page</li>
@@ -1099,6 +1100,15 @@
 						attribute of the first element matching the specified selector (e.g.
 						"%page-element-attribute&lt;h1|class&gt;" for the class attribute of the first H1 element)
 					</li>
+					<li><code>%date-locale&lt;locales&gt;</code>: the localized value of the date and time (e.g.
+						"%date-locale&lt;en-US&gt;" for the date and time in the US English format)
+					</li>
+					<li><code>%time-locale&lt;locales&gt;</code>: the localized value of the time (e.g.
+						"%time-locale&lt;en-US&gt;" for the time in the US English format)
+					</li>
+					<li><code>%datetime-locale&lt;locales&gt;</code>: the localized value of the date and time (e.g.
+						"%datetime-locale&lt;en-US&gt;" for the date and time in the US English format)
+					</li>
 				</ul>
 			</li>
 			<li>