screentake 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d6fe6b26493d9070ad6db10fd5accd18b1ada36cd60eccc157c0378cc24d28f1
4
+ data.tar.gz: 94b23b9f579ad1d7cbc4244d5d54260d692bf94e88a15384c1573bfb8602b62f
5
+ SHA512:
6
+ metadata.gz: aecb55173a821838fe18c495b38c0f2caa34415d8b0685925403ccbdd96fb891d3905887d206256e6dc632b506f5fcf342f8de2f73249d9a2265f63a105fea63
7
+ data.tar.gz: 4d34057305663ca48d3e520ed25d213b12271f13e35ebb28dc541ebf0f9382ce364d52730148adf6d816f76c6c811e65627cf034a7194d15f1d198b4543394a1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Maful Prayoga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,519 @@
1
+ # Screentake
2
+
3
+ A Ruby gem for capturing web page screenshots with a clean, keyword-driven API. Supports both the Cloudflare Browser Rendering API and a local Ferrum (headless Chrome) driver.
4
+
5
+ ## Overview
6
+
7
+ Screentake provides a simple interface for turning URLs or raw HTML into PNG, JPEG, or WebP screenshots. It handles viewport configuration, device scale factors, full-page captures, element-specific screenshots, and various wait strategies out of the box.
8
+
9
+ The gem ships with two interchangeable drivers. The **Cloudflare** driver sends rendering requests to the [Cloudflare Browser Rendering API](https://developers.cloudflare.com/browser-rendering/) -- no local browser required. The **Ferrum** driver uses headless Chrome on your own machine via the [Ferrum](https://github.com/rubycdp/ferrum) gem. Both drivers share the same options interface, so switching between them is a one-line configuration change.
10
+
11
+ ## Features
12
+
13
+ - **URL and HTML rendering** -- pass a URL or an HTML string
14
+ - **Multiple output formats** -- PNG, JPEG, WebP
15
+ - **Viewport control** -- width, height, and device scale factor (1-4x)
16
+ - **Full-page capture** -- screenshot the entire scrollable page
17
+ - **Element targeting** -- capture a specific CSS selector
18
+ - **Clip regions** -- crop to an arbitrary rectangle
19
+ - **Transparent backgrounds** -- omit the default white background
20
+ - **Wait strategies** -- wait for load, DOMContentLoaded, network idle, a selector, or a fixed timeout
21
+ - **Automatic retries** -- Cloudflare driver retries on 429 rate limits with exponential backoff
22
+ - **Three output methods** -- raw binary, Base64, or save directly to a file
23
+ - **Rails auto-integration** -- Railtie loaded automatically when Rails is present
24
+ - **Driver pattern** -- swap between Cloudflare and Ferrum without changing application code
25
+
26
+ ## Installation
27
+
28
+ Add to your Gemfile:
29
+
30
+ ```ruby
31
+ gem "screentake"
32
+ ```
33
+
34
+ Then run:
35
+
36
+ ```bash
37
+ bundle install
38
+ ```
39
+
40
+ Or install directly:
41
+
42
+ ```bash
43
+ gem install screentake
44
+ ```
45
+
46
+ If you plan to use the Ferrum driver, also add:
47
+
48
+ ```ruby
49
+ gem "ferrum", "~> 0.15"
50
+ ```
51
+
52
+ ### Rails Installation
53
+
54
+ After adding screentake to your Gemfile, run the install generator:
55
+
56
+ ```bash
57
+ bundle install
58
+ rails generate screentake:install
59
+ ```
60
+
61
+ This creates `config/initializers/screentake.rb` with default configuration. Set your Cloudflare credentials via environment variables (`CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN`) or edit the initializer directly.
62
+
63
+ ## Quick Start
64
+
65
+ ```ruby
66
+ require "screentake"
67
+
68
+ Screentake.configure do |config|
69
+ config.cloudflare_account_id = ENV["CLOUDFLARE_ACCOUNT_ID"]
70
+ config.cloudflare_api_token = ENV["CLOUDFLARE_API_TOKEN"]
71
+ end
72
+
73
+ # Take a screenshot and save it
74
+ screenshot = Screentake.take(url: "https://example.com")
75
+ screenshot.save("example.png")
76
+
77
+ # Or get the binary data directly
78
+ binary = screenshot.capture
79
+
80
+ # Or get Base64 for embedding in HTML/JSON
81
+ encoded = screenshot.base64
82
+ ```
83
+
84
+ ## Configuration
85
+
86
+ Configure Screentake globally with `Screentake.configure`:
87
+
88
+ ```ruby
89
+ Screentake.configure do |config|
90
+ # Driver selection (:cloudflare or :ferrum)
91
+ config.driver = :cloudflare
92
+
93
+ # Cloudflare credentials (required for :cloudflare driver)
94
+ config.cloudflare_account_id = ENV["CLOUDFLARE_ACCOUNT_ID"]
95
+ config.cloudflare_api_token = ENV["CLOUDFLARE_API_TOKEN"]
96
+
97
+ # Default viewport dimensions
98
+ config.default_viewport = { width: 1280, height: 800 }
99
+
100
+ # Device scale factor (1-4, default: 2)
101
+ config.default_scale = 2
102
+
103
+ # Default image format (:png, :jpeg, :webp)
104
+ config.default_format = :png
105
+
106
+ # Navigation timeout in milliseconds (default: 30000)
107
+ config.timeout = 30_000
108
+
109
+ # Logger instance for debug/retry output (default: nil)
110
+ config.logger = Rails.logger
111
+
112
+ # Ferrum browser options (only used with :ferrum driver)
113
+ config.ferrum_options = { headless: true }
114
+ end
115
+ ```
116
+
117
+ ### Configuration Defaults
118
+
119
+ | Option | Default | Description |
120
+ |---|---|---|
121
+ | `driver` | `:cloudflare` | Which rendering backend to use |
122
+ | `cloudflare_account_id` | `nil` | Your Cloudflare account ID |
123
+ | `cloudflare_api_token` | `nil` | Your Cloudflare API token |
124
+ | `default_viewport` | `{ width: 1280, height: 800 }` | Browser viewport size |
125
+ | `default_scale` | `2` | Device scale factor (Retina) |
126
+ | `default_format` | `:png` | Output image format |
127
+ | `timeout` | `30000` | Navigation timeout (ms) |
128
+ | `logger` | `nil` | Logger for debug output |
129
+ | `ferrum_options` | `{ headless: true }` | Options passed to `Ferrum::Browser.new` |
130
+
131
+ ## Usage Examples
132
+
133
+ ### Basic URL Screenshot
134
+
135
+ ```ruby
136
+ screenshot = Screentake.take(url: "https://example.com")
137
+ screenshot.save("output.png")
138
+ ```
139
+
140
+ ### HTML Content Screenshot
141
+
142
+ ```ruby
143
+ html = <<~HTML
144
+ <html>
145
+ <body style="background: #1a1a2e; color: #eee; padding: 40px;">
146
+ <h1>Hello from Screentake</h1>
147
+ </body>
148
+ </html>
149
+ HTML
150
+
151
+ screenshot = Screentake.take(html: html)
152
+ screenshot.save("rendered.png")
153
+ ```
154
+
155
+ Note: `url:` and `html:` are mutually exclusive. Passing both raises `ArgumentError`.
156
+
157
+ ### Full-Page Capture
158
+
159
+ ```ruby
160
+ screenshot = Screentake.take(
161
+ url: "https://example.com/long-page",
162
+ full_page: true,
163
+ )
164
+ screenshot.save("full_page.png")
165
+ ```
166
+
167
+ ### Custom Viewport and Scale
168
+
169
+ ```ruby
170
+ # Using width: and height:
171
+ screenshot = Screentake.take(
172
+ url: "https://example.com",
173
+ width: 1920,
174
+ height: 1080,
175
+ scale: 3,
176
+ )
177
+
178
+ # Using size: shorthand
179
+ screenshot = Screentake.take(
180
+ url: "https://example.com",
181
+ size: [375, 812], # iPhone viewport
182
+ scale: 3,
183
+ )
184
+ ```
185
+
186
+ ### Selector-Based Screenshot
187
+
188
+ Capture only a specific element:
189
+
190
+ ```ruby
191
+ screenshot = Screentake.take(
192
+ url: "https://example.com",
193
+ selector: "#hero-section",
194
+ )
195
+ screenshot.save("hero.png")
196
+ ```
197
+
198
+ ### Clip Region
199
+
200
+ Crop to an arbitrary rectangle:
201
+
202
+ ```ruby
203
+ screenshot = Screentake.take(
204
+ url: "https://example.com",
205
+ clip: { x: 0, y: 0, width: 600, height: 400 },
206
+ )
207
+ screenshot.save("cropped.png")
208
+ ```
209
+
210
+ ### Different Formats
211
+
212
+ ```ruby
213
+ # JPEG with quality setting
214
+ screenshot = Screentake.take(
215
+ url: "https://example.com",
216
+ format: :jpeg,
217
+ quality: 85,
218
+ )
219
+ screenshot.save("output.jpg")
220
+
221
+ # WebP with quality setting
222
+ screenshot = Screentake.take(
223
+ url: "https://example.com",
224
+ format: :webp,
225
+ quality: 90,
226
+ )
227
+ screenshot.save("output.webp")
228
+ ```
229
+
230
+ Note: `quality:` is only valid for JPEG and WebP. Passing it with PNG format raises `InvalidOptionError`.
231
+
232
+ The `.save` method also infers format from the file extension. Saving to `output.jpg` will produce a JPEG regardless of the `format:` option.
233
+
234
+ ### Transparent Background
235
+
236
+ ```ruby
237
+ screenshot = Screentake.take(
238
+ url: "https://example.com",
239
+ transparent: true,
240
+ format: :png,
241
+ )
242
+ screenshot.save("transparent.png")
243
+ ```
244
+
245
+ ### Wait Strategies
246
+
247
+ ```ruby
248
+ # Wait until there are zero network connections for 500ms
249
+ screenshot = Screentake.take(
250
+ url: "https://example.com",
251
+ wait_until: :networkidle0,
252
+ )
253
+
254
+ # Wait for a specific element to appear
255
+ screenshot = Screentake.take(
256
+ url: "https://example.com",
257
+ wait_for_selector: ".chart-loaded",
258
+ )
259
+
260
+ # Add a fixed delay (in milliseconds, 1-30000)
261
+ screenshot = Screentake.take(
262
+ url: "https://example.com",
263
+ wait_for_timeout: 2000,
264
+ )
265
+ ```
266
+
267
+ Available `wait_until` values:
268
+
269
+ | Value | Description |
270
+ |---|---|
271
+ | `:load` | Wait for the `load` event |
272
+ | `:domcontentloaded` | Wait for `DOMContentLoaded` event |
273
+ | `:networkidle0` | Wait until zero network connections for 500ms (default) |
274
+ | `:networkidle2` | Wait until two or fewer network connections for 500ms |
275
+
276
+ ### Output Methods
277
+
278
+ Every `Screentake.take` call returns a `Screenshot` object with three output methods:
279
+
280
+ ```ruby
281
+ screenshot = Screentake.take(url: "https://example.com")
282
+
283
+ # Raw binary data
284
+ binary = screenshot.capture
285
+
286
+ # Base64-encoded string
287
+ encoded = screenshot.base64
288
+
289
+ # Save to file (creates parent directories automatically, returns the path)
290
+ path = screenshot.save("screenshots/example.png")
291
+ ```
292
+
293
+ ### Debugging
294
+
295
+ Inspect the resolved options for a screenshot:
296
+
297
+ ```ruby
298
+ screenshot = Screentake.take(url: "https://example.com", full_page: true)
299
+ pp screenshot.debug
300
+ # {
301
+ # source_type: :url,
302
+ # source: "https://example.com",
303
+ # width: 1280,
304
+ # height: 800,
305
+ # scale: 2,
306
+ # format: :png,
307
+ # quality: nil,
308
+ # full_page: true,
309
+ # selector: nil,
310
+ # clip: nil,
311
+ # transparent: false,
312
+ # wait_until: :networkidle0,
313
+ # wait_for_selector: nil,
314
+ # wait_for_timeout: nil,
315
+ # driver: :cloudflare,
316
+ # }
317
+ ```
318
+
319
+ ## Drivers
320
+
321
+ ### Cloudflare (Default)
322
+
323
+ The Cloudflare driver sends requests to the [Cloudflare Browser Rendering API](https://developers.cloudflare.com/browser-rendering/). No local browser installation needed.
324
+
325
+ ```ruby
326
+ Screentake.configure do |config|
327
+ config.driver = :cloudflare
328
+ config.cloudflare_account_id = ENV["CLOUDFLARE_ACCOUNT_ID"]
329
+ config.cloudflare_api_token = ENV["CLOUDFLARE_API_TOKEN"]
330
+ end
331
+ ```
332
+
333
+ **Rate limits:** Cloudflare enforces 2 browsers per minute and 2 concurrent requests. The driver automatically retries up to 3 times on HTTP 429 responses with exponential backoff (1s, 2s, 4s).
334
+
335
+ ### Ferrum (Local Chrome)
336
+
337
+ The Ferrum driver runs a local headless Chrome instance via the [Ferrum](https://github.com/rubycdp/ferrum) gem. It requires Chrome or Chromium installed on the machine.
338
+
339
+ ```ruby
340
+ # Gemfile
341
+ gem "ferrum", "~> 0.15"
342
+ ```
343
+
344
+ ```ruby
345
+ Screentake.configure do |config|
346
+ config.driver = :ferrum
347
+ config.ferrum_options = {
348
+ headless: true,
349
+ # browser_path: "/usr/bin/chromium", # custom Chrome path
350
+ # timeout: 60, # Ferrum process timeout
351
+ }
352
+ end
353
+ ```
354
+
355
+ The Ferrum driver lazily starts the browser on the first screenshot, reuses it for subsequent requests (each screenshot gets its own browser context), and automatically shuts it down on process exit.
356
+
357
+ ### Choosing a Driver
358
+
359
+ | | Cloudflare | Ferrum |
360
+ |---|---|---|
361
+ | **Setup** | API credentials only | Chrome/Chromium installed locally |
362
+ | **Infrastructure** | No local browser needed | Runs on your server |
363
+ | **Rate limits** | 2/min, 2 concurrent | Limited by your hardware |
364
+ | **Cost** | Cloudflare pricing applies | Free (your compute) |
365
+ | **Best for** | Production, serverless | Development, CI, high volume |
366
+
367
+ ## API Reference
368
+
369
+ ### `Screentake.take(**options)`
370
+
371
+ Creates a `Screenshot` instance. Validates all options eagerly -- invalid options raise immediately, before any network request.
372
+
373
+ **Source options** (exactly one required):
374
+
375
+ | Option | Type | Description |
376
+ |---|---|---|
377
+ | `url:` | `String` | URL to capture (http/https only) |
378
+ | `html:` | `String` | Raw HTML content to render |
379
+
380
+ **Viewport options:**
381
+
382
+ | Option | Type | Default | Description |
383
+ |---|---|---|---|
384
+ | `width:` | `Integer` | `1280` | Viewport width (1-10000) |
385
+ | `height:` | `Integer` | `800` | Viewport height (1-10000) |
386
+ | `size:` | `Array` | -- | Shorthand `[width, height]` |
387
+ | `scale:` | `Numeric` | `2` | Device scale factor (1-4) |
388
+
389
+ **Capture options:**
390
+
391
+ | Option | Type | Default | Description |
392
+ |---|---|---|---|
393
+ | `format:` | `Symbol` | `:png` | `:png`, `:jpeg`, or `:webp` |
394
+ | `quality:` | `Integer` | `nil` | 1-100, JPEG/WebP only |
395
+ | `full_page:` | `Boolean` | `false` | Capture full scrollable page |
396
+ | `selector:` | `String` | `nil` | CSS selector to capture |
397
+ | `clip:` | `Hash` | `nil` | `{ x:, y:, width:, height: }` |
398
+ | `transparent:` | `Boolean` | `false` | Transparent background |
399
+
400
+ **Wait options:**
401
+
402
+ | Option | Type | Default | Description |
403
+ |---|---|---|---|
404
+ | `wait_until:` | `Symbol` | `:networkidle0` | Page load strategy |
405
+ | `wait_for_selector:` | `String` | `nil` | Wait for this CSS selector |
406
+ | `wait_for_timeout:` | `Numeric` | `nil` | Fixed delay in ms (1-30000) |
407
+
408
+ ### `Screenshot#capture`
409
+
410
+ Returns raw binary image data as a `String`.
411
+
412
+ ### `Screenshot#base64`
413
+
414
+ Returns the screenshot as a Base64-encoded `String` (strict encoding, no newlines).
415
+
416
+ ### `Screenshot#save(path)`
417
+
418
+ Writes the screenshot to `path`, creating parent directories as needed. Infers format from the file extension (`.jpg`/`.jpeg` to JPEG, `.webp` to WebP, `.png` to PNG). Returns the path as a `String`.
419
+
420
+ ### `Screenshot#debug`
421
+
422
+ Returns a `Hash` of all resolved options for inspection.
423
+
424
+ ### `Screentake.configure { |config| ... }`
425
+
426
+ Yields the global `Configuration` object for setting defaults.
427
+
428
+ ### `Screentake.reset_configuration!`
429
+
430
+ Resets all configuration to defaults and shuts down the current driver. Useful in tests.
431
+
432
+ ## Error Handling
433
+
434
+ All Screentake errors inherit from `Screentake::Error`, so you can rescue broadly or handle specific cases:
435
+
436
+ ```ruby
437
+ begin
438
+ screenshot = Screentake.take(url: "https://example.com")
439
+ screenshot.save("output.png")
440
+ rescue Screentake::RateLimitError
441
+ # Cloudflare 429 after all retries exhausted
442
+ retry_later
443
+ rescue Screentake::AuthenticationError => e
444
+ # Invalid Cloudflare credentials
445
+ Rails.logger.error("Screentake auth failed: #{e.message}")
446
+ rescue Screentake::TimeoutError
447
+ # Page took too long to load
448
+ handle_timeout
449
+ rescue Screentake::ElementNotFoundError
450
+ # Selector matched no elements
451
+ use_fallback_image
452
+ rescue Screentake::Error => e
453
+ # Catch-all for any Screentake error
454
+ Rails.logger.error("Screenshot failed: #{e.message}")
455
+ end
456
+ ```
457
+
458
+ ### Error Hierarchy
459
+
460
+ ```
461
+ Screentake::Error
462
+ Screentake::NotImplementedError
463
+ Screentake::InvalidUrlError
464
+ Screentake::InvalidHtmlError
465
+ Screentake::InvalidDimensionError
466
+ Screentake::InvalidOptionError
467
+ Screentake::InvalidClipError
468
+ Screentake::ElementNotFoundError
469
+ Screentake::TimeoutError
470
+ Screentake::RenderError
471
+ Screentake::DriverError
472
+ Screentake::CloudflareError
473
+ Screentake::RateLimitError
474
+ Screentake::AuthenticationError
475
+ Screentake::FerrumError
476
+ Screentake::BrowserNotFoundError
477
+ Screentake::BrowserCrashedError
478
+ ```
479
+
480
+ ## Development
481
+
482
+ ### Setup
483
+
484
+ ```bash
485
+ git clone https://github.com/maful/screentake.git
486
+ cd screentake
487
+ bin/setup
488
+ ```
489
+
490
+ ### Running Tests
491
+
492
+ ```bash
493
+ rake test # Run all tests
494
+ rake rubocop # Run linter
495
+ rake # Run tests + rubocop (default)
496
+ ```
497
+
498
+ ### Interactive Console
499
+
500
+ ```bash
501
+ bin/console
502
+ ```
503
+
504
+ ### Requirements
505
+
506
+ - Ruby >= 3.1
507
+ - Chrome or Chromium (for Ferrum driver only)
508
+
509
+ ### Contributing
510
+
511
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/maful/screentake](https://github.com/maful/screentake). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/maful/screentake/blob/main/CODE_OF_CONDUCT.md).
512
+
513
+ ## License
514
+
515
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
516
+
517
+ ## Code of Conduct
518
+
519
+ Everyone interacting in the Screentake project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/maful/screentake/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: [:test, :rubocop]
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Screentake
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates a Screentake initializer file."
9
+
10
+ def copy_initializer
11
+ template("screentake.rb", "config/initializers/screentake.rb")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ Screentake.configure do |config|
4
+ # Driver to use for capturing screenshots.
5
+ # :cloudflare and :ferrum is supported.
6
+ config.driver = :cloudflare
7
+
8
+ # Cloudflare Browser Rendering API credentials.
9
+ # You can also set these via environment variables:
10
+ # CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN
11
+ config.cloudflare_account_id = ENV.fetch("CLOUDFLARE_ACCOUNT_ID", nil)
12
+ config.cloudflare_api_token = ENV.fetch("CLOUDFLARE_API_TOKEN", nil)
13
+
14
+ # Default viewport dimensions (pixels).
15
+ # config.default_viewport = { width: 1280, height: 800 }
16
+
17
+ # Default device scale factor (1-4). 2 produces retina-quality output.
18
+ # config.default_scale = 2
19
+
20
+ # Default image format (:png, :jpeg, :webp).
21
+ # config.default_format = :png
22
+
23
+ # Request timeout in milliseconds.
24
+ # config.timeout = 30_000
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Screentake
4
+ class Configuration
5
+ attr_accessor :driver,
6
+ :cloudflare_account_id,
7
+ :cloudflare_api_token,
8
+ :default_viewport,
9
+ :default_scale,
10
+ :default_format,
11
+ :timeout,
12
+ :logger,
13
+ :ferrum_options
14
+
15
+ def initialize
16
+ @driver = :cloudflare
17
+ @cloudflare_account_id = nil
18
+ @cloudflare_api_token = nil
19
+ @default_viewport = { width: 1280, height: 800 }
20
+ @default_scale = 2
21
+ @default_format = :png
22
+ @timeout = 30_000
23
+ @logger = nil
24
+ @ferrum_options = { headless: true }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Screentake
4
+ module Drivers
5
+ # Abstract base class for screenshot drivers.
6
+ # All drivers must inherit from this class and implement #screenshot.
7
+ class Base
8
+ # Capture a screenshot and return binary image data.
9
+ #
10
+ # @param source [String] the URL or HTML content
11
+ # @param type [Symbol] :url or :html
12
+ # @param options [Hash] screenshot options (viewport, format, etc.)
13
+ # @return [String] binary image data
14
+ def screenshot(source:, type:, options:)
15
+ raise NotImplementedError, "#{self.class}#screenshot must be implemented"
16
+ end
17
+ end
18
+ end
19
+ end