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.
Files changed (43) hide show
  1. package/{.eslintrc.js → .eslintrc.json} +5 -6
  2. package/Dockerfile +2 -1
  3. package/README.MD +56 -60
  4. package/args.js +252 -334
  5. package/back-ends/chromium-back-end.js +223 -0
  6. package/back-ends/chromium-browser.js +89 -0
  7. package/back-ends/chromium-constants.js +157 -0
  8. package/back-ends/{common/scripts.js → single-file-script.js} +21 -49
  9. package/build-lib-dev.sh +84 -0
  10. package/build-lib.sh +80 -3
  11. package/compile.sh +13 -0
  12. package/deno-polyfill.js +223 -0
  13. package/deno.json +13 -0
  14. package/deno.lock +49 -0
  15. package/lib/single-file-bundle.js +1 -0
  16. package/package.json +9 -33
  17. package/single-file +39 -14
  18. package/single-file-cli-api.js +32 -44
  19. package/back-ends/extensions/bypass-csp/index.js +0 -36
  20. package/back-ends/extensions/bypass-csp/manifest.json +0 -20
  21. package/back-ends/extensions/disable-web-security/index.js +0 -54
  22. package/back-ends/extensions/disable-web-security/manifest.json +0 -20
  23. package/back-ends/extensions/network-idle/bg.js +0 -61
  24. package/back-ends/extensions/network-idle/content.js +0 -29
  25. package/back-ends/extensions/network-idle/manifest.json +0 -31
  26. package/back-ends/extensions/signed/bypass_csp-0.0.3-an+fx.xpi +0 -0
  27. package/back-ends/extensions/signed/disable_web_security-0.0.3-an+fx.xpi +0 -0
  28. package/back-ends/extensions/signed/network_idle-0.0.2-an+fx.xpi +0 -0
  29. package/back-ends/jsdom.js +0 -159
  30. package/back-ends/playwright-chromium.js +0 -126
  31. package/back-ends/playwright-firefox.js +0 -115
  32. package/back-ends/playwright-webkit.js +0 -126
  33. package/back-ends/puppeteer-firefox.js +0 -172
  34. package/back-ends/puppeteer.js +0 -201
  35. package/back-ends/webdriver-chromium.js +0 -172
  36. package/back-ends/webdriver-gecko.js +0 -190
  37. package/lib/single-file-bootstrap.js +0 -1
  38. package/lib/single-file-frames.js +0 -1
  39. package/lib/single-file-hooks-frames.js +0 -1
  40. package/lib/single-file-zip.min.js +0 -1
  41. package/lib/single-file.js +0 -1
  42. package/rollup.config.dev.js +0 -57
  43. package/rollup.config.js +0 -58
@@ -1,159 +0,0 @@
1
- /*
2
- * Copyright 2010-2020 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 require, exports, Buffer, setTimeout */
25
-
26
- const crypto = require("crypto");
27
-
28
- const jsdom = require("jsdom");
29
- const { JSDOM, VirtualConsole } = jsdom;
30
- const iconv = require("iconv-lite");
31
-
32
- exports.initialize = async () => { };
33
-
34
- exports.getPageData = async options => {
35
- let win;
36
- try {
37
- const dom = await JSDOM.fromURL(options.url, await getBrowserOptions(options));
38
- win = dom.window;
39
- return await getPageData(win, options);
40
- } finally {
41
- if (win) {
42
- win.close();
43
- }
44
- }
45
- };
46
-
47
- exports.closeBrowser = () => { };
48
-
49
- async function getPageData(win, options) {
50
- const doc = win.document;
51
- const scripts = await require("./common/scripts.js").get(options);
52
- win.TextDecoder = class {
53
- constructor(utfLabel) {
54
- this.utfLabel = utfLabel;
55
- }
56
- decode(buffer) {
57
- return iconv.decode(Buffer.from(buffer), this.utfLabel);
58
- }
59
- };
60
- win.TextEncoder = class {
61
- encode(value) {
62
- return iconv.encode(value, "utf-8");
63
- }
64
- };
65
- win.crypto = {
66
- subtle: {
67
- digest: async function digestText(algo, text) {
68
- const hash = crypto.createHash(algo.replace("-", "").toLowerCase());
69
- hash.update(text, "utf-8");
70
- return hash.digest();
71
- }
72
- }
73
- };
74
- win.Element.prototype.getBoundingClientRect = undefined;
75
- win.getComputedStyle = () => { };
76
- win.eval(scripts);
77
- if (win.document.readyState == "loading" || win.document.readyState == "interactive") {
78
- await new Promise(resolve => win.onload = resolve);
79
- }
80
- executeFrameScripts(doc, scripts);
81
- options.removeHiddenElements = false;
82
- options.loadDeferredImages = false;
83
- if (options.browserWaitDelay) {
84
- await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
85
- }
86
- const pageData = await win.singlefile.getPageData(options, undefined, doc, win);
87
- if (options.compressContent) {
88
- pageData.content = new Uint8Array(pageData.content);
89
- }
90
- return pageData;
91
- }
92
-
93
- async function getBrowserOptions(options) {
94
- class ResourceLoader extends jsdom.ResourceLoader {
95
- _getRequestOptions(fetchOptions) {
96
- const requestOptions = super._getRequestOptions(fetchOptions);
97
- if (options.httpHeaders) {
98
- requestOptions.headers = Object.assign(requestOptions.headers, options.httpHeaders);
99
- }
100
- return requestOptions;
101
- }
102
- }
103
- const resourceLoader = new ResourceLoader({
104
- userAgent: options.userAgent,
105
- strictSSL: options.browserIgnoreInsecureCerts === undefined || !options.browserIgnoreInsecureCerts
106
- });
107
- const jsdomOptions = {
108
- virtualConsole: new VirtualConsole(),
109
- userAgent: options.userAgent,
110
- pretendToBeVisual: true,
111
- runScripts: "outside-only",
112
- resources: resourceLoader
113
- };
114
- if (options.browserWidth && options.browserHeight) {
115
- jsdomOptions.beforeParse = function (window) {
116
- window.outerWidth = window.innerWidth = options.browserWidth;
117
- window.outerHeight = window.innerHeight = options.browserHeight;
118
- };
119
- }
120
- if (options.browserCookies && options.browserCookies.length) {
121
- jsdomOptions.cookieJar = new jsdom.CookieJar();
122
- await Promise.all(options.browserCookies.map(cookie => {
123
- let cookieString = cookie.name + "=" + cookie.value;
124
- if (cookie.path) {
125
- cookieString += ";path=" + cookie.path;
126
- }
127
- if (cookie.domain) {
128
- cookieString += ";domain=" + cookie.domain;
129
- }
130
- if (cookie.expires) {
131
- cookieString += ";max-age=" + cookie.expires;
132
- }
133
- if (cookie.secure) {
134
- cookieString += ";secure";
135
- }
136
- if (cookie.sameSite) {
137
- cookieString += ";samesite=" + options.sameSite;
138
- }
139
- const cookieOptions = {
140
- http: Boolean(cookie.httpOnly)
141
- };
142
- return new Promise((resolve, reject) => jsdomOptions.cookieJar.setCookie(cookieString, options.url, cookieOptions, error => error ? reject(error) : resolve()));
143
- }));
144
- }
145
- return jsdomOptions;
146
- }
147
-
148
- function executeFrameScripts(doc, scripts) {
149
- const frameElements = doc.querySelectorAll("iframe, frame");
150
- frameElements.forEach(frameElement => {
151
- try {
152
- frameElement.contentWindow.Element.prototype.getBoundingClientRect = undefined;
153
- frameElement.contentWindow.eval(scripts);
154
- executeFrameScripts(frameElement.contentDocument, scripts);
155
- } catch (error) {
156
- // ignored
157
- }
158
- });
159
- }
@@ -1,126 +0,0 @@
1
- /*
2
- * Copyright 2010-2020 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 singlefile, require, exports */
25
-
26
- const playwright = require("playwright").chromium;
27
- const scripts = require("./common/scripts.js");
28
-
29
- const NETWORK_IDLE_STATE = "networkidle";
30
-
31
- let browser;
32
-
33
- exports.initialize = async options => {
34
- browser = await playwright.launch(getBrowserOptions(options));
35
- };
36
-
37
- exports.getPageData = async options => {
38
- let page, context;
39
- try {
40
- const contextOptions = {
41
- bypassCSP: options.browserBypassCSP === undefined || options.browserBypassCSP,
42
- ignoreHTTPSErrors: options.browserIgnoreInsecureCerts !== undefined && options.browserIgnoreInsecureCerts
43
- };
44
- if (options.httpProxyServer) {
45
- contextOptions.proxy = {
46
- server: options.httpProxyServer
47
- };
48
- if (options.httpProxyUsername) {
49
- contextOptions.proxy.username = options.httpProxyUsername;
50
- }
51
- if (options.httpProxyPassword) {
52
- contextOptions.proxy.password = options.httpProxyPassword;
53
- }
54
- }
55
- context = await browser.newContext(contextOptions);
56
- await setContextOptions(context, options);
57
- page = await context.newPage();
58
- await setPageOptions(page, options);
59
- return await getPageData(page, options);
60
- } finally {
61
- if (page && !options.browserDebug) {
62
- await page.close();
63
- }
64
- }
65
- };
66
-
67
- exports.closeBrowser = () => {
68
- if (browser) {
69
- return browser.close();
70
- }
71
- };
72
-
73
- function getBrowserOptions(options) {
74
- const browserOptions = {};
75
- if (options.browserHeadless !== undefined) {
76
- browserOptions.headless = options.browserHeadless && !options.browserDebug;
77
- }
78
- browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
79
- if (options.browserExecutablePath) {
80
- browserOptions.executablePath = options.browserExecutablePath || "chrome";
81
- }
82
- return browserOptions;
83
- }
84
-
85
- async function setContextOptions(context, options) {
86
- if (options.browserCookies && options.browserCookies.length) {
87
- await context.addCookies(options.browserCookies);
88
- }
89
- }
90
-
91
- async function setPageOptions(page, options) {
92
- if (options.browserWidth && options.browserHeight) {
93
- await page.setViewportSize({
94
- width: options.browserWidth,
95
- height: options.browserHeight
96
- });
97
- }
98
- if (options.httpHeaders) {
99
- page.setExtraHTTPHeaders(options.httpHeaders);
100
- }
101
- if (options.emulateMediaFeatures) {
102
- await page.emulateMedia({
103
- features: options.emulateMediaFeatures
104
- });
105
- }
106
- }
107
-
108
- async function getPageData(page, options) {
109
- const injectedScript = await scripts.get(options);
110
- await page.addInitScript(injectedScript);
111
- if (options.browserDebug) {
112
- await page.waitForTimeout(3000);
113
- }
114
- await page.goto(options.url, {
115
- timeout: options.browserLoadMaxTime || 0,
116
- waitUntil: options.browserWaitUntil && options.browserWaitUntil.startsWith("networkidle") ? NETWORK_IDLE_STATE : options.browserWaitUntil || NETWORK_IDLE_STATE
117
- });
118
- if (options.browserWaitDelay) {
119
- await page.waitForTimeout(options.browserWaitDelay);
120
- }
121
- const pageData = await page.evaluate(async options => await singlefile.getPageData(options), options);
122
- if (options.compressContent) {
123
- pageData.content = new Uint8Array(pageData.content);
124
- }
125
- return pageData;
126
- }
@@ -1,115 +0,0 @@
1
- /*
2
- * Copyright 2010-2020 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 singlefile, require, exports */
25
-
26
- const playwright = require("playwright").firefox;
27
- const scripts = require("./common/scripts.js");
28
-
29
- const NETWORK_IDLE_STATE = "networkidle";
30
-
31
- let browser;
32
-
33
- exports.initialize = async options => {
34
- browser = await playwright.launch(getBrowserOptions(options));
35
- };
36
-
37
- exports.getPageData = async options => {
38
- let page, context;
39
- try {
40
- context = await browser.newContext({
41
- bypassCSP: options.browserBypassCSP === undefined || options.browserBypassCSP,
42
- ignoreHTTPSErrors: options.browserIgnoreInsecureCerts !== undefined && options.browserIgnoreInsecureCerts
43
- });
44
- await setContextOptions(context, options);
45
- page = await context.newPage();
46
- await setPageOptions(page, options);
47
- return await getPageData(page, options);
48
- } finally {
49
- if (page && !options.browserDebug) {
50
- await page.close();
51
- }
52
- }
53
- };
54
-
55
- exports.closeBrowser = () => {
56
- if (browser) {
57
- return browser.close();
58
- }
59
- };
60
-
61
- function getBrowserOptions(options) {
62
- const browserOptions = {};
63
- if (options.browserHeadless !== undefined) {
64
- browserOptions.headless = options.browserHeadless && !options.browserDebug;
65
- }
66
- browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
67
- if (options.browserExecutablePath) {
68
- browserOptions.executablePath = options.browserExecutablePath || "firefox";
69
- }
70
- return browserOptions;
71
- }
72
-
73
- async function setContextOptions(context, options) {
74
- if (options.browserCookies && options.browserCookies.length) {
75
- await context.addCookies(options.browserCookies);
76
- }
77
- }
78
-
79
- async function setPageOptions(page, options) {
80
- if (options.browserWidth && options.browserHeight) {
81
- await page.setViewportSize({
82
- width: options.browserWidth,
83
- height: options.browserHeight
84
- });
85
- }
86
- if (options.httpHeaders) {
87
- page.setExtraHTTPHeaders(options.httpHeaders);
88
- }
89
- if (options.emulateMediaFeatures) {
90
- await page.emulateMedia({
91
- features: options.emulateMediaFeatures
92
- });
93
- }
94
- options.browserWaitUntil = "load";
95
- }
96
-
97
- async function getPageData(page, options) {
98
- const injectedScript = await scripts.get(options);
99
- await page.addInitScript(injectedScript);
100
- if (options.browserDebug) {
101
- await page.waitForTimeout(3000);
102
- }
103
- await page.goto(options.url, {
104
- timeout: options.browserLoadMaxTime || 0,
105
- waitUntil: options.browserWaitUntil && options.browserWaitUntil.startsWith("networkidle") ? NETWORK_IDLE_STATE : options.browserWaitUntil || NETWORK_IDLE_STATE
106
- });
107
- if (options.browserWaitDelay) {
108
- await page.waitForTimeout(options.browserWaitDelay);
109
- }
110
- const pageData = await page.evaluate(async options => await singlefile.getPageData(options), options);
111
- if (options.compressContent) {
112
- pageData.content = new Uint8Array(pageData.content);
113
- }
114
- return pageData;
115
- }
@@ -1,126 +0,0 @@
1
- /*
2
- * Copyright 2010-2020 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 singlefile, require, exports */
25
-
26
- const playwright = require("playwright").webkit;
27
- const scripts = require("./common/scripts.js");
28
-
29
- const NETWORK_IDLE_STATE = "networkidle";
30
-
31
- let browser;
32
-
33
- exports.initialize = async options => {
34
- browser = await playwright.launch(getBrowserOptions(options));
35
- };
36
-
37
- exports.getPageData = async options => {
38
- let page, context;
39
- try {
40
- const contextOptions = {
41
- bypassCSP: options.browserBypassCSP === undefined || options.browserBypassCSP,
42
- ignoreHTTPSErrors: options.browserIgnoreInsecureCerts !== undefined && options.browserIgnoreInsecureCerts
43
- };
44
- if (options.httpProxyServer) {
45
- contextOptions.proxy = {
46
- server: options.httpProxyServer
47
- };
48
- if (options.httpProxyUsername) {
49
- contextOptions.proxy.username = options.httpProxyUsername;
50
- }
51
- if (options.httpProxyPassword) {
52
- contextOptions.proxy.password = options.httpProxyPassword;
53
- }
54
- }
55
- context = await browser.newContext(contextOptions);
56
- await setContextOptions(context, options);
57
- page = await context.newPage();
58
- await setPageOptions(page, options);
59
- return await getPageData(page, options);
60
- } finally {
61
- if (page && !options.browserDebug) {
62
- await page.close();
63
- }
64
- }
65
- };
66
-
67
- exports.closeBrowser = () => {
68
- if (browser) {
69
- return browser.close();
70
- }
71
- };
72
-
73
- function getBrowserOptions(options) {
74
- const browserOptions = {};
75
- if (options.browserHeadless !== undefined) {
76
- browserOptions.headless = options.browserHeadless && !options.browserDebug;
77
- }
78
- browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
79
- if (options.browserExecutablePath) {
80
- browserOptions.executablePath = options.browserExecutablePath || "safari";
81
- }
82
- return browserOptions;
83
- }
84
-
85
- async function setContextOptions(context, options) {
86
- if (options.browserCookies && options.browserCookies.length) {
87
- await context.addCookies(options.browserCookies);
88
- }
89
- }
90
-
91
- async function setPageOptions(page, options) {
92
- if (options.browserWidth && options.browserHeight) {
93
- await page.setViewportSize({
94
- width: options.browserWidth,
95
- height: options.browserHeight
96
- });
97
- }
98
- if (options.httpHeaders) {
99
- page.setExtraHTTPHeaders(options.httpHeaders);
100
- }
101
- if (options.emulateMediaFeatures) {
102
- await page.emulateMedia({
103
- features: options.emulateMediaFeatures
104
- });
105
- }
106
- }
107
-
108
- async function getPageData(page, options) {
109
- const injectedScript = await scripts.get(options);
110
- await page.addInitScript(injectedScript);
111
- if (options.browserDebug) {
112
- await page.waitForTimeout(3000);
113
- }
114
- await page.goto(options.url, {
115
- timeout: options.browserLoadMaxTime || 0,
116
- waitUntil: options.browserWaitUntil && options.browserWaitUntil.startsWith("networkidle") ? NETWORK_IDLE_STATE : options.browserWaitUntil || NETWORK_IDLE_STATE
117
- });
118
- if (options.browserWaitDelay) {
119
- await page.waitForTimeout(options.browserWaitDelay);
120
- }
121
- const pageData = await page.evaluate(async options => await singlefile.getPageData(options), options);
122
- if (options.compressContent) {
123
- pageData.content = new Uint8Array(pageData.content);
124
- }
125
- return pageData;
126
- }
@@ -1,172 +0,0 @@
1
- /*
2
- * Copyright 2010-2020 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 singlefile, require, exports, setTimeout */
25
-
26
- const puppeteer = require("puppeteer-core");
27
- const scripts = require("./common/scripts.js");
28
-
29
- const EXECUTION_CONTEXT_DESTROYED_ERROR = "Execution context was destroyed";
30
- const NETWORK_IDLE_STATE = "networkidle0";
31
-
32
- let browser;
33
-
34
- exports.initialize = async options => {
35
- browser = await puppeteer.launch(getBrowserOptions(options));
36
- };
37
-
38
- exports.getPageData = async options => {
39
- let page;
40
- try {
41
- page = await browser.newPage();
42
- await setPageOptions(page, options);
43
- return await getPageData(browser, page, options);
44
- } finally {
45
- if (page && !options.browserDebug) {
46
- await page.close();
47
- }
48
- }
49
- };
50
-
51
- exports.closeBrowser = () => {
52
- if (browser) {
53
- return browser.close();
54
- }
55
- };
56
-
57
- function getBrowserOptions(options) {
58
- const browserOptions = {};
59
- if (options.browserHeadless !== undefined) {
60
- browserOptions.headless = options.browserHeadless && !options.browserDebug;
61
- }
62
- browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
63
- if (options.browserExecutablePath) {
64
- browserOptions.executablePath = options.browserExecutablePath || "firefox";
65
- }
66
- if (options.browserIgnoreInsecureCerts !== undefined) {
67
- browserOptions.ignoreHTTPSErrors = options.browserIgnoreInsecureCerts;
68
- }
69
- browserOptions.product = "firefox";
70
- return browserOptions;
71
- }
72
-
73
- async function setPageOptions(page, options) {
74
- if (options.browserWidth && options.browserHeight) {
75
- await page.setViewport({
76
- width: options.browserWidth,
77
- height: options.browserHeight
78
- });
79
- }
80
- if ((options.browserBypassCSP === undefined || options.browserBypassCSP) && page.setBypassCSP) {
81
- try {
82
- await page.setBypassCSP(true);
83
- } catch (error) {
84
- // ignored
85
- }
86
- }
87
- if (options.httpHeaders) {
88
- try {
89
- await page.setExtraHTTPHeaders(options.httpHeaders);
90
- } catch (error) {
91
- // ignored
92
- }
93
- }
94
- if (options.browserCookies && options.browserCookies.length) {
95
- await page.setCookie(...options.browserCookies);
96
- }
97
- if (options.emulateMediaFeatures) {
98
- try {
99
- await page.emulateMediaFeatures(options.emulateMediaFeatures);
100
- } catch (error) {
101
- // ignored
102
- }
103
- }
104
- options.browserWaitUntil = "load";
105
- }
106
-
107
- async function getPageData(browser, page, options) {
108
- const injectedScript = await scripts.get(options);
109
- await page.evaluateOnNewDocument(injectedScript);
110
- if (options.browserDebug) {
111
- await new Promise(resolve => setTimeout(resolve, 3000));
112
- }
113
- await pageGoto(page, options);
114
- try {
115
- await page.evaluate(injectedScript);
116
- if (options.browserWaitDelay) {
117
- await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
118
- }
119
- const pageData = await page.evaluate(async options => await singlefile.getPageData(options), options);
120
- if (options.compressContent) {
121
- pageData.content = new Uint8Array(pageData.content);
122
- }
123
- return pageData;
124
- } catch (error) {
125
- if (error.message && error.message.includes(EXECUTION_CONTEXT_DESTROYED_ERROR)) {
126
- const pageData = await handleJSRedirect(browser, options);
127
- if (pageData) {
128
- return pageData;
129
- } else {
130
- throw error;
131
- }
132
- } else if (error.name != "TimeoutError") {
133
- throw error;
134
- }
135
- }
136
- }
137
-
138
- async function handleJSRedirect(browser, options) {
139
- const pages = await browser.pages();
140
- const page = pages[1] || pages[0];
141
- try {
142
- await pageGoto(page, options);
143
- } catch (error) {
144
- if (error.name != "TimeoutError") {
145
- throw error;
146
- }
147
- }
148
- const url = page.url();
149
- if (url != options.url) {
150
- options.url = url;
151
- await browser.close();
152
- return exports.getPageData(options);
153
- }
154
- }
155
-
156
- async function pageGoto(page, options) {
157
- try {
158
- await page.goto(options.url, {
159
- timeout: options.browserLoadMaxTime || 0,
160
- waitUntil: options.browserWaitUntil || NETWORK_IDLE_STATE
161
- });
162
- } catch (error) {
163
- if (error.message.includes("Unknown waitUntil condition")) {
164
- await page.goto(options.url, {
165
- timeout: options.browserLoadMaxTime || 0,
166
- waitUntil: "load"
167
- });
168
- } else {
169
- throw error;
170
- }
171
- }
172
- }