Kaynağa Gözat

Added option "Auto-save > save the page with SingleFile Companion"

Gildas 5 yıl önce
ebeveyn
işleme
30903d89bb

+ 4 - 0
_locales/de/messages.json

@@ -367,6 +367,10 @@
 		"message": "Zeitraum (s.)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "Speichern der Seite mit SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/en/messages.json

@@ -367,6 +367,10 @@
 		"message": "period (s.)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/es/messages.json

@@ -367,6 +367,10 @@
 		"message": "periodo (s)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "guardar la página con SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/fr/messages.json

@@ -367,6 +367,10 @@
 		"message": "période (s)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "sauvegarder la page avec SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Éditeur d'annotations",
 		"description": "Options sub-title: 'Éditeur d'annotations'"

+ 4 - 0
_locales/ja/messages.json

@@ -367,6 +367,10 @@
 		"message": "所要時間(秒)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "注釈エディタ",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/pl/messages.json

@@ -367,6 +367,10 @@
 		"message": "okres (s)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Edytor adnotacji",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/ru/messages.json

@@ -367,6 +367,10 @@
 		"message": "период (сек.)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Редактор аннотаций",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/uk/messages.json

@@ -367,6 +367,10 @@
 		"message": "період (с.)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/zh_CN/messages.json

@@ -367,6 +367,10 @@
 		"message": "周期(秒)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},	
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 4 - 0
_locales/zh_TW/messages.json

@@ -367,6 +367,10 @@
 		"message": "週期(秒)",
 		"description": "Options page label: 'period (s)'"
 	},
+	"optionAutoSaveExternalSave": {
+		"message": "save the page with SingleFile Companion",
+		"description": "Options page label: 'save the page with SingleFile Companion'"
+	},
 	"optionsEditorSubTitle": {
 		"message": "Annotation editor",
 		"description": "Options sub-title: 'Annotation editor'"

+ 6 - 3
build-extension.sh

@@ -5,18 +5,21 @@ cp extension/core/bg/downloads.js downloads.copy.js
 sed -i 's/207618107333-bktohpfmdfnv5hfavi1ll18h74gqi27v/207618107333-8fpm0a5h0lho1svrhdj21sbri3via774/g' extension/core/bg/downloads.js
 
 cp extension/core/bg/config.js config.copy.js
-jq "del(.options_page,.background.persistent,.optional_permissions[0],.oauth2)" manifest.copy.json > manifest.json
+cp extension/core/bg/companion.js companion.copy.js
+jq "del(.options_page,.background.persistent,.optional_permissions[0],.optional_permissions[1],.oauth2)" manifest.copy.json > manifest.json
 sed -i 's/207618107333-bktohpfmdfnv5hfavi1ll18h74gqi27v/207618107333-8fpm0a5h0lho1svrhdj21sbri3via774/g' manifest.json
 sed -i 's/forceWebAuthFlow: false/forceWebAuthFlow: true/g' extension/core/bg/config.js
+sed -i 's/enabled: true/enabled: false/g' extension/core/bg/companion.js
 zip -r singlefile-extension-firefox.zip manifest.json common extension lib _locales
 mv config.copy.js extension/core/bg/config.js
+mv companion.copy.js extension/core/bg/companion.js
 
-jq "del(.browser_specific_settings,.permissions[0],.permissions[1],.options_ui.browser_style)" manifest.copy.json > manifest.json
+jq "del(.browser_specific_settings,.permissions[0],.permissions[1],.permissions[2],.options_ui.browser_style)" manifest.copy.json > manifest.json
 sed -i 's/207618107333-bktohpfmdfnv5hfavi1ll18h74gqi27v/207618107333-8fpm0a5h0lho1svrhdj21sbri3via774/g' manifest.json
 zip -r singlefile-extension-chromium.zip manifest.json common extension lib _locales
 
 cp extension/core/bg/config.js config.copy.js
-jq "del(.browser_specific_settings,.permissions[0],.permissions[1],.options_ui.browser_style)" manifest.copy.json > manifest.json
+jq "del(.browser_specific_settings,.permissions[0],.permissions[1],.permissions[2],.options_ui.browser_style)" manifest.copy.json > manifest.json
 sed -i 's/207618107333-bktohpfmdfnv5hfavi1ll18h74gqi27v/207618107333-8fpm0a5h0lho1svrhdj21sbri3via774/g' manifest.json
 sed -i 's/forceWebAuthFlow: false/forceWebAuthFlow: true/g' extension/core/bg/config.js
 mkdir _locales.copy

+ 28 - 0
companion/README.MD

@@ -0,0 +1,28 @@
+# SingleFile Companion
+SingleFile Companion is a program that runs outside the browser and can help to make the saving process more transparent when the auto-save is active. It also allows the pages to be saved in another directory than the download directory. It uses the [Native Messaging API](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/Native_messaging) to communicate with SingleFile.
+
+## Install
+
+ - Install [SingleFile CLI](https://github.com/gildas-lormeau/SingleFile/tree/master/cli)
+
+ - In the `companion` folder of SingleFile, go into the subfolder corresponding to your OS and your browser. For example, if you use Chome on Windows:
+
+`cd companion`
+
+`cd win`
+
+`cd chrome`
+
+ - Make `install.sh` executable (Linux/Unix/BSD etc.).
+
+`chmod +x install.sh`
+
+ - Run `install`
+
+`./install.sh` (Linux/Unix/BSD etc.)
+
+`install.bat` (Windows)
+
+## Notes
+
+ - Only the Chrome version of SingleFile allows you to use SingleFile Companion at the moment. This feature will be available in Firefox when this bug is fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=1630415. Although, you can use SingleFile Companion with Firefox by installing it SingleFile manually, see https://github.com/gildas-lormeau/SingleFile#install.

+ 9 - 4
companion/singlefile_companion.js

@@ -38,10 +38,15 @@ const backEnds = {
 
 process.stdin
 	.pipe(new nativeMessage.Input())
-	.pipe(new nativeMessage.Transform(function (msg, push, done) {
-		capturePage(msg);
-		push(JSON.stringify(msg));
+	.pipe(new nativeMessage.Transform(async function (message, push, done) {
+		try {
+			await capturePage(message);
+			push({});
+		} catch (error) {
+			push({ error });
+		}
 		done();
+		process.exit(0);
 	}))
 	.pipe(new nativeMessage.Output())
 	.pipe(process.stdout);
@@ -60,9 +65,9 @@ async function capturePage(options) {
 			const message = "URL: " + options.url + "\nStack: " + error.stack + "\n";
 			fs.writeFileSync(options.errorFile, message, { flag: "a" });
 		}
+		throw error;
 	} finally {
 		await backend.closeBrowser();
-		process.exit(0);
 	}
 }
 

+ 7 - 3
extension/core/bg/companion.js

@@ -24,8 +24,13 @@
 /* global singlefile, browser */
 
 singlefile.extension.core.bg.companion = {
-
-	save: async options => {
+	enabled: true,
+	async onMessage(message) {
+		if (message.method.endsWith(".state")) {
+			return { enabled: this.enabled };
+		}
+	},
+	async save(options) {
 		try {
 			options.autoSaveExternalSave = false;
 			const port = browser.runtime.connectNative("singlefile_companion");
@@ -45,5 +50,4 @@ singlefile.extension.core.bg.companion = {
 			singlefile.extension.ui.bg.main.onError(options.tabId);
 		}
 	}
-
 };

+ 2 - 1
extension/core/bg/config.js

@@ -93,7 +93,8 @@ singlefile.extension.core.bg.config = (() => {
 		replaceBookmarkURL: true,
 		saveFavicon: true,
 		includeBOM: false,
-		warnUnsavedPage: true
+		warnUnsavedPage: true,
+		autoSaveExternalSave: false
 	};
 
 	let configStorage;

+ 3 - 0
extension/core/bg/messages.js

@@ -53,6 +53,9 @@ singlefile.extension.core.bg.messages = (() => {
 		if (message.method.startsWith("bookmarks.")) {
 			return singlefile.extension.core.bg.bookmarks.onMessage(message, sender);
 		}
+		if (message.method.startsWith("companion.")) {
+			return singlefile.extension.core.bg.companion.onMessage(message, sender);
+		}
 	});
 	if (browser.runtime.onMessageExternal) {
 		browser.runtime.onMessageExternal.addListener(async (message, sender) => {

+ 40 - 1
extension/ui/bg/ui-options.js

@@ -66,6 +66,7 @@
 	const autoSaveLoadOrUnloadLabel = document.getElementById("autoSaveLoadOrUnloadLabel");
 	const autoSaveRepeatLabel = document.getElementById("autoSaveRepeatLabel");
 	const autoSaveRepeatDelayLabel = document.getElementById("autoSaveRepeatDelayLabel");
+	const autoSaveExternalSaveLabel = document.getElementById("autoSaveExternalSaveLabel");
 	const removeAlternativeFontsLabel = document.getElementById("removeAlternativeFontsLabel");
 	const removeAlternativeImagesLabel = document.getElementById("removeAlternativeImagesLabel");
 	const removeAlternativeMediasLabel = document.getElementById("removeAlternativeMediasLabel");
@@ -141,6 +142,7 @@
 	const autoSaveLoadOrUnloadInput = document.getElementById("autoSaveLoadOrUnloadInput");
 	const autoSaveRepeatInput = document.getElementById("autoSaveRepeatInput");
 	const autoSaveRepeatDelayInput = document.getElementById("autoSaveRepeatDelayInput");
+	const autoSaveExternalSaveInput = document.getElementById("autoSaveExternalSaveInput");
 	const removeAlternativeFontsInput = document.getElementById("removeAlternativeFontsInput");
 	const removeAlternativeImagesInput = document.getElementById("removeAlternativeImagesInput");
 	const removeAlternativeMediasInput = document.getElementById("removeAlternativeMediasInput");
@@ -369,6 +371,7 @@
 		}
 	}, false);
 	saveCreatedBookmarksInput.addEventListener("click", saveCreatedBookmarks, false);
+	autoSaveExternalSaveInput.addEventListener("click", enableExternalSave, false);
 	saveToGDriveInput.addEventListener("click", async () => {
 		if (!saveToGDriveInput.checked) {
 			await browser.runtime.sendMessage({ method: "downloads.disableGDrive" });
@@ -466,6 +469,7 @@
 	autoSaveLoadOrUnloadLabel.textContent = browser.i18n.getMessage("optionAutoSaveLoadOrUnload");
 	autoSaveRepeatLabel.textContent = browser.i18n.getMessage("optionAutoSaveRepeat");
 	autoSaveRepeatDelayLabel.textContent = browser.i18n.getMessage("optionAutoSaveRepeatDelay");
+	autoSaveExternalSaveLabel.textContent = browser.i18n.getMessage("optionAutoSaveExternalSave");
 	removeAlternativeFontsLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeFonts");
 	removeAlternativeImagesLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeImages");
 	removeAlternativeMediasLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeMedias");
@@ -521,7 +525,10 @@
 	refresh(tabsData.profileName);
 
 	async function refresh(profileName) {
-		const [profiles, rules] = await Promise.all([browser.runtime.sendMessage({ method: "config.getProfiles" }), browser.runtime.sendMessage({ method: "config.getRules" })]);
+		const [profiles, rules, companionState] = await Promise.all([
+			browser.runtime.sendMessage({ method: "config.getProfiles" }),
+			browser.runtime.sendMessage({ method: "config.getRules" }),
+			browser.runtime.sendMessage({ method: "companion.state" })]);
 		const selectedProfileName = profileName || profileNamesInput.value || DEFAULT_PROFILE_NAME;
 		Array.from(profileNamesInput.childNodes).forEach(node => node.remove());
 		profileNamesInput.options.length = 0;
@@ -660,6 +667,8 @@
 		autoSaveRepeatInput.disabled = !profileOptions.autoSaveLoadOrUnload && !profileOptions.autoSaveLoad;
 		autoSaveRepeatDelayInput.value = profileOptions.autoSaveRepeatDelay;
 		autoSaveRepeatDelayInput.disabled = !profileOptions.autoSaveRepeat;
+		autoSaveExternalSaveInput.checked = profileOptions.autoSaveExternalSave;
+		autoSaveExternalSaveInput.parentElement.hidden = !companionState.enabled;
 		removeAlternativeFontsInput.checked = profileOptions.removeAlternativeFonts;
 		removeAlternativeImagesInput.checked = profileOptions.removeAlternativeImages;
 		groupDuplicateImagesInput.checked = profileOptions.groupDuplicateImages;
@@ -727,6 +736,7 @@
 				autoSaveLoadOrUnload: autoSaveLoadOrUnloadInput.checked,
 				autoSaveRepeat: autoSaveRepeatInput.checked,
 				autoSaveRepeatDelay: Math.max(autoSaveRepeatDelayInput.value, 1),
+				autoSaveExternalSave: autoSaveExternalSaveInput.checked,
 				removeAlternativeFonts: removeAlternativeFontsInput.checked,
 				removeAlternativeImages: removeAlternativeImagesInput.checked,
 				removeAlternativeMedias: removeAlternativeMediasInput.checked,
@@ -786,6 +796,35 @@
 		}
 	}
 
+	async function enableExternalSave() {
+		if (autoSaveExternalSaveInput.checked) {
+			autoSaveExternalSaveInput.checked = false;
+			try {
+				const permissionGranted = await browser.permissions.request({ permissions: ["nativeMessaging"] });
+				if (permissionGranted) {
+					autoSaveExternalSaveInput.checked = true;
+					await refreshOption();
+					if (window.chrome) {
+						window.chrome.runtime.reload();
+						location.reload();
+					}
+				} else {
+					await refreshOption();
+				}
+			} catch (error) {
+				autoSaveExternalSaveInput.checked = true;
+				await refreshOption();
+			}
+		} else {
+			await refreshOption();
+		}
+
+		async function refreshOption() {
+			await update();
+			await refresh();
+		}
+	}
+
 	async function confirm(message, position = "center") {
 		document.getElementById("confirmLabel").textContent = message;
 		document.getElementById("formConfirmContainer").style.setProperty("display", "flex");

+ 8 - 0
extension/ui/pages/help.html

@@ -332,6 +332,14 @@
 						<p>Specify the delay in seconds to wait before each page saving when the "auto-save
 							periodically" option is checked. </p>
 					</li>
+					<li data-options-label="autoSaveExternalSaveLabel"> <span class="option">Option: save the page with
+							SingleFile Companion</span>
+						<p>Check this option to delegate the saving process to SingleFile Companion. It is a program
+							that runs outside the browser and can help to make the saving process more transparent. It
+							also allows the pages to be saved in another directory than the download directory. You
+							can find more info <a
+								href="https://github.com/gildas-lormeau/SingleFile/tree/master/companion">here</a></p>
+					</li>
 				</ul>
 				<p>Annotation editor</p>
 				<ul>

+ 1 - 1
extension/ui/pages/options.css

@@ -339,7 +339,7 @@ a {
     margin-left: 10px;
 }
 
-.option {
+.option:not([hidden]) {
     display: flex;
     justify-content: space-between;
     margin-top: 3px;

+ 4 - 0
extension/ui/pages/options.html

@@ -188,6 +188,10 @@
 				<label for="autoSaveRepeatDelayInput" id="autoSaveRepeatDelayLabel"></label>
 				<input type="number" id="autoSaveRepeatDelayInput" min="1">
 			</div>
+			<div class="option">
+				<label for="autoSaveExternalSaveInput" id="autoSaveExternalSaveLabel"></label>
+				<input type="checkbox" id="autoSaveExternalSaveInput">
+			</div>
 		</details>
 		<details>
 			<summary id="editorLabel"></summary>

+ 2 - 0
manifest.json

@@ -161,6 +161,7 @@
 	"permissions": [
 		"identity",
 		"menus",
+		"nativeMessaging",
 		"clipboardWrite",
 		"contextMenus",
 		"downloads",
@@ -170,6 +171,7 @@
 	],
 	"optional_permissions": [
 		"identity",
+		"nativeMessaging",
 		"bookmarks"
 	],
 	"browser_specific_settings": {