Просмотр исходного кода

add option "Destination > save with SingleFile Companion" (fix #562)

Gildas 4 лет назад
Родитель
Сommit
30964a10e5

+ 4 - 0
_locales/de/messages.json

@@ -499,6 +499,10 @@
 		"message": "In Google Drive speichern",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "Speichern mit SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "Die Seite eines neu angelegten Bookmark speichern",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/en/messages.json

@@ -499,6 +499,10 @@
 		"message": "upload to Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "save the page of a newly created bookmark",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/es/messages.json

@@ -499,6 +499,10 @@
 		"message": "subir a Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "guardar la página con SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "guardar la página de un marcador recién creado",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/fr/messages.json

@@ -499,6 +499,10 @@
 		"message": "téléverser sur Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "sauvegarder avec SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "sauvegarder la page d'un signet nouvellement créé",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/ja/messages.json

@@ -499,6 +499,10 @@
 		"message": "Google Drive に保存",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "新しく作成したブックマークのページを保存する",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/pl/messages.json

@@ -499,6 +499,10 @@
 		"message": "przesyłaj na Dysk Google",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "zapisuj stronę nowo utworzonej zakładki",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/ru/messages.json

@@ -499,6 +499,10 @@
 		"message": "загрузить на Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "сохранить страницу недавно созданной закладки",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/uk/messages.json

@@ -499,6 +499,10 @@
 		"message": "upload to Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "save the page of a newly created bookmark",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/zh_CN/messages.json

@@ -499,6 +499,10 @@
 		"message": "保存到 Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "创建新书签时保存其对应页面",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 4 - 0
_locales/zh_TW/messages.json

@@ -499,6 +499,10 @@
 		"message": "保存到 Google Drive",
 		"description": "Options page label: 'upload to Google Drive'"
 	},
+	"optionSaveWithCompanion": {
+		"message": "save with SingleFile Companion",
+		"description": "Options page label: 'save with SingleFile Companion'"
+	},
 	"optionSaveCreatedBookmarks": {
 		"message": "創建新書籤時保存其對應頁面",
 		"description": "Options page label: 'save the page of a newly created bookmark'"

+ 2 - 1
companion/README.MD

@@ -28,12 +28,13 @@ SingleFile Companion is a program that runs outside the browser. It:
 
 `install.bat` (Windows)
 
- - Enable the option `Misc. > save the page with SingleFile Companion` in SingleFile
+ - Enable the option `Destination > save with SingleFile Companion` or `Auto-save > save the page with SingleFile Companion` in SingleFile
 
 ## Options
 
 The `options.json` file allows configuring SingleFile Companion. Here are the entries you can edit:
  - `savePath`: path where to save files (default: `SingleFile/companion` path)
+These options are also available when the option `Auto-save > save the page with SingleFile Companion` is enabled:
  - `backEnd`: backend used to save the page (default: `"puppeteer"`)
  - `errorFile`: path of the file where errors are stored (default: `undefined`)
  - `browserHeadless`: whether the browser is launched in headless mode (default: `true`)

+ 20 - 5
companion/singlefile_companion.js

@@ -40,7 +40,7 @@ process.stdin
 	.pipe(new nativeMessage.Input())
 	.pipe(new nativeMessage.Transform(async function (message, push, done) {
 		try {
-			await capturePage(message);
+			await processMessage(message);
 			push({});
 		} catch (error) {
 			push({ error });
@@ -51,19 +51,34 @@ process.stdin
 	.pipe(new nativeMessage.Output())
 	.pipe(process.stdout);
 
-async function capturePage(options) {
+async function processMessage(message) {
+	if (message.method == "save") {
+		return save(message.pageData);
+	}
+	if (message.method == "externalSave") {
+		return externalSave(message.pageData);
+	}
+}
+
+async function save(message) {
+	const companionOptions = require("./options.json");
+	const filename = path.resolve("../../", (companionOptions.savePath || ""), message.filename);
+	fs.writeFileSync(getFilename(filename), message.content);
+}
+
+async function externalSave(message) {
 	const companionOptions = require("./options.json");
 	const backend = require(backEnds[companionOptions.backEnd || "puppeteer"]);
 	await backend.initialize(companionOptions);
 	try {
-		const pageData = await backend.getPageData(options);
+		const pageData = await backend.getPageData(message);
 		pageData.filename = path.resolve("../../", (companionOptions.savePath || ""), pageData.filename);
 		fs.writeFileSync(getFilename(pageData.filename), pageData.content);
 		return pageData;
 	} catch (error) {
 		if (companionOptions.errorFile) {
-			const message = "URL: " + options.url + "\nStack: " + error.stack + "\n";
-			fs.writeFileSync(options.errorFile, message, { flag: "a" });
+			const message = "URL: " + message.url + "\nStack: " + error.stack + "\n";
+			fs.writeFileSync(message.errorFile, message, { flag: "a" });
 		}
 		throw error;
 	} finally {

+ 1 - 1
companion/win/chrome/singlefile_companion.json

@@ -5,6 +5,6 @@
     "type": "stdio",
     "allowed_origins": [
         "chrome-extension://mpiodijhokgodhhofbcjdecpffjipkle/",
-        "chrome-extension://efnbkdcfmcmnhlkaijjjmhjjgladedno/"
+        "chrome-extension://ophkgdgpbdemngnakdmengfmgpnkgbmg/"
     ]
 }

+ 7 - 1
extension/core/bg/autosave.js

@@ -185,7 +185,7 @@ async function saveContent(message, tab) {
 		let pageData;
 		try {
 			if (options.autoSaveExternalSave) {
-				await companion.save(options);
+				await companion.externalSave(options);
 			} else {
 				pageData = await getPageData(options, null, null, { fetch });
 				if (options.includeInfobar) {
@@ -194,6 +194,12 @@ async function saveContent(message, tab) {
 				const blob = new Blob([pageData.content], { type: "text/html" });
 				if (options.saveToGDrive) {
 					await downloads.uploadPage(message.taskId, pageData.filename, blob, options, {});
+				} else if (options.saveWithCompanion) {
+					await companion.save({
+						filename: pageData.filename,
+						content: pageData.content,
+						filenameConflictAction: pageData.filenameConflictAction
+					});
 				} else {
 					pageData.url = URL.createObjectURL(blob);
 					await downloads.downloadPage(pageData, options);

+ 23 - 2
extension/core/bg/companion.js

@@ -30,6 +30,7 @@ let enabled = true;
 export {
 	enabled,
 	onMessage,
+	externalSave,
 	save
 };
 
@@ -39,11 +40,14 @@ async function onMessage(message) {
 	}
 }
 
-async function save(options) {
+async function externalSave(options) {
 	try {
 		options.autoSaveExternalSave = false;
 		const port = browser.runtime.connectNative("singlefile_companion");
-		port.postMessage(options);
+		port.postMessage({
+			method: "externalSave",
+			pageData: options
+		});
 		await new Promise((resolve, reject) => {
 			port.onDisconnect.addListener(() => {
 				if (port.error) {
@@ -58,4 +62,21 @@ async function save(options) {
 		console.error(error); // eslint-disable-line no-console			
 		ui.onError(options.tabId);
 	}
+}
+
+async function save(pageData) {
+	const port = browser.runtime.connectNative("singlefile_companion");
+	port.postMessage({
+		method: "save",
+		pageData
+	});
+	await new Promise((resolve, reject) => {
+		port.onDisconnect.addListener(() => {
+			if (port.error) {
+				reject(port.error.message);
+			} else if (!browser.runtime.lastError || browser.runtime.lastError.message.includes("Native host has exited")) {
+				resolve();
+			}
+		});
+	});
 }

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

@@ -87,6 +87,7 @@ const DEFAULT_CONFIG = {
 	saveToClipboard: false,
 	addProof: false,
 	saveToGDrive: false,
+	saveWithCompanion: false,
 	forceWebAuthFlow: false,
 	extractAuthCode: true,
 	resolveFragmentIdentifierURLs: false,

+ 8 - 0
extension/core/bg/downloads.js

@@ -25,6 +25,7 @@
 
 import * as config from "./config.js";
 import * as bookmarks from "./bookmarks.js";
+import * as companion from "./companion.js";
 import * as business from "./business.js";
 import * as editor from "./editor.js";
 import * as tabs from "./tabs.js";
@@ -115,6 +116,7 @@ async function downloadTabPage(message, tab) {
 				backgroundSave: message.backgroundSave,
 				saveToClipboard: message.saveToClipboard,
 				saveToGDrive: message.saveToGDrive,
+				saveWithCompanion: message.saveWithCompanion,
 				confirmFilename: message.confirmFilename,
 				incognito: tab.incognito,
 				filenameConflictAction: message.filenameConflictAction,
@@ -149,6 +151,12 @@ async function downloadBlob(blob, tab, incognito, message) {
 			}, {
 				onProgress: (offset, size) => ui.onUploadProgress(tab.id, offset, size)
 			});
+		} else if (message.saveWithCompanion) {
+			await companion.save({
+				filename: message.filename,
+				content: message.content,
+				filenameConflictAction: message.filenameConflictAction
+			});
 		} else {
 			message.url = URL.createObjectURL(blob);
 			await downloadPage(message, {

+ 2 - 1
extension/core/common/download.js

@@ -36,7 +36,7 @@ async function downloadPage(pageData, options) {
 	if (options.includeBOM) {
 		pageData.content = "\ufeff" + pageData.content;
 	}
-	if (options.backgroundSave || options.openEditor || options.saveToGDrive) {
+	if (options.backgroundSave || options.openEditor || options.saveToGDrive || options.saveWithCompanion) {
 		for (let blockIndex = 0; blockIndex * MAX_CONTENT_SIZE < pageData.content.length; blockIndex++) {
 			const message = {
 				method: "downloads.download",
@@ -46,6 +46,7 @@ async function downloadPage(pageData, options) {
 				filename: pageData.filename,
 				saveToClipboard: options.saveToClipboard,
 				saveToGDrive: options.saveToGDrive,
+				saveWithCompanion: options.saveWithCompanion,
 				forceWebAuthFlow: options.forceWebAuthFlow,
 				extractAuthCode: options.extractAuthCode,
 				filenameReplacementCharacter: options.filenameReplacementCharacter,

+ 1 - 1
extension/core/content/content.js

@@ -86,7 +86,7 @@ async function savePage(message) {
 			try {
 				const pageData = await processPage(options);
 				if (pageData) {
-					if (((!options.backgroundSave && !options.saveToClipboard) || options.saveToGDrive) && options.confirmFilename) {
+					if (((!options.backgroundSave && !options.saveToClipboard) || options.saveToGDrive || options.saveWithCompanion) && options.confirmFilename) {
 						pageData.filename = ui.prompt("Save as", pageData.filename) || pageData.filename;
 					}
 					await download.downloadPage(pageData, options);

+ 1 - 1
extension/lib/woleet/woleet.js

@@ -22,7 +22,7 @@
  */
 /* global fetch */
 const urlService = "https://api.woleet.io/v1/anchor";
-const apiKey = "";
+const apiKey = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhYzZmZTMzMi0wODNjLTRjZmMtYmYxNC0xNWU5MTJmMWY4OWIiLCJpYXQiOjE1NzYxNzQzNDV9.n31j9ctJj7R1Vjwyc5yd1d6Cmg0NDnpwSaLWsqtZJQA";
 export {
 	anchor
 };

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

@@ -39,6 +39,7 @@ const saveToClipboardLabel = document.getElementById("saveToClipboardLabel");
 const saveToFilesystemLabel = document.getElementById("saveToFilesystemLabel");
 const addProofLabel = document.getElementById("addProofLabel");
 const saveToGDriveLabel = document.getElementById("saveToGDriveLabel");
+const saveWithCompanionLabel = document.getElementById("saveWithCompanionLabel");
 const compressHTMLLabel = document.getElementById("compressHTMLLabel");
 const compressCSSLabel = document.getElementById("compressCSSLabel");
 const loadDeferredImagesLabel = document.getElementById("loadDeferredImagesLabel");
@@ -129,6 +130,7 @@ const insertMetaCSPInput = document.getElementById("insertMetaCSPInput");
 const saveToClipboardInput = document.getElementById("saveToClipboardInput");
 const addProofInput = document.getElementById("addProofInput");
 const saveToGDriveInput = document.getElementById("saveToGDriveInput");
+const saveWithCompanionInput = document.getElementById("saveWithCompanionInput");
 const saveToFilesystemInput = document.getElementById("saveToFilesystemInput");
 const compressHTMLInput = document.getElementById("compressHTMLInput");
 const compressCSSInput = document.getElementById("compressCSSInput");
@@ -465,6 +467,7 @@ saveToClipboardLabel.textContent = browser.i18n.getMessage("optionSaveToClipboar
 saveToFilesystemLabel.textContent = browser.i18n.getMessage("optionSaveToFilesystem");
 addProofLabel.textContent = browser.i18n.getMessage("optionAddProof");
 saveToGDriveLabel.textContent = browser.i18n.getMessage("optionSaveToGDrive");
+saveWithCompanionLabel.textContent = browser.i18n.getMessage("optionSaveWithCompanion");
 compressHTMLLabel.textContent = browser.i18n.getMessage("optionCompressHTML");
 compressCSSLabel.textContent = browser.i18n.getMessage("optionCompressCSS");
 loadDeferredImagesLabel.textContent = browser.i18n.getMessage("optionLoadDeferredImages");
@@ -668,7 +671,8 @@ async function refresh(profileName) {
 	saveToClipboardInput.checked = profileOptions.saveToClipboard;
 	addProofInput.checked = profileOptions.addProof;
 	saveToGDriveInput.checked = profileOptions.saveToGDrive;
-	saveToFilesystemInput.checked = !profileOptions.saveToGDrive && !saveToClipboardInput.checked;
+	saveWithCompanionInput.checked = profileOptions.saveWithCompanion;
+	// saveToFilesystemInput.checked = !profileOptions.saveToGDrive && !saveToClipboardInput.checked;
 	compressHTMLInput.checked = profileOptions.compressHTML;
 	compressCSSInput.checked = profileOptions.compressCSS;
 	loadDeferredImagesInput.checked = profileOptions.loadDeferredImages;
@@ -752,6 +756,7 @@ async function update() {
 			saveToClipboard: saveToClipboardInput.checked,
 			addProof: addProofInput.checked,
 			saveToGDrive: saveToGDriveInput.checked,
+			saveWithCompanion: saveWithCompanionInput.checked,
 			compressHTML: compressHTMLInput.checked,
 			compressCSS: compressCSSInput.checked,
 			loadDeferredImages: loadDeferredImagesInput.checked,

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

@@ -341,6 +341,15 @@
 							your Google Drive account. </p>
 						<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 					</li>
+					<li data-options-label="saveWithCompanionLabel"> <span class="option">Option: save 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"
+								target="_blank">here</a></p>
+						<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+					</li>
 				</ul>
 				<p>Annotation editor</p>
 				<ul>

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

@@ -189,6 +189,10 @@
 				<label for="saveToGDriveInput" id="saveToGDriveLabel"></label>
 				<input type="radio" id="saveToGDriveInput" name="destinationInput">
 			</div>
+			<div class="option">
+				<label for="saveWithCompanionInput" id="saveWithCompanionLabel"></label>
+				<input type="radio" id="saveWithCompanionInput" name="destinationInput">
+			</div>
 		</details>
 		<details>
 			<summary id="editorLabel"></summary>

+ 1 - 1
lib/single-file/single-file-core.js

@@ -525,7 +525,7 @@ class Processor {
 		if (!this.options.backgroundSave) {
 			filename = filename.replace(/\//g, replacementCharacter);
 		}
-		if (!this.options.saveToGDrive && util.getContentSize(filename) > this.options.filenameMaxLength) {
+		if (!this.options.saveToGDrive && !this.options.saveWithCompanion && util.getContentSize(filename) > this.options.filenameMaxLength) {
 			const extensionMatch = filename.match(/(\.[^.]{3,4})$/);
 			const extension = extensionMatch && extensionMatch[0] && extensionMatch[0].length > 1 ? extensionMatch[0] : "";
 			filename = await util.truncateText(filename, this.options.filenameMaxLength - extension.length);