lib/grover.rb in grover-0.11.4 vs lib/grover.rb in grover-0.12.1
- old
+ new
@@ -3,148 +3,24 @@
require 'grover/version'
require 'grover/utils'
require 'active_support_ext/object/deep_dup' unless defined?(ActiveSupport)
+require 'grover/errors'
require 'grover/html_preprocessor'
require 'grover/middleware'
require 'grover/configuration'
require 'grover/options_builder'
+require 'grover/processor'
require 'nokogiri'
-require 'schmooze'
require 'yaml'
#
# Grover interface for converting HTML to PDF
#
class Grover
- #
- # Processor helper class for calling out to Puppeteer NodeJS library
- #
- class Processor < Schmooze::Base
- dependencies puppeteer: 'puppeteer'
-
- def self.launch_params
- ENV['GROVER_NO_SANDBOX'] == 'true' ? "{args: ['--no-sandbox', '--disable-setuid-sandbox']}" : '{args: []}'
- end
-
- def self.convert_function(convert_action)
- <<~FUNCTION
- async (url_or_html, options) => {
- let browser;
- try {
- let launchParams = #{launch_params};
-
- // Configure puppeteer debugging options
- const debug = options.debug; delete options.debug;
- if (typeof debug === 'object' && !!debug) {
- if (debug.headless != undefined) { launchParams.headless = debug.headless; }
- if (debug.devtools != undefined) { launchParams.devtools = debug.devtools; }
- }
-
- // Configure additional launch arguments
- const args = options.launchArgs; delete options.launchArgs;
- if (Array.isArray(args)) {
- launchParams.args = launchParams.args.concat(args);
- }
-
- // Set executable path if given
- const executablePath = options.executablePath; delete options.executablePath;
- if (executablePath) {
- launchParams.executablePath = executablePath;
- }
-
- // Launch the browser and create a page
- browser = await puppeteer.launch(launchParams);
- const page = await browser.newPage();
-
- // Basic auth
- const username = options.username; delete options.username
- const password = options.password; delete options.password
- if (username != undefined && password != undefined) {
- await page.authenticate({ username, password });
- }
-
- // Setting cookies
- const cookies = options.cookies; delete options.cookies
- if (Array.isArray(cookies)) {
- await page.setCookie(...cookies);
- }
-
- // Set caching flag (if provided)
- const cache = options.cache; delete options.cache;
- if (cache != undefined) {
- await page.setCacheEnabled(cache);
- }
-
- // Setup timeout option (if provided)
- let request_options = {};
- const timeout = options.timeout; delete options.timeout;
- if (timeout != undefined) {
- request_options.timeout = timeout;
- }
-
- // Setup viewport options (if provided)
- const viewport = options.viewport; delete options.viewport;
- if (viewport != undefined) {
- await page.setViewport(viewport);
- }
-
- const waitUntil = options.waitUntil; delete options.waitUntil;
- if (url_or_html.match(/^http/i)) {
- // Request is for a URL, so request it
- request_options.waitUntil = waitUntil || 'networkidle2';
- await page.goto(url_or_html, request_options);
- } else {
- // Request is some HTML content. Use request interception to assign the body
- request_options.waitUntil = waitUntil || 'networkidle0';
- await page.setRequestInterception(true);
- page.once('request', request => {
- request.respond({ body: url_or_html });
- // Reset the request interception
- // (we only want to intercept the first request - ie our HTML)
- page.on('request', request => request.continue());
- });
- const displayUrl = options.displayUrl; delete options.displayUrl;
- await page.goto(displayUrl || 'http://example.com', request_options);
- }
-
- // If specified, emulate the media type
- const emulateMedia = options.emulateMedia; delete options.emulateMedia;
- if (emulateMedia != undefined) {
- if (typeof page.emulateMediaType == 'function') {
- await page.emulateMediaType(emulateMedia);
- } else {
- await page.emulateMedia(emulateMedia);
- }
- }
-
- // If specified, evaluate script on the page
- const executeScript = options.executeScript; delete options.executeScript;
- if (executeScript != undefined) {
- await page.evaluate(executeScript);
- }
-
- // If we're running puppeteer in headless mode, return the converted PDF
- if (debug == undefined || (typeof debug === 'object' && (debug.headless == undefined || debug.headless))) {
- return await page.#{convert_action}(options);
- }
- } finally {
- if (browser) {
- await browser.close();
- }
- }
- }
- FUNCTION
- end
-
- method :convert_pdf, convert_function('pdf')
- method :convert_screenshot, convert_function('screenshot')
- end
- private_constant :Processor
-
DEFAULT_HEADER_TEMPLATE = "<div class='date text left'></div><div class='title text center'></div>"
DEFAULT_FOOTER_TEMPLATE = <<~HTML
<div class='url text left grow'></div>
<div class='text right'><span class='pageNumber'></span>/<span class='totalPages'></span></div>
HTML
@@ -169,14 +45,11 @@
#
# @param [String] path Optional path to write the PDF to
# @return [String] The resulting PDF data
#
def to_pdf(path = nil)
- result = processor.convert_pdf @url, normalized_options(path: path)
- return unless result
-
- result['data'].pack('C*')
+ processor.convert :pdf, @url, normalized_options(path: path)
end
#
# Request URL with provided options and create screenshot
#
@@ -184,34 +57,31 @@
# @param [String] format Optional format of the screenshot
# @return [String] The resulting image data
#
def screenshot(path: nil, format: nil)
options = normalized_options(path: path)
- options['type'] = format if format.is_a? ::String
- result = processor.convert_screenshot @url, options
- return unless result
-
- result['data'].pack('C*')
+ options['type'] = format if %w[png jpeg].include? format
+ processor.convert :screenshot, @url, options
end
#
# Request URL with provided options and create PNG
#
# @param [String] path Optional path to write the screenshot to
# @return [String] The resulting PNG data
#
def to_png(path = nil)
- screenshot(path: path, format: 'png')
+ screenshot path: path, format: 'png'
end
#
# Request URL with provided options and create JPEG
#
# @param [String] path Optional path to write the screenshot to
# @return [String] The resulting JPEG data
#
def to_jpeg(path = nil)
- screenshot(path: path, format: 'jpeg')
+ screenshot path: path, format: 'jpeg'
end
#
# Returns whether a front cover (request) path has been specified in the options
#