single-file-webdriver.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright 2010-2019 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. /* global require, exports */
  24. const fs = require("fs");
  25. const chrome = require("selenium-webdriver/chrome");
  26. const { Builder } = require("selenium-webdriver");
  27. const SCRIPTS = [
  28. "../lib/frame-tree/frame-tree.js",
  29. "../lib/single-file/util/doc-util.js",
  30. "../lib/single-file/util/doc-helper.js",
  31. "../lib/single-file/util/timeout.js",
  32. "../lib/single-file/vendor/css-tree.js",
  33. "../lib/single-file/vendor/html-srcset-parser.js",
  34. "../lib/single-file/vendor/css-minifier.js",
  35. "../lib/single-file/vendor/css-font-property-parser.js",
  36. "../lib/single-file/vendor/css-media-query-parser.js",
  37. "../lib/single-file/modules/html-minifier.js",
  38. "../lib/single-file/modules/css-fonts-minifier.js",
  39. "../lib/single-file/modules/css-fonts-alt-minifier.js",
  40. "../lib/single-file/modules/css-matched-rules.js",
  41. "../lib/single-file/modules/css-medias-alt-minifier.js",
  42. "../lib/single-file/modules/css-rules-minifier.js",
  43. "../lib/single-file/modules/html-images-alt-minifier.js",
  44. "../lib/single-file/modules/html-serializer.js",
  45. "../lib/single-file/single-file-core.js",
  46. "../lib/single-file/single-file-browser.js"
  47. ];
  48. exports.getPageData = async options => {
  49. let driver;
  50. try {
  51. const builder = new Builder();
  52. const chromeOptions = new chrome.Options();
  53. if (options.browserHeadless === undefined || options.browserHeadless) {
  54. chromeOptions.headless();
  55. }
  56. if (options.browserDisableWebSecurity === undefined || options.browserDisableWebSecurity) {
  57. chromeOptions.addArguments("--disable-web-security");
  58. }
  59. if (options.userAgent) {
  60. await chromeOptions.addArguments("--user-agent=" + JSON.stringify(options.userAgent));
  61. }
  62. builder.setChromeOptions(chromeOptions);
  63. driver = await builder.forBrowser("chrome").build();
  64. await driver.get(options.url);
  65. let scripts = (await Promise.all(SCRIPTS.map(scriptPath => fs.readFileSync(require.resolve(scriptPath)).toString()))).join("\n");
  66. if (options.loadDeferredImages) {
  67. scripts += "\ntry {\n" + fs.readFileSync(require.resolve("../lib/lazy/web/web-lazy-loader-before")) + "\n} catch (error) {}";
  68. }
  69. const mainWindowHandle = driver.getWindowHandle();
  70. const windowHandles = await driver.getAllWindowHandles();
  71. await Promise.all(windowHandles.map(async windowHandle => {
  72. await driver.switchTo().window(windowHandle);
  73. driver.executeScript(scripts);
  74. }));
  75. await driver.switchTo().window(mainWindowHandle);
  76. if (options.loadDeferredImages) {
  77. await driver.sleep(options.loadDeferredImagesMaxIdleTime || 1500);
  78. }
  79. return await driver.executeAsyncScript(getPageDataScript(), options);
  80. } finally {
  81. if (driver) {
  82. driver.quit();
  83. }
  84. }
  85. };
  86. function getPageDataScript() {
  87. return `
  88. const [options, callback] = arguments;
  89. getPageData().then(pageData => callback(pageData))
  90. async function getPageData() {
  91. options.insertSingleFileComment = true;
  92. options.insertFaviconLink = true;
  93. if (!options.saveRawPage && !options.removeFrames) {
  94. options.framesData = await frameTree.getAsync(options);
  95. }
  96. options.doc = document;
  97. options.win = window;
  98. const SingleFile = SingleFileBrowser.getClass();
  99. const singleFile = new SingleFile(options);
  100. await singleFile.initialize();
  101. await singleFile.run();
  102. return await singleFile.getPageData();
  103. }
  104. `;
  105. }