Dhalang 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -10
- data/lib/Dhalang.rb +3 -1
- data/lib/Dhalang/error.rb +1 -0
- data/lib/Dhalang/puppeteer.rb +41 -27
- data/lib/Dhalang/version.rb +1 -1
- data/lib/Screenshot.rb +11 -0
- data/lib/js/dhalang.js +30 -9
- data/lib/js/pdf-generator.js +4 -3
- data/lib/js/screenshot-generator.js +10 -6
- data/package.json +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bd71cb9e8eb643b85d2d2e68909db725b088b10ef29cd717634bc5429067ed4
|
4
|
+
data.tar.gz: 77b10c45d0c30132e3888c2cc04998502b34ae24a0e363e70b971987ec6a722c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d36638644a8b02e167b76f4b943b527fd06dd20cdc6ef4c77ce37af1e41bb24f4f03f13549b0b3cfcd9a1693b7aad535448ebbfd01b6a54cb53be39d32bbd063
|
7
|
+
data.tar.gz: e31806a5c74557130c558eda263a0b72045814db398c1554fe5bfaa5ce0240f14b22b52ce1afd1d8c488936097a8c407ff255c53c166cf346054d57cff749c80
|
data/README.md
CHANGED
@@ -3,11 +3,14 @@
|
|
3
3
|
> Dhalang is a Ruby wrapper for Google's Puppeteer.
|
4
4
|
|
5
5
|
|
6
|
+
|
6
7
|
## Features
|
7
8
|
* Generate PDFs from pages
|
8
9
|
* Generate PDFs from html ( external images/stylesheets supported )
|
9
10
|
* Capture a screenshot of a webpage
|
10
11
|
|
12
|
+
|
13
|
+
|
11
14
|
## Installation
|
12
15
|
Add this line to your application's Gemfile:
|
13
16
|
|
@@ -40,21 +43,43 @@ All methods return a string containing the PDF or JPEG/PNG in binary.
|
|
40
43
|
|
41
44
|
|
42
45
|
|
43
|
-
## Custom
|
44
|
-
|
46
|
+
## Custom PDF/screenshot options
|
47
|
+
To override the default options that are set by Dhalang you can pass as last argument a hash with the custom options you want to set.
|
48
|
+
|
49
|
+
For example to set custom margins for PDFs:
|
50
|
+
|
51
|
+
`Dhalang::PDF.get_from_url("https://www.google.com", {margin: { top: 100, right: 100, bottom: 100, left: 100}})
|
52
|
+
`
|
53
|
+
|
54
|
+
For example to only take a screenshot of the visible part of the page:
|
55
|
+
`Dhalang::Screenshot.get_from_url_as_png("https://www.google.com", {fullPage: false})
|
56
|
+
`
|
57
|
+
|
58
|
+
A list of all possible PDF options that can be set, can be found at: https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagepdfoptions
|
45
59
|
|
46
|
-
|
47
|
-
`Dhalang::Screenshot.get_from_url_as_jpeg("https://www.google.com", {navigation_timeout: 20000})`
|
60
|
+
A list of all possible screenshot options that can be set, can be found at: https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagescreenshotoptions
|
48
61
|
|
49
|
-
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
## Custom user options
|
66
|
+
You may want to change the way Dhalang interacts with Puppeteer in general. User options can be set by providing them in a hash as last argument to any calls you make to the library. Are you setting both custom PDF and user options? Then they should be passed as a single hash.
|
67
|
+
|
68
|
+
For example to set a custom navigation timeout:
|
69
|
+
`Dhalang::Screenshot.get_from_url_as_jpeg("https://www.google.com", {navigationTimeout: 20000})`
|
70
|
+
|
71
|
+
Below table lists all possible configuration parameters that can be set:
|
50
72
|
| Key | Description | Default |
|
51
73
|
|--------------------|-----------------------------------------------------------------------------------------|---------------------------------|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
| navigationTimeout | Amount of milliseconds until Puppeteer while timeout when navigating to the given page | 10000 |
|
75
|
+
| userAgent | User agent to send with the request | Default Puppeteer one |
|
76
|
+
| isHeadless | Indicates if Chromium should be launched headless | true |
|
77
|
+
| viewPort | Custom viewport to use for the request | Default Puppeteer one |
|
78
|
+
| httpAuthenticationCredentials | Custom HTTP authentication credentials to use for the request | None |
|
79
|
+
|
80
|
+
|
56
81
|
|
57
|
-
## Examples
|
82
|
+
## Examples of using Dhalang
|
58
83
|
To return a PDF from a Rails controller you can do the following:
|
59
84
|
```
|
60
85
|
def example_controller_method
|
data/lib/Dhalang.rb
CHANGED
@@ -4,9 +4,11 @@ module Dhalang
|
|
4
4
|
require_relative 'Dhalang/version'
|
5
5
|
require_relative 'Dhalang/url_utils'
|
6
6
|
require_relative 'Dhalang/file_utils'
|
7
|
+
require_relative 'Dhalang/error'
|
7
8
|
require_relative 'Dhalang/puppeteer'
|
8
9
|
require 'uri'
|
9
10
|
require 'tempfile'
|
10
11
|
require 'shellwords'
|
11
12
|
require 'json'
|
12
|
-
|
13
|
+
require 'open3'
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class DhalangError < StandardError; end
|
data/lib/Dhalang/puppeteer.rb
CHANGED
@@ -4,22 +4,17 @@ module Dhalang
|
|
4
4
|
NODE_MODULES_PATH = Dir.pwd + '/node_modules/'.freeze
|
5
5
|
private_constant :NODE_MODULES_PATH
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
VIEW_PORT = ''
|
17
|
-
private_constant :VIEW_PORT
|
18
|
-
|
19
|
-
HTTP_AUTHENTICATION_CREDENTIALS = ''
|
20
|
-
private_constant :HTTP_AUTHENTICATION_CREDENTIALS
|
7
|
+
USER_OPTIONS = {
|
8
|
+
navigationTimeout: 10000,
|
9
|
+
navigationWaitUntil: 'load',
|
10
|
+
userAgent: '',
|
11
|
+
isHeadless: true,
|
12
|
+
viewPort: '',
|
13
|
+
httpAuthenticationCredentials: ''
|
14
|
+
}
|
15
|
+
private_constant :USER_OPTIONS
|
21
16
|
|
22
|
-
|
17
|
+
DEFAULT_PDF_OPTIONS = {
|
23
18
|
scale: 1,
|
24
19
|
displayHeaderFooter: false,
|
25
20
|
headerTemplate: '',
|
@@ -33,7 +28,22 @@ module Dhalang
|
|
33
28
|
margin: { top: 36, right: 36, bottom: 20, left: 36 },
|
34
29
|
preferCSSPageSiz: false
|
35
30
|
}
|
36
|
-
private_constant :
|
31
|
+
private_constant :DEFAULT_PDF_OPTIONS
|
32
|
+
|
33
|
+
DEFAULT_PNG_OPTIONS = {
|
34
|
+
fullPage: true,
|
35
|
+
clip: nil,
|
36
|
+
omitBackground: false
|
37
|
+
}
|
38
|
+
private_constant :DEFAULT_PNG_OPTIONS
|
39
|
+
|
40
|
+
DEFAULT_JPEG_OPTIONS = {
|
41
|
+
quality: 100,
|
42
|
+
fullPage: true,
|
43
|
+
clip: nil,
|
44
|
+
omitBackground: false
|
45
|
+
}
|
46
|
+
private_constant :DEFAULT_JPEG_OPTIONS
|
37
47
|
|
38
48
|
|
39
49
|
# Launches a new Node process, executing the (Puppeteer) script under the given script_path.
|
@@ -45,7 +55,17 @@ module Dhalang
|
|
45
55
|
# @param [Object] options Set of options to use, configurable by the user.
|
46
56
|
def self.visit(page_url, script_path, temp_file_path, temp_file_extension, options)
|
47
57
|
configuration = create_configuration(page_url, script_path, temp_file_path, temp_file_extension, options)
|
48
|
-
|
58
|
+
|
59
|
+
command = "node #{script_path} #{Shellwords.escape(configuration)}"
|
60
|
+
|
61
|
+
Open3.popen2e(command) do |_stdin, stdouterr, wait|
|
62
|
+
return nil if wait.value.success?
|
63
|
+
|
64
|
+
output = stdouterr.read.strip
|
65
|
+
output = nil if output == ''
|
66
|
+
message = output || "Exited with status #{wait.value.exitstatus}"
|
67
|
+
raise DhalangError, message
|
68
|
+
end
|
49
69
|
end
|
50
70
|
|
51
71
|
|
@@ -62,16 +82,10 @@ module Dhalang
|
|
62
82
|
tempFilePath: temp_file_path,
|
63
83
|
puppeteerPath: NODE_MODULES_PATH,
|
64
84
|
imageType: temp_file_extension,
|
65
|
-
userOptions: {
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
},
|
70
|
-
userAgent: options.has_key?(:user_agent) ? options[:user_agent] : USER_AGENT,
|
71
|
-
viewPort: options.has_key?(:view_port) ? options[:view_port] : VIEW_PORT,
|
72
|
-
httpAuthenticationCredentials: options.has_key?(:http_authentication_credentials) ? options[:http_authentication_credentials] : HTTP_AUTHENTICATION_CREDENTIALS
|
73
|
-
},
|
74
|
-
pdfOptions: DEFAULT_OPTIONS.map { |option, value| [option, options.has_key?(option) ? options[option] : value] }.to_h
|
85
|
+
userOptions: USER_OPTIONS.map { |option, value| [option, options.has_key?(option) ? options[option] : value]}.to_h,
|
86
|
+
pdfOptions: DEFAULT_PDF_OPTIONS.map { |option, value| [option, options.has_key?(option) ? options[option] : value] }.to_h,
|
87
|
+
pngOptions: DEFAULT_PNG_OPTIONS.map { |option, value| [option, options.has_key?(option) ? options[option] : value] }.to_h,
|
88
|
+
jpegOptions: DEFAULT_JPEG_OPTIONS.map { |option, value| [option, options.has_key?(option) ? options[option] : value] }.to_h
|
75
89
|
}.to_json
|
76
90
|
end
|
77
91
|
end
|
data/lib/Dhalang/version.rb
CHANGED
data/lib/Screenshot.rb
CHANGED
@@ -33,6 +33,7 @@ module Dhalang
|
|
33
33
|
# @return [String] The screenshot that was taken as binary.
|
34
34
|
private_class_method def self.get(url, image_type, options)
|
35
35
|
UrlUtils.validate(url)
|
36
|
+
validate_options(options)
|
36
37
|
temp_file = FileUtils.create_temp_file(image_type)
|
37
38
|
begin
|
38
39
|
Puppeteer.visit(url, PUPPETEER_SCRIPT_PATH, temp_file.path, image_type, options)
|
@@ -42,5 +43,15 @@ module Dhalang
|
|
42
43
|
end
|
43
44
|
return binary_image_content
|
44
45
|
end
|
46
|
+
|
47
|
+
# Raises an error if the given options might conflict with the Puppeteer configuration.
|
48
|
+
#
|
49
|
+
# @param [Hash] options The options to validate
|
50
|
+
private_class_method def self.validate_options(options)
|
51
|
+
symbolized_options = options.transform_keys(&:to_sym)
|
52
|
+
if symbolized_options.has_key?(:type)
|
53
|
+
raise DhalangError, 'Invalid option set: "type"'
|
54
|
+
end
|
55
|
+
end
|
45
56
|
end
|
46
57
|
end
|
data/lib/js/dhalang.js
CHANGED
@@ -4,14 +4,20 @@
|
|
4
4
|
* @property {string} tempFilePath - The path of the tempfile to write the screenshot/pdf to.
|
5
5
|
* @property {string} puppeteerModulePath - The path of the Puppeteer module.
|
6
6
|
* @property {string} imageType - The type of image to save ( undefined for pdfgenerator ).
|
7
|
-
* @property {UserOptions} userOptions - User defined and default parameters to use when navigating to pages
|
7
|
+
* @property {UserOptions} userOptions - User defined and default parameters to use when navigating to pages.
|
8
|
+
* @property {Object} pdfOptions - User defined and default parameters to use when creating PDFs.
|
9
|
+
* @property {Object} pngOptions - User defined and default parameters to use when creating PNGs.
|
10
|
+
* @property {Object} jpegOptions - User defined and default parameters to use when creating JPEGs.
|
8
11
|
*/
|
12
|
+
|
9
13
|
/**
|
10
14
|
* @typedef {Object} UserOptions
|
11
|
-
* @property {
|
12
|
-
* @property {string}
|
13
|
-
* @property {
|
14
|
-
* @property {
|
15
|
+
* @property {number} navigationTimeout - Maximum in milliseconds until navigation times out, we use a default of 10 seconds as timeout.
|
16
|
+
* @property {string} navigationWaitUntil - Determines when the navigation was finished, we wait here until the Window.load event is fired ( meaning all images, stylesheet, etc was loaded ).
|
17
|
+
* @property {string} userAgent - The user agent to send with requests.
|
18
|
+
* @property {boolean} isHeadless - Indicates if Puppeteer should launch Chromium in headless mode.
|
19
|
+
* @property {Object} viewPort - The view port to use.
|
20
|
+
* @property {Object} httpAuthenticationCredentials - The credentials to use for HTTP authentication.
|
15
21
|
*/
|
16
22
|
|
17
23
|
/**
|
@@ -31,15 +37,17 @@ exports.getConfiguration = function () {
|
|
31
37
|
|
32
38
|
/**
|
33
39
|
* Launches Puppeteer and returns its instance.
|
34
|
-
* @param {
|
40
|
+
* @param {UserOptions} configuration - The configuration to use.
|
35
41
|
* @returns {Promise<Object>}
|
36
42
|
* The launched instance of Puppeteer.
|
37
43
|
*/
|
38
|
-
exports.launchPuppeteer = async function (
|
39
|
-
module.paths.push(
|
44
|
+
exports.launchPuppeteer = async function (configuration) {
|
45
|
+
module.paths.push(configuration.puppeteerPath);
|
40
46
|
const puppeteer = require('puppeteer');
|
47
|
+
const launchArgs = ['--no-sandbox', '--disable-setuid-sandbox'];
|
41
48
|
return await puppeteer.launch({
|
42
|
-
args:
|
49
|
+
args: launchArgs,
|
50
|
+
headless: configuration.userOptions.isHeadless
|
43
51
|
});
|
44
52
|
}
|
45
53
|
|
@@ -60,4 +68,17 @@ exports.configurePage = async function (page, configuration) {
|
|
60
68
|
if (configuration.httpAuthenticationCredentials !== "") {
|
61
69
|
await page.authenticate(configuration.authenticationCredentials)
|
62
70
|
}
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Extracts the navigation parameters from the configuration in a format that is usable by Puppeteer.
|
75
|
+
* @param {Configuration} configuration - The configuration to extract the navigation parameters from.
|
76
|
+
* @returns {NavigationParameters}
|
77
|
+
* The extracted navigation parameters.
|
78
|
+
*/
|
79
|
+
exports.getNavigationParameters = function (configuration) {
|
80
|
+
return {
|
81
|
+
timeout: configuration.userOptions.navigationTimeout,
|
82
|
+
waituntil: configuration.userOptions.navigationWaitUntil
|
83
|
+
}
|
63
84
|
}
|
data/lib/js/pdf-generator.js
CHANGED
@@ -6,10 +6,10 @@ const createPdf = async () => {
|
|
6
6
|
|
7
7
|
let browser;
|
8
8
|
try {
|
9
|
-
browser = await dhalang.launchPuppeteer(configuration
|
9
|
+
browser = await dhalang.launchPuppeteer(configuration);
|
10
10
|
const page = await browser.newPage();
|
11
11
|
await dhalang.configurePage(page, configuration.userOptions);
|
12
|
-
await page.goto(configuration.webPageUrl, configuration
|
12
|
+
await page.goto(configuration.webPageUrl, dhalang.getNavigationParameters(configuration));
|
13
13
|
await page.waitForTimeout(250);
|
14
14
|
await page.pdf({
|
15
15
|
...{
|
@@ -18,7 +18,8 @@ const createPdf = async () => {
|
|
18
18
|
...configuration.pdfOptions
|
19
19
|
});
|
20
20
|
} catch (error) {
|
21
|
-
console.
|
21
|
+
console.error(error.message);
|
22
|
+
process.exit(1);
|
22
23
|
} finally {
|
23
24
|
if (browser) {
|
24
25
|
browser.close();
|
@@ -6,18 +6,22 @@ const createPdf = async () => {
|
|
6
6
|
|
7
7
|
let browser;
|
8
8
|
try {
|
9
|
-
browser = await dhalang.launchPuppeteer(configuration
|
9
|
+
browser = await dhalang.launchPuppeteer(configuration);
|
10
10
|
const page = await browser.newPage();
|
11
11
|
await dhalang.configurePage(page, configuration.userOptions);
|
12
|
-
await page.goto(configuration.webPageUrl, configuration
|
12
|
+
await page.goto(configuration.webPageUrl, dhalang.getNavigationParameters(configuration));
|
13
13
|
await page.waitForTimeout(250);
|
14
|
+
const screenshotOptions = configuration.imageType === "png" ? configuration.pngOptions : configuration.jpegOptions
|
14
15
|
await page.screenshot({
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
...{
|
17
|
+
path: configuration.tempFilePath,
|
18
|
+
type: configuration.imageType,
|
19
|
+
},
|
20
|
+
...screenshotOptions
|
18
21
|
});
|
19
22
|
} catch (error) {
|
20
|
-
console.
|
23
|
+
console.error(error.message);
|
24
|
+
process.exit(1);
|
21
25
|
} finally {
|
22
26
|
if (browser) {
|
23
27
|
browser.close();
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "dhalang",
|
3
|
-
"version": "
|
3
|
+
"version": "0.5.0",
|
4
4
|
"description": "",
|
5
5
|
"main": "index.js",
|
6
6
|
"directories": {
|
@@ -14,7 +14,7 @@
|
|
14
14
|
"url": "git+https://github.com/NielsSteensma/Dhalang.git"
|
15
15
|
},
|
16
16
|
"author": "",
|
17
|
-
"license": "
|
17
|
+
"license": "MIT",
|
18
18
|
"bugs": {
|
19
19
|
"url": "https://github.com/NielsSteensma/Dhalang/issues"
|
20
20
|
},
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Dhalang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Niels Steensma
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- README.md
|
97
97
|
- Rakefile
|
98
98
|
- lib/Dhalang.rb
|
99
|
+
- lib/Dhalang/error.rb
|
99
100
|
- lib/Dhalang/file_utils.rb
|
100
101
|
- lib/Dhalang/puppeteer.rb
|
101
102
|
- lib/Dhalang/url_utils.rb
|