lightpanda 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 591cd0a182a0ce6cfababbdfa954162a4ac47c0968f9a84663d34fb0acb71c20
4
- data.tar.gz: e4783c19ac142387b2d3eb9144115bae6d252a9d7ca4c3c944d5692aeb8bfb12
3
+ metadata.gz: 3e916e825715e3501b088ac44898d31bab07985528782eec4da975fd91bfe009
4
+ data.tar.gz: e290aabcd4c89547255ca9e6090eb4eb5bc22dc4551d3811e9bf7f5f03a3bbe4
5
5
  SHA512:
6
- metadata.gz: 1aec3d07fd8fb537e82c1e1c938b6008727d90f8fca579caf0d2120501d9acb2659e4bb177b3568e43bbeb2d27f83084bf3a9e61673aa89e11830ff7409c152b
7
- data.tar.gz: 300e97b99c1b1f5524c53bec47cded120cde15c680d260da0be7472e447f8e15c939c6068172b36ef408d78bde75a8c591ee633863bb5393235611a0ae0e1eb5
6
+ metadata.gz: e98478d21b3044f719470994b8ef2d90ca484e26173097829ebc196612e9bad1e8e0da1764abef32d605cf9d38686cc267e5b3a4571ec4cbb23f58189a523fe0
7
+ data.tar.gz: ecf37c64b4349e8d9a2013979c3bfac94c40952afa5e835711ddbfdf49e8035677cb7b863bd9a2922e9a8d595f0c4cfd3299dfa1996ac115d77eefc714f03fd1
data/README.md CHANGED
@@ -1,16 +1,20 @@
1
- # Lightpanda
1
+ # Lightpanda for Ruby
2
2
 
3
- Ruby client for the [Lightpanda](https://lightpanda.io) headless browser via CDP (Chrome DevTools Protocol).
3
+ Ruby client for the [Lightpanda](https://lightpanda.io) [open-source](https://github.com/lightpanda-io/browser) headless browser via CDP (Chrome DevTools Protocol).
4
4
 
5
5
  Lightpanda is a fast, lightweight headless browser built for web automation, AI agents, and scraping. This gem provides a high-level Ruby API to control Lightpanda, similar to [Ferrum](https://github.com/rubycdp/ferrum) for Chrome.
6
6
 
7
+ > [!NOTE]
8
+ > This gem is experimental. [Lightpanda itself](https://github.com/lightpanda-io/browser?tab=readme-ov-file#status) is in Beta and currently a work in progress. Stability and coverage are improving, but you may still encounter errors or crashes. This gem's API will evolve as Lightpanda matures. See [Limitations](#limitations).
9
+
10
+
7
11
  ## Features
8
12
 
9
13
  - High-level browser automation API
10
14
  - CDP (Chrome DevTools Protocol) client
11
15
  - Capybara driver included
12
16
  - Auto-downloads Lightpanda binary if not found
13
- - Ruby 3.1+
17
+ - Ruby 3.2+
14
18
 
15
19
  ## Installation
16
20
 
@@ -124,6 +128,20 @@ html = Lightpanda::Binary.fetch("https://example.com")
124
128
  # => "<!DOCTYPE html><html>..."
125
129
  ```
126
130
 
131
+ ### Global Configuration
132
+
133
+ ```ruby
134
+ Lightpanda.configure do |config|
135
+ config.binary_path = "/path/to/lightpanda"
136
+ end
137
+ ```
138
+
139
+ If not explicitly set, the binary path is auto-discovered on first use and cached for subsequent calls. The discovery order is:
140
+
141
+ 1. `LIGHTPANDA_PATH` environment variable
142
+ 2. `lightpanda` executable in your `PATH`
143
+ 3. Auto-download to `~/.cache/lightpanda/lightpanda` (or `$XDG_CACHE_HOME/lightpanda/lightpanda`)
144
+
127
145
  ### Capybara Integration
128
146
 
129
147
  **Basic usage**
@@ -187,7 +205,7 @@ Lightpanda is a lightweight browser with some limitations compared to Chrome:
187
205
 
188
206
  ```bash
189
207
  bundle install
190
- bundle exec mtest
208
+ bundle exec minitest
191
209
  ```
192
210
 
193
211
  ## License
data/exe/lightpanda ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/lightpanda"
5
+
6
+ args = ARGV.empty? ? ["help"] : ARGV
7
+
8
+ Lightpanda::Binary.exec(*args)
@@ -25,29 +25,32 @@ module Lightpanda
25
25
  GITHUB_RELEASE_URL = "https://github.com/lightpanda-io/browser/releases/download/nightly"
26
26
 
27
27
  PLATFORMS = {
28
- %w[x86_64 linux] => "lightpanda-x86_64-linux",
29
- %w[aarch64 darwin] => "lightpanda-aarch64-macos",
30
- %w[arm64 darwin] => "lightpanda-aarch64-macos"
28
+ ["x86_64", "linux"] => "lightpanda-x86_64-linux",
29
+ ["aarch64", "darwin"] => "lightpanda-aarch64-macos",
30
+ ["arm64", "darwin"] => "lightpanda-aarch64-macos",
31
31
  }.freeze
32
32
 
33
33
  class << self
34
34
  def path
35
- find_or_download
35
+ Lightpanda.configuration.binary_path ||= find_or_download
36
36
  end
37
37
 
38
38
  def find_or_download
39
39
  find || download
40
40
  end
41
41
 
42
- def run(*args)
43
- binary = find_or_download
44
- stdout, stderr, status = Open3.capture3(binary, *args)
42
+ def run(*)
43
+ stdout, stderr, status = Open3.capture3(path, *)
45
44
 
46
45
  Result.new(stdout: stdout, stderr: stderr, status: status)
47
46
  rescue Errno::ENOENT
48
47
  raise BinaryNotFoundError, "Lightpanda binary not found"
49
48
  end
50
49
 
50
+ def exec(*)
51
+ Kernel.exec(path, *)
52
+ end
53
+
51
54
  def fetch(url)
52
55
  result = run("fetch", "--dump", url)
53
56
  raise BinaryError, result.stderr unless result.success?
@@ -105,12 +108,31 @@ module Lightpanda
105
108
  ENV["PATH"].to_s.split(File::PATH_SEPARATOR).each do |dir|
106
109
  path = File.join(dir, "lightpanda")
107
110
 
108
- return path if File.executable?(path)
111
+ return path if File.executable?(path) && native_binary?(path)
109
112
  end
110
113
 
111
114
  nil
112
115
  end
113
116
 
117
+ def native_binary?(path)
118
+ header = File.binread(path, 4)
119
+
120
+ return true if elf_binary?(header)
121
+ return true if mach_o_binary?(header)
122
+
123
+ false
124
+ rescue StandardError
125
+ false
126
+ end
127
+
128
+ def elf_binary?(header)
129
+ header.start_with?("\x7FELF")
130
+ end
131
+
132
+ def mach_o_binary?(header)
133
+ header.start_with?("\xCF\xFA\xED\xFE")
134
+ end
135
+
114
136
  def normalize_arch(arch)
115
137
  case arch
116
138
  when /x86_64|amd64/i then "x86_64"
@@ -8,7 +8,7 @@ module Lightpanda
8
8
 
9
9
  attr_reader :options, :process, :client, :target_id, :session_id
10
10
 
11
- delegate %i[on off] => :client
11
+ delegate [:on, :off] => :client
12
12
 
13
13
  def initialize(options = {})
14
14
  @options = Options.new(options)
@@ -157,7 +157,7 @@ module Lightpanda
157
157
  y: 0,
158
158
  width: content_size["width"],
159
159
  height: content_size["height"],
160
- scale: 1
160
+ scale: 1,
161
161
  }
162
162
  end
163
163
 
@@ -16,9 +16,16 @@ module Lightpanda
16
16
  end
17
17
 
18
18
  def browser
19
+ @browser = nil if @browser && !browser_alive?
19
20
  @browser ||= Lightpanda::Browser.new(@options)
20
21
  end
21
22
 
23
+ def browser_alive?
24
+ @browser.client && !@browser.client.closed?
25
+ rescue StandardError
26
+ false
27
+ end
28
+
22
29
  def visit(url)
23
30
  browser.go_to(url)
24
31
  end
@@ -34,7 +34,7 @@ module Lightpanda
34
34
  host: host,
35
35
  port: port,
36
36
  timeout: timeout,
37
- browser_path: browser_path
37
+ browser_path: browser_path,
38
38
  }
39
39
  end
40
40
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lightpanda
4
+ class Configuration
5
+ attr_accessor :binary_path
6
+
7
+ def initialize
8
+ @binary_path = nil
9
+ end
10
+ end
11
+ end
@@ -24,7 +24,7 @@ module Lightpanda
24
24
  value: value,
25
25
  path: path,
26
26
  secure: secure,
27
- httpOnly: http_only
27
+ httpOnly: http_only,
28
28
  }
29
29
 
30
30
  params[:domain] = domain if domain
@@ -55,7 +55,7 @@ module Lightpanda
55
55
  url: params.dig("request", "url"),
56
56
  method: params.dig("request", "method"),
57
57
  timestamp: params["timestamp"],
58
- response: nil
58
+ response: nil,
59
59
  }
60
60
  end
61
61
 
@@ -67,7 +67,7 @@ module Lightpanda
67
67
  request[:response] = {
68
68
  status: params.dig("response", "status"),
69
69
  headers: params.dig("response", "headers"),
70
- mime_type: params.dig("response", "mimeType")
70
+ mime_type: params.dig("response", "mimeType"),
71
71
  }
72
72
  end
73
73
  end
@@ -39,7 +39,7 @@ module Lightpanda
39
39
  window_size: window_size,
40
40
  browser_path: browser_path,
41
41
  headless: headless,
42
- ws_url: ws_url
42
+ ws_url: ws_url,
43
43
  }
44
44
  end
45
45
  end
@@ -69,11 +69,14 @@ module Lightpanda
69
69
  end
70
70
 
71
71
  def build_args
72
- %W[
73
- serve
74
- --host #{@options.host}
75
- --port #{@options.port}
76
- --log_level info
72
+ [
73
+ "serve",
74
+ "--host",
75
+ @options.host.to_s,
76
+ "--port",
77
+ @options.port.to_s,
78
+ "--log_level",
79
+ "info",
77
80
  ]
78
81
  end
79
82
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lightpanda
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/lightpanda.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "lightpanda/version"
4
4
  require_relative "lightpanda/errors"
5
+ require_relative "lightpanda/configuration"
5
6
  require_relative "lightpanda/options"
6
7
  require_relative "lightpanda/binary"
7
8
  require_relative "lightpanda/process"
@@ -12,8 +13,16 @@ require_relative "lightpanda/browser"
12
13
 
13
14
  module Lightpanda
14
15
  class << self
15
- def new(**options)
16
- Browser.new(**options)
16
+ def new(**)
17
+ Browser.new(**)
18
+ end
19
+
20
+ def configuration
21
+ @configuration ||= Configuration.new
22
+ end
23
+
24
+ def configure
25
+ yield(configuration)
17
26
  end
18
27
  end
19
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightpanda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Roth
@@ -29,39 +29,41 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.1'
32
+ version: '1.3'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.1'
39
+ version: '1.3'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: websocket-driver
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.7'
46
+ version: '0.8'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.7'
54
- description: High-level Ruby API to control Lightpanda browser. Lightpanda is a fast,
55
- lightweight headless browser built for web automation, AI agents, and scraping.
53
+ version: '0.8'
54
+ description: High-level Ruby API to control the Lightpanda browser. Lightpanda is
55
+ a fast, lightweight headless browser built for web automation, AI agents, and scraping.
56
56
  This gem provides CDP-based browser control similar to Ferrum.
57
57
  email:
58
58
  - marco.roth@intergga.ch
59
- executables: []
59
+ executables:
60
+ - lightpanda
60
61
  extensions: []
61
62
  extra_rdoc_files: []
62
63
  files:
63
64
  - LICENSE.txt
64
65
  - README.md
66
+ - exe/lightpanda
65
67
  - lib/lightpanda.rb
66
68
  - lib/lightpanda/binary.rb
67
69
  - lib/lightpanda/browser.rb
@@ -71,6 +73,7 @@ files:
71
73
  - lib/lightpanda/client.rb
72
74
  - lib/lightpanda/client/subscriber.rb
73
75
  - lib/lightpanda/client/web_socket.rb
76
+ - lib/lightpanda/configuration.rb
74
77
  - lib/lightpanda/cookies.rb
75
78
  - lib/lightpanda/errors.rb
76
79
  - lib/lightpanda/network.rb
@@ -92,14 +95,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
95
  requirements:
93
96
  - - ">="
94
97
  - !ruby/object:Gem::Version
95
- version: 3.1.0
98
+ version: '3.2'
96
99
  required_rubygems_version: !ruby/object:Gem::Requirement
97
100
  requirements:
98
101
  - - ">="
99
102
  - !ruby/object:Gem::Version
100
103
  version: '0'
101
104
  requirements: []
102
- rubygems_version: 3.6.9
105
+ rubygems_version: 4.0.3
103
106
  specification_version: 4
104
107
  summary: Ruby client for the Lightpanda headless browser via Chrome DevTools Protocol.
105
108
  test_files: []