single-file-cli 1.1.53 → 2.0.2
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/{.eslintrc.js → .eslintrc.json} +5 -6
- package/Dockerfile +2 -1
- package/README.MD +56 -60
- package/args.js +252 -334
- package/back-ends/chromium-back-end.js +223 -0
- package/back-ends/chromium-browser.js +89 -0
- package/back-ends/chromium-constants.js +157 -0
- package/back-ends/{common/scripts.js → single-file-script.js} +21 -49
- package/build-lib-dev.sh +84 -0
- package/build-lib.sh +80 -3
- package/compile.sh +13 -0
- package/deno-polyfill.js +223 -0
- package/deno.json +13 -0
- package/deno.lock +49 -0
- package/lib/single-file-bundle.js +1 -0
- package/package.json +9 -33
- package/single-file +39 -14
- package/single-file-cli-api.js +32 -44
- package/back-ends/extensions/bypass-csp/index.js +0 -36
- package/back-ends/extensions/bypass-csp/manifest.json +0 -20
- package/back-ends/extensions/disable-web-security/index.js +0 -54
- package/back-ends/extensions/disable-web-security/manifest.json +0 -20
- package/back-ends/extensions/network-idle/bg.js +0 -61
- package/back-ends/extensions/network-idle/content.js +0 -29
- package/back-ends/extensions/network-idle/manifest.json +0 -31
- package/back-ends/extensions/signed/bypass_csp-0.0.3-an+fx.xpi +0 -0
- package/back-ends/extensions/signed/disable_web_security-0.0.3-an+fx.xpi +0 -0
- package/back-ends/extensions/signed/network_idle-0.0.2-an+fx.xpi +0 -0
- package/back-ends/jsdom.js +0 -159
- package/back-ends/playwright-chromium.js +0 -126
- package/back-ends/playwright-firefox.js +0 -115
- package/back-ends/playwright-webkit.js +0 -126
- package/back-ends/puppeteer-firefox.js +0 -172
- package/back-ends/puppeteer.js +0 -201
- package/back-ends/webdriver-chromium.js +0 -172
- package/back-ends/webdriver-gecko.js +0 -190
- package/lib/single-file-bootstrap.js +0 -1
- package/lib/single-file-frames.js +0 -1
- package/lib/single-file-hooks-frames.js +0 -1
- package/lib/single-file-zip.min.js +0 -1
- package/lib/single-file.js +0 -1
- package/rollup.config.dev.js +0 -57
- package/rollup.config.js +0 -58
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2010-2024 Gildas Lormeau
|
|
3
|
+
* contact : gildas.lormeau <at> gmail.com
|
|
4
|
+
*
|
|
5
|
+
* This file is part of SingleFile.
|
|
6
|
+
*
|
|
7
|
+
* The code in this file is free software: you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Affero General Public License
|
|
9
|
+
* (GNU AGPL) as published by the Free Software Foundation, either version 3
|
|
10
|
+
* of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* The code in this file is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
|
15
|
+
* General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* As additional permission under GNU AGPL version 3 section 7, you may
|
|
18
|
+
* distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
|
|
19
|
+
* AGPL normally required by section 4, provided you include this license
|
|
20
|
+
* notice and a URL through which recipients can access the Corresponding
|
|
21
|
+
* Source.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/* global setTimeout, clearTimeout */
|
|
25
|
+
|
|
26
|
+
import { launchBrowser, closeBrowser } from "./chromium-browser.js";
|
|
27
|
+
import { getScriptSource, getHookScriptSource } from "./single-file-script.js";
|
|
28
|
+
import { getCDP } from "../deno-polyfill.js";
|
|
29
|
+
|
|
30
|
+
const LOAD_TIMEOUT_ERROR = "ERR_LOAD_TIMEOUT";
|
|
31
|
+
const NETWORK_IDLE_STATE = "networkIdle";
|
|
32
|
+
const NETWORK_STATES = ["networkAlmostIdle", "load", "DOMContentLoaded"];
|
|
33
|
+
const MINIMIZED_WINDOW_STATE = "minimized";
|
|
34
|
+
const SINGLE_FILE_WORLD_NAME = "singlefile";
|
|
35
|
+
const EMPTY_PAGE_URL = "about:blank";
|
|
36
|
+
|
|
37
|
+
export { initialize, getPageData, closeBrowser };
|
|
38
|
+
|
|
39
|
+
async function initialize(options) {
|
|
40
|
+
await launchBrowser(getBrowserOptions(options));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getPageData(options) {
|
|
44
|
+
let targetInfo;
|
|
45
|
+
const CDP = await getCDP();
|
|
46
|
+
try {
|
|
47
|
+
const targetInfo = await CDP.createTarget({ url: EMPTY_PAGE_URL });
|
|
48
|
+
const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger } = new CDP(targetInfo);
|
|
49
|
+
if (options.browserStartMinimized) {
|
|
50
|
+
const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.targetId });
|
|
51
|
+
if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
|
|
52
|
+
await Browser.setWindowBounds({ windowId, bounds: { windowState: MINIMIZED_WINDOW_STATE } });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (options.browserIgnoreHTTPSErrors !== undefined && options.browserIgnoreHTTPSErrors) {
|
|
56
|
+
await Security.setIgnoreCertificateErrors({ ignore: true });
|
|
57
|
+
}
|
|
58
|
+
if (options.browserByPassCSP === undefined || options.browserByPassCSP) {
|
|
59
|
+
await Page.setBypassCSP({ enabled: true });
|
|
60
|
+
}
|
|
61
|
+
if (options.browserMobileEmulation) {
|
|
62
|
+
await Emulation.setDeviceMetricsOverride({ mobile: true });
|
|
63
|
+
}
|
|
64
|
+
if (options.httpProxyServer && options.httpProxyUsername) {
|
|
65
|
+
await Fetch.enable({ handleAuthRequests: true });
|
|
66
|
+
Fetch.addEventListener("authRequired", async ({ params }) => {
|
|
67
|
+
await Fetch.continueWithAuth({
|
|
68
|
+
requestId: params.requestId,
|
|
69
|
+
authChallengeResponse: {
|
|
70
|
+
response: "ProvideCredentials",
|
|
71
|
+
username: options.httpProxyUsername,
|
|
72
|
+
password: options.httpProxyPassword
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
Fetch.addEventListener("requestPaused", ({ params }) => Fetch.continueRequest({ requestId: params.requestId }));
|
|
77
|
+
}
|
|
78
|
+
if (options.httpHeaders && options.httpHeaders.length) {
|
|
79
|
+
await Network.setExtraHTTPHeaders({ headers: options.httpHeaders });
|
|
80
|
+
}
|
|
81
|
+
if (options.emulateMediaFeatures) {
|
|
82
|
+
for (const mediaFeature of options.emulateMediaFeatures) {
|
|
83
|
+
await Emulation.setEmulatedMedia({
|
|
84
|
+
media: mediaFeature.name,
|
|
85
|
+
features: mediaFeature.value.split(",").map(feature => feature.trim())
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (options.browserCookies && options.browserCookies.length) {
|
|
90
|
+
await Network.setCookies({ cookies: options.browserCookies });
|
|
91
|
+
}
|
|
92
|
+
let debuggerReady;
|
|
93
|
+
if (options.browserDebug) {
|
|
94
|
+
await Debugger.enable();
|
|
95
|
+
debuggerReady = new Promise(resolve => {
|
|
96
|
+
const SCRIPT_PARSED_EVENT = "scriptParsed";
|
|
97
|
+
const RESUMED_EVENT = "resumed";
|
|
98
|
+
Debugger.addEventListener(SCRIPT_PARSED_EVENT, onScriptParsed);
|
|
99
|
+
|
|
100
|
+
async function onScriptParsed() {
|
|
101
|
+
Debugger.removeEventListener(SCRIPT_PARSED_EVENT, onScriptParsed);
|
|
102
|
+
Debugger.addEventListener(RESUMED_EVENT, onResumed);
|
|
103
|
+
await Debugger.pause();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function onResumed() {
|
|
107
|
+
Debugger.removeEventListener(RESUMED_EVENT, onResumed);
|
|
108
|
+
await Debugger.disable();
|
|
109
|
+
resolve();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
await Page.addScriptToEvaluateOnNewDocument({
|
|
114
|
+
source: await getHookScriptSource(),
|
|
115
|
+
runImmediately: true
|
|
116
|
+
});
|
|
117
|
+
await Page.addScriptToEvaluateOnNewDocument({
|
|
118
|
+
source: await getScriptSource(options),
|
|
119
|
+
runImmediately: true,
|
|
120
|
+
worldName: SINGLE_FILE_WORLD_NAME
|
|
121
|
+
});
|
|
122
|
+
await Runtime.enable();
|
|
123
|
+
let topFrameId;
|
|
124
|
+
const executionContextIdPromise = new Promise(resolve => {
|
|
125
|
+
const CONTEXT_CREATED_EVENT = "executionContextCreated";
|
|
126
|
+
Runtime.addEventListener(CONTEXT_CREATED_EVENT, executionContextCreated);
|
|
127
|
+
|
|
128
|
+
async function executionContextCreated({ params }) {
|
|
129
|
+
const { context } = params;
|
|
130
|
+
if (context.auxData && context.auxData.isDefault && topFrameId === undefined) {
|
|
131
|
+
topFrameId = context.auxData.frameId;
|
|
132
|
+
} else if (context.name === SINGLE_FILE_WORLD_NAME && context.auxData && context.auxData.frameId === topFrameId) {
|
|
133
|
+
Runtime.removeEventListener(CONTEXT_CREATED_EVENT, executionContextCreated);
|
|
134
|
+
await Runtime.disable();
|
|
135
|
+
resolve(context.id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
await Page.enable();
|
|
140
|
+
await Page.setLifecycleEventsEnabled({ enabled: true });
|
|
141
|
+
const pageNavigated = Page.navigate({ url: options.url });
|
|
142
|
+
const pageReady = new Promise(resolve => {
|
|
143
|
+
const LIFE_CYCLE_EVENT = "lifecycleEvent";
|
|
144
|
+
let contentLoaded;
|
|
145
|
+
Page.addEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
|
|
146
|
+
|
|
147
|
+
async function onLifecycleEvent({ params }) {
|
|
148
|
+
const { name, frameId } = params;
|
|
149
|
+
if (topFrameId === undefined && frameId !== undefined) {
|
|
150
|
+
topFrameId = frameId;
|
|
151
|
+
}
|
|
152
|
+
if (name === "DOMContentLoaded" && topFrameId !== undefined && frameId === topFrameId) {
|
|
153
|
+
contentLoaded = true;
|
|
154
|
+
}
|
|
155
|
+
if (contentLoaded && name === (options.browserWaitUntil || NETWORK_IDLE_STATE) && frameId === topFrameId) {
|
|
156
|
+
if (options.browserWaitDelay) {
|
|
157
|
+
setTimeout(() => resolve, options.browserWaitDelay);
|
|
158
|
+
} else {
|
|
159
|
+
Page.removeEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
|
|
160
|
+
await Page.setLifecycleEventsEnabled({ enabled: false });
|
|
161
|
+
await Page.disable();
|
|
162
|
+
resolve();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
let timeoutReady, timeoutId, resolveTimeoutReady;
|
|
168
|
+
if (options.browserLoadMaxTime) {
|
|
169
|
+
timeoutReady = new Promise((resolve, reject) => {
|
|
170
|
+
resolveTimeoutReady = resolve;
|
|
171
|
+
timeoutId = setTimeout(() => {
|
|
172
|
+
const error = new Error("Load timeout");
|
|
173
|
+
error.code = LOAD_TIMEOUT_ERROR;
|
|
174
|
+
reject(error);
|
|
175
|
+
}, options.browserLoadMaxTime);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
await Promise.race([Promise.all([pageNavigated, pageReady, debuggerReady]), timeoutReady]);
|
|
179
|
+
if (timeoutId) {
|
|
180
|
+
clearTimeout(timeoutId);
|
|
181
|
+
resolveTimeoutReady();
|
|
182
|
+
}
|
|
183
|
+
const contextId = await executionContextIdPromise;
|
|
184
|
+
const { result } = await Runtime.evaluate({
|
|
185
|
+
expression: `singlefile.getPageData(${JSON.stringify(options)})`,
|
|
186
|
+
awaitPromise: true,
|
|
187
|
+
returnByValue: true,
|
|
188
|
+
contextId
|
|
189
|
+
});
|
|
190
|
+
const { value } = result;
|
|
191
|
+
if (options.compressContent) {
|
|
192
|
+
value.content = new Uint8Array(value.content);
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error.code === LOAD_TIMEOUT_ERROR && options.browserWaitUntilFallback && options.browserWaitUntil) {
|
|
197
|
+
const browserWaitUntil = NETWORK_STATES[(NETWORK_STATES.indexOf(options.browserWaitUntil) + 1)];
|
|
198
|
+
if (browserWaitUntil) {
|
|
199
|
+
options.browserWaitUntil = browserWaitUntil;
|
|
200
|
+
return await getPageData(options);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
throw error;
|
|
204
|
+
} finally {
|
|
205
|
+
if (targetInfo && !options.browserDebug) {
|
|
206
|
+
await CDP.closeTarget(targetInfo.targetId);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getBrowserOptions(options) {
|
|
212
|
+
const browserOptions = {};
|
|
213
|
+
browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
|
|
214
|
+
browserOptions.headless = options.browserHeadless && !options.browserDebug;
|
|
215
|
+
browserOptions.executablePath = options.browserExecutablePath;
|
|
216
|
+
browserOptions.browserDebug = options.browserDebug;
|
|
217
|
+
browserOptions.browserDisableWebSecurity = options.browserDisableWebSecurity === undefined || options.browserDisableWebSecurity;
|
|
218
|
+
browserOptions.browserWidth = options.browserWidth;
|
|
219
|
+
browserOptions.browserHeight = options.browserHeight;
|
|
220
|
+
browserOptions.userAgent = options.userAgent;
|
|
221
|
+
browserOptions.httpProxyServer = options.httpProxyServer;
|
|
222
|
+
return browserOptions;
|
|
223
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2010-2024 Gildas Lormeau
|
|
3
|
+
* contact : gildas.lormeau <at> gmail.com
|
|
4
|
+
*
|
|
5
|
+
* This file is part of SingleFile.
|
|
6
|
+
*
|
|
7
|
+
* The code in this file is free software: you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Affero General Public License
|
|
9
|
+
* (GNU AGPL) as published by the Free Software Foundation, either version 3
|
|
10
|
+
* of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* The code in this file is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
|
15
|
+
* General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* As additional permission under GNU AGPL version 3 section 7, you may
|
|
18
|
+
* distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
|
|
19
|
+
* AGPL normally required by section 4, provided you include this license
|
|
20
|
+
* notice and a URL through which recipients can access the Corresponding
|
|
21
|
+
* Source.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { BROWSER_PATHS, BROWSER_ARGS } from "./chromium-constants.js";
|
|
25
|
+
import { build, makeTempDir, Command, errors, remove } from "../deno-polyfill.js";
|
|
26
|
+
|
|
27
|
+
const PIPED_STD_CONFIG = "piped";
|
|
28
|
+
|
|
29
|
+
let child, profilePath;
|
|
30
|
+
export { launchBrowser, closeBrowser };
|
|
31
|
+
|
|
32
|
+
async function launchBrowser(options = {}, indexPath = 0) {
|
|
33
|
+
let path = BROWSER_PATHS[build.os][indexPath];
|
|
34
|
+
const args = Array.from(BROWSER_ARGS);
|
|
35
|
+
profilePath = await makeTempDir();
|
|
36
|
+
if (options.headless) {
|
|
37
|
+
args.push("--headless");
|
|
38
|
+
} else {
|
|
39
|
+
args.push("--start-maximized");
|
|
40
|
+
}
|
|
41
|
+
if (options.executablePath) {
|
|
42
|
+
path = options.executablePath;
|
|
43
|
+
}
|
|
44
|
+
if (options.browserDebug) {
|
|
45
|
+
args.push("--auto-open-devtools-for-tabs");
|
|
46
|
+
}
|
|
47
|
+
if (options.browserDisableWebSecurity) {
|
|
48
|
+
args.push("--disable-web-security");
|
|
49
|
+
}
|
|
50
|
+
if (options.browserWidth && options.browserHeight) {
|
|
51
|
+
args.push("--window-size=" + options.browserWidth + "," + options.browserHeight);
|
|
52
|
+
}
|
|
53
|
+
if (options.userAgent) {
|
|
54
|
+
args.push("--user-agent=" + options.userAgent);
|
|
55
|
+
}
|
|
56
|
+
if (options.httpProxyServer) {
|
|
57
|
+
args.push("--proxy-server=" + options.httpProxyServer);
|
|
58
|
+
}
|
|
59
|
+
if (options.args) {
|
|
60
|
+
args.push(...options.args);
|
|
61
|
+
}
|
|
62
|
+
args.push(`--user-data-dir=${profilePath}`);
|
|
63
|
+
const command = new Command(path, { args, stdout: PIPED_STD_CONFIG, stderr: PIPED_STD_CONFIG });
|
|
64
|
+
try {
|
|
65
|
+
child = await command.spawn();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error instanceof errors.NotFound) {
|
|
68
|
+
if (indexPath + 1 < BROWSER_PATHS[build.os].length) {
|
|
69
|
+
await launchBrowser(options, indexPath + 1);
|
|
70
|
+
} else {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
child.ref();
|
|
76
|
+
return child;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function closeBrowser() {
|
|
80
|
+
if (child !== undefined) {
|
|
81
|
+
child.kill();
|
|
82
|
+
await child.status;
|
|
83
|
+
child = undefined;
|
|
84
|
+
}
|
|
85
|
+
if (profilePath !== undefined) {
|
|
86
|
+
await remove(profilePath, { recursive: true });
|
|
87
|
+
profilePath = undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2010-2024 Gildas Lormeau
|
|
3
|
+
* contact : gildas.lormeau <at> gmail.com
|
|
4
|
+
*
|
|
5
|
+
* This file is part of SingleFile.
|
|
6
|
+
*
|
|
7
|
+
* The code in this file is free software: you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Affero General Public License
|
|
9
|
+
* (GNU AGPL) as published by the Free Software Foundation, either version 3
|
|
10
|
+
* of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* The code in this file is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
|
15
|
+
* General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* As additional permission under GNU AGPL version 3 section 7, you may
|
|
18
|
+
* distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
|
|
19
|
+
* AGPL normally required by section 4, provided you include this license
|
|
20
|
+
* notice and a URL through which recipients can access the Corresponding
|
|
21
|
+
* Source.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const BROWSER_ARGS = [
|
|
25
|
+
"--disable-field-trial-config",
|
|
26
|
+
"--disable-background-networking",
|
|
27
|
+
"--enable-features=NetworkService,NetworkServiceInProcess",
|
|
28
|
+
"--disable-background-timer-throttling",
|
|
29
|
+
"--disable-backgrounding-occluded-windows",
|
|
30
|
+
"--disable-back-forward-cache",
|
|
31
|
+
"--disable-breakpad",
|
|
32
|
+
"--disable-client-side-phishing-detection",
|
|
33
|
+
"--disable-component-extensions-with-background-pages",
|
|
34
|
+
"--disable-component-update",
|
|
35
|
+
"--no-default-browser-check",
|
|
36
|
+
"--disable-default-apps",
|
|
37
|
+
"--disable-dev-shm-usage",
|
|
38
|
+
"--disable-extensions",
|
|
39
|
+
"--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,HttpsUpgrades,PaintHolding",
|
|
40
|
+
"--allow-pre-commit-input",
|
|
41
|
+
"--disable-hang-monitor",
|
|
42
|
+
"--disable-ipc-flooding-protection",
|
|
43
|
+
"--disable-popup-blocking",
|
|
44
|
+
"--disable-prompt-on-repost",
|
|
45
|
+
"--disable-renderer-backgrounding",
|
|
46
|
+
"--force-color-profile=srgb",
|
|
47
|
+
"--metrics-recording-only",
|
|
48
|
+
"--no-first-run",
|
|
49
|
+
"--enable-automation",
|
|
50
|
+
"--password-store=basic",
|
|
51
|
+
"--use-mock-keychain",
|
|
52
|
+
"--no-service-autorun",
|
|
53
|
+
"--export-tagged-pdf",
|
|
54
|
+
"--disable-search-engine-choice-screen",
|
|
55
|
+
"--enable-use-zoom-for-dsf=false",
|
|
56
|
+
"--no-sandbox",
|
|
57
|
+
"--no-startup-window",
|
|
58
|
+
"--remote-debugging-port=9222",
|
|
59
|
+
"--bwsi"
|
|
60
|
+
];
|
|
61
|
+
const BROWSER_PATHS = {
|
|
62
|
+
linux: [
|
|
63
|
+
"/usr/bin/chromium",
|
|
64
|
+
"/usr/bin/chromium-beta",
|
|
65
|
+
"/usr/bin/chromium-unstable",
|
|
66
|
+
"/usr/bin/chromium-dev",
|
|
67
|
+
"/usr/bin/chromium-browser",
|
|
68
|
+
"/usr/bin/chromium-browser-beta",
|
|
69
|
+
"/usr/bin/chromium-browser-unstable",
|
|
70
|
+
"/usr/bin/chromium-browser-dev",
|
|
71
|
+
"/opt/google/chrome/google-chrome",
|
|
72
|
+
"/opt/google/chrome-beta/google-chrome",
|
|
73
|
+
"/opt/google/chrome-unstable/google-chrome",
|
|
74
|
+
"/opt/google/chrome-dev/google-chrome",
|
|
75
|
+
"/usr/bin/google-chrome",
|
|
76
|
+
"/usr/bin/google-chrome-beta",
|
|
77
|
+
"/usr/bin/google-chrome-unstable",
|
|
78
|
+
"/usr/bin/google-chrome-dev",
|
|
79
|
+
"/usr/bin/brave-browser",
|
|
80
|
+
"/usr/bin/brave-browser-beta",
|
|
81
|
+
"/usr/bin/brave-browser-dev",
|
|
82
|
+
"/usr/bin/brave-browser-nightly",
|
|
83
|
+
"/usr/bin/brave",
|
|
84
|
+
"/usr/bin/brave-beta",
|
|
85
|
+
"/usr/bin/brave-dev",
|
|
86
|
+
"/usr/bin/brave-nightly",
|
|
87
|
+
"/usr/bin/microsoft-edge",
|
|
88
|
+
"/usr/bin/microsoft-edge-beta",
|
|
89
|
+
"/usr/bin/microsoft-edge-dev",
|
|
90
|
+
"/usr/bin/microsoft-edge-insider",
|
|
91
|
+
"/usr/bin/microsoft-edge-beta",
|
|
92
|
+
"/usr/bin/microsoft-edge-dev",
|
|
93
|
+
"/usr/bin/microsoft-edge-canary",
|
|
94
|
+
"/usr/bin/vivaldi",
|
|
95
|
+
"/usr/bin/vivaldi-stable",
|
|
96
|
+
"/usr/bin/vivaldi-snapshot",
|
|
97
|
+
"/usr/bin/vivaldi-beta",
|
|
98
|
+
"/usr/bin/opera",
|
|
99
|
+
"/usr/bin/opera-beta",
|
|
100
|
+
"/usr/bin/opera-developer",
|
|
101
|
+
"/usr/bin/opera-snapshot",
|
|
102
|
+
"/usr/bin/yandex-browser-beta",
|
|
103
|
+
"/usr/bin/yandex-browser-alpha",
|
|
104
|
+
"/usr/bin/yandex-browser",
|
|
105
|
+
"/usr/bin/yandex",
|
|
106
|
+
"/usr/bin/yandex-beta",
|
|
107
|
+
"/usr/bin/yandex-alpha"
|
|
108
|
+
],
|
|
109
|
+
darwin: [
|
|
110
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
111
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
112
|
+
"/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev",
|
|
113
|
+
"/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta",
|
|
114
|
+
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
|
115
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
116
|
+
"/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
|
|
117
|
+
"/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
|
|
118
|
+
"/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary",
|
|
119
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
120
|
+
"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi",
|
|
121
|
+
"/Applications/Opera.app/Contents/MacOS/Opera",
|
|
122
|
+
"/Applications/Yandex.app/Contents/MacOS/Yandex"
|
|
123
|
+
],
|
|
124
|
+
windows: [
|
|
125
|
+
"C:\\Program Files\\Chromium\\Application\\chrome.exe",
|
|
126
|
+
"C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe",
|
|
127
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
128
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
129
|
+
"C:\\Program Files\\Google\\Chrome Dev\\Application\\chrome.exe",
|
|
130
|
+
"C:\\Program Files (x86)\\Google\\Chrome Dev\\Application\\chrome.exe",
|
|
131
|
+
"C:\\Program Files\\Google\\Chrome Beta\\Application\\chrome.exe",
|
|
132
|
+
"C:\\Program Files (x86)\\Google\\Chrome Beta\\Application\\chrome.exe",
|
|
133
|
+
"C:\\Program Files\\Google\\Chrome SxS\\Application\\chrome.exe",
|
|
134
|
+
"C:\\Program Files (x86)\\Google\\Chrome SxS\\Application\\chrome.exe",
|
|
135
|
+
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
136
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
137
|
+
"C:\\Program Files\\Microsoft\\Edge Dev\\Application\\msedge.exe",
|
|
138
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge Dev\\Application\\msedge.exe",
|
|
139
|
+
"C:\\Program Files\\Microsoft\\Edge Beta\\Application\\msedge.exe",
|
|
140
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge Beta\\Application\\msedge.exe",
|
|
141
|
+
"C:\\Program Files\\Microsoft\\Edge SxS\\Application\\msedge.exe",
|
|
142
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge SxS\\Application\\msedge.exe",
|
|
143
|
+
"C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
|
|
144
|
+
"C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
|
|
145
|
+
"C:\\Program Files\\Vivaldi\\Application\\vivaldi.exe",
|
|
146
|
+
"C:\\Program Files (x86)\\Vivaldi\\Application\\vivaldi.exe",
|
|
147
|
+
"C:\\Program Files\\Opera\\launcher.exe",
|
|
148
|
+
"C:\\Program Files (x86)\\Opera\\launcher.exe",
|
|
149
|
+
"C:\\Program Files\\Yandex\\YandexBrowser\\Application\\browser.exe",
|
|
150
|
+
"C:\\Program Files (x86)\\Yandex\\YandexBrowser\\Application\\browser.exe"
|
|
151
|
+
]
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
BROWSER_ARGS,
|
|
156
|
+
BROWSER_PATHS
|
|
157
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2010-
|
|
2
|
+
* Copyright 2010-2024 Gildas Lormeau
|
|
3
3
|
* contact : gildas.lormeau <at> gmail.com
|
|
4
4
|
*
|
|
5
5
|
* This file is part of SingleFile.
|
|
@@ -21,18 +21,12 @@
|
|
|
21
21
|
* Source.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
/* global
|
|
24
|
+
/* global singlefile, XMLHttpRequest */
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
import { script, hookScript, zipScript } from "../lib/single-file-bundle.js";
|
|
27
|
+
import { readTextFile } from "../deno-polyfill.js";
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
"lib/single-file.js",
|
|
30
|
-
"lib/single-file-bootstrap.js",
|
|
31
|
-
"lib/single-file-hooks-frames.js",
|
|
32
|
-
"lib/single-file-zip.min.js"
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
const basePath = "./../../";
|
|
29
|
+
export { getScriptSource, getHookScriptSource, getZipScriptSource };
|
|
36
30
|
|
|
37
31
|
function initSingleFile() {
|
|
38
32
|
singlefile.init({
|
|
@@ -64,47 +58,25 @@ function initSingleFile() {
|
|
|
64
58
|
});
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Object.freeze(String.prototype);
|
|
72
|
-
Object.freeze(Number.prototype);
|
|
73
|
-
Object.freeze(Boolean.prototype);
|
|
74
|
-
Object.freeze(Date.prototype);
|
|
75
|
-
Object.freeze(RegExp.prototype);
|
|
76
|
-
Object.freeze(Math.prototype);
|
|
77
|
-
Object.freeze(Error.prototype);
|
|
78
|
-
Object.freeze(JSON.prototype);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
exports.get = async options => {
|
|
82
|
-
let scripts = "let _singleFileDefine; if (typeof define !== 'undefined') { _singleFileDefine = define; define = null }";
|
|
83
|
-
scripts += await readScriptFiles(SCRIPTS, basePath);
|
|
84
|
-
scripts += await readScriptFiles(options && options.browserScripts ? options.browserScripts : [], "");
|
|
61
|
+
async function getScriptSource(options) {
|
|
62
|
+
let source = "";
|
|
63
|
+
source += script;
|
|
64
|
+
source += await readScriptFiles(options && options.browserScripts ? options.browserScripts : []);
|
|
85
65
|
if (options.browserStylesheets && options.browserStylesheets.length) {
|
|
86
|
-
|
|
66
|
+
source += "addEventListener(\"load\",()=>{const styleElement=document.createElement(\"style\");styleElement.textContent=" + JSON.stringify(await readScriptFiles(options.browserStylesheets)) + ";document.body.appendChild(styleElement);});";
|
|
87
67
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
scripts += "if (_singleFileDefine) { define = _singleFileDefine; _singleFileDefine = null }";
|
|
92
|
-
scripts += "(" + initSingleFile.toString() + ")();";
|
|
93
|
-
return scripts;
|
|
94
|
-
};
|
|
68
|
+
source += "(" + initSingleFile.toString() + ")();";
|
|
69
|
+
return source;
|
|
70
|
+
}
|
|
95
71
|
|
|
96
|
-
async function
|
|
97
|
-
return
|
|
72
|
+
async function getHookScriptSource() {
|
|
73
|
+
return hookScript;
|
|
98
74
|
}
|
|
99
75
|
|
|
100
|
-
function
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
resolve(data.toString() + "\n");
|
|
107
|
-
}
|
|
108
|
-
})
|
|
109
|
-
);
|
|
76
|
+
async function getZipScriptSource() {
|
|
77
|
+
return zipScript;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function readScriptFiles(paths) {
|
|
81
|
+
return (await Promise.all(paths.map(path => readTextFile(path)))).join("");
|
|
110
82
|
}
|
package/build-lib-dev.sh
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
mkdir -p node_modules/single-file-core
|
|
4
|
+
cp -R ../single-file-core/* node_modules/single-file-core
|
|
5
|
+
|
|
6
|
+
echo "
|
|
7
|
+
import { build } from 'npm:esbuild';
|
|
8
|
+
|
|
9
|
+
await build({
|
|
10
|
+
entryPoints: [
|
|
11
|
+
'node_modules/single-file-core/single-file.js'
|
|
12
|
+
],
|
|
13
|
+
bundle: true,
|
|
14
|
+
globalName: 'singlefile',
|
|
15
|
+
outdir: 'lib/',
|
|
16
|
+
platform: 'browser',
|
|
17
|
+
sourcemap: false,
|
|
18
|
+
minify: false,
|
|
19
|
+
format: 'iife',
|
|
20
|
+
plugins: [],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
await build({
|
|
24
|
+
entryPoints: [
|
|
25
|
+
'node_modules/single-file-core/single-file-bootstrap.js'
|
|
26
|
+
],
|
|
27
|
+
bundle: true,
|
|
28
|
+
globalName: 'singlefileBootstrap',
|
|
29
|
+
outdir: 'lib/',
|
|
30
|
+
platform: 'browser',
|
|
31
|
+
sourcemap: false,
|
|
32
|
+
minify: false,
|
|
33
|
+
format: 'iife',
|
|
34
|
+
plugins: [],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await build({
|
|
38
|
+
entryPoints: [
|
|
39
|
+
'node_modules/single-file-core/single-file-hooks-frames.js'
|
|
40
|
+
],
|
|
41
|
+
bundle: true,
|
|
42
|
+
outdir: 'lib/',
|
|
43
|
+
platform: 'browser',
|
|
44
|
+
sourcemap: false,
|
|
45
|
+
minify: false,
|
|
46
|
+
format: 'iife',
|
|
47
|
+
plugins: [],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await build({
|
|
51
|
+
entryPoints: [
|
|
52
|
+
'node_modules/single-file-core/vendor/zip/zip.min.js'
|
|
53
|
+
],
|
|
54
|
+
bundle: true,
|
|
55
|
+
globalName: 'zip',
|
|
56
|
+
outdir: 'lib/',
|
|
57
|
+
platform: 'browser',
|
|
58
|
+
sourcemap: false,
|
|
59
|
+
minify: false,
|
|
60
|
+
format: 'iife',
|
|
61
|
+
plugins: [],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const SCRIPTS = [
|
|
65
|
+
'lib/single-file.js',
|
|
66
|
+
'lib/single-file-bootstrap.js',
|
|
67
|
+
'lib/zip.min.js'
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
let script = '';
|
|
71
|
+
const scripts = SCRIPTS.map(script => Deno.readTextFile(script));
|
|
72
|
+
const sources = await Promise.all(scripts);
|
|
73
|
+
script += 'const script = ' + JSON.stringify(sources.join(';')) + ';';
|
|
74
|
+
const hookScript = await Deno.readTextFile('lib/single-file-hooks-frames.js');
|
|
75
|
+
script += 'const hookScript = ' + JSON.stringify(hookScript) + ';';
|
|
76
|
+
const zipScript = await Deno.readTextFile('lib/zip.min.js');
|
|
77
|
+
script += 'const zipScript = ' + JSON.stringify(zipScript) + ';';
|
|
78
|
+
script += 'export { script, zipScript, hookScript };';
|
|
79
|
+
await Deno.writeTextFile('lib/single-file-bundle.js', script)
|
|
80
|
+
await Promise.all(SCRIPTS.map(script => Deno.remove(script)));
|
|
81
|
+
await Deno.remove('lib/single-file-hooks-frames.js');
|
|
82
|
+
" | deno run --allow-read --allow-write --allow-net --allow-run --allow-env --lock=node_modules/deno.lock.tmp -
|
|
83
|
+
|
|
84
|
+
rm -rf node_modules
|