robro 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 748799da6fc13bfb258f0faf4a35f6a77b5763d771ac383e5541106642777072
4
- data.tar.gz: 147c0165a510ee0b40c20c1e4ee471510a283c7808783daee68d8e43e0662077
3
+ metadata.gz: a1ed8475085bbc598b8d65eb0bd03913e6c1d898156bed192373c9dd4543e025
4
+ data.tar.gz: b233b37e22fff88c921a08a524a87515805de9327531ecdb8d636cf4ec33e8ea
5
5
  SHA512:
6
- metadata.gz: 1996d036539ca697e428d3b9a36d13be8f49d2b2f69b1bbd0ef5a79d9b2d82994970c1c813f165af621279e62fa7e4115c446e6762beb8d8c259a0243483347c
7
- data.tar.gz: 315dfaf0095ae5df05688f708cf07ec95c56bdb0c9be52ee65f586117a07392c4b83294fa4bad133597335279cbc8fea471a960516560b547134a3e6d7cff349
6
+ metadata.gz: e826a76fe9e7dce91249b2a0d5bd19495bebe6202e2ff55be5871b6acad9d8c8b3a4a160f03062b5a8b82f72f8c68ec4dfba3e8ce10b592f88fb316f9e0af003
7
+ data.tar.gz: b4de6981f340ebcc59bf0c709dde1546440a67e6a53137550a58f8d816e19ecac58cf0075da48029c66ec616036dae0e8a24fb626d8691560bd04aeb6732dc95
data/.gitignore CHANGED
@@ -8,4 +8,3 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /Gemfile.lock
11
- /.byebug_history
@@ -0,0 +1,36 @@
1
+ module Robro
2
+ class Browser
3
+ module Helpers
4
+ def remove_elements(css:)
5
+ page.execute_script "document.querySelectorAll('#{css}').forEach(e => { e.remove() } )"
6
+ end
7
+
8
+ def click_through_overlay(element)
9
+ element_regexp = {
10
+ firefox: /^Element (<.*>) is not clickable at point \((\d+),(\d+)\) because another element (?<element><.*>) obscures it$/,
11
+ chrome: /^element click intercepted: Element (<.*>) is not clickable at point \((\d+), (\d+)\)\. Other element would receive the click: (?<element><.*>)/,
12
+ }
13
+ loop do
14
+ element.click(wait: 1)
15
+ break
16
+ rescue StandardError => e
17
+ m_element = element_regexp[Robro.browser.application].match e.message
18
+ unless m_element.nil?
19
+ m_id = /id=\"(?<id>[a-zA-Z0-9-]+)/.match m_element[:element]
20
+ unless m_id.nil?
21
+ overlay_element_id = m_id[:id]
22
+ Robro.logger.debug "Removing '#{overlay_element_id}' that obscures target element"
23
+ remove_elements css: "##{overlay_element_id}"
24
+ else
25
+ Robro.logger.error "Unable to find element ID that obscures target (#{element}) in: '#{m_id[:element]}'"
26
+ debugger
27
+ end
28
+ else
29
+ Robro.logger.error "Unable to find element that obscures target (#{element}) in: '#{e.message}'"
30
+ debugger
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/robro/browser.rb CHANGED
@@ -2,32 +2,35 @@ require 'capybara'
2
2
  require 'capybara/dsl'
3
3
  require 'capybara-screenshot'
4
4
 
5
+ require_relative 'browser/helpers'
6
+
5
7
  module Robro
6
8
  class Browser
7
9
  attr_reader :application
8
10
 
9
11
  include Capybara::DSL
12
+ include Robro::Browser::Helpers
10
13
 
11
- def initialize(application)
14
+ def initialize(application, headless: false)
12
15
  @application = application.to_sym
13
- @headless = false # FIXME ENV['GUI'].nil?
16
+ @headless = headless
14
17
 
15
18
  Capybara.configure do |config|
16
19
  config.run_server = false
17
20
  config.default_max_wait_time = 5
18
21
  end
19
22
 
20
- # FIXME Register chrome_jack_headless
21
23
  require 'selenium-webdriver'
22
24
  Capybara.register_driver :chrome_jack do |app|
23
- options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
24
- opts.args << '--start-maximized'
25
- opts.args << '--disable-blink-features'
26
- opts.args << '--disable-blink-features=AutomationControlled'
27
- opts.args << '--excludeSwitches=enable-automation'
28
- opts.args << '--disable-gpu'
29
- end
30
- driver = Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: options)
25
+ options = ::Selenium::WebDriver::Chrome::Options.new
26
+ options.add_argument('--headless') if headless
27
+ options.add_argument('--start-maximized')
28
+ options.add_argument('--disable-blink-features')
29
+ options.add_argument('--disable-blink-features=AutomationControlled')
30
+ options.add_argument('--excludeSwitches=enable-automation')
31
+ options.add_argument('--disable-gpu')
32
+
33
+ driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
31
34
  bridge = driver.browser.send(:bridge)
32
35
 
33
36
  path = '/session/:session_id/chromium/send_command'
@@ -104,15 +107,13 @@ module Robro
104
107
 
105
108
  driver_name = case @application
106
109
  when :firefox
107
- 'selenium'
110
+ @headless ? 'selenium_headless' : 'selenium'
108
111
  when :chrome
109
112
  'chrome_jack'
110
113
  else
111
114
  raise "Unsupported browser: '#{application}'"
112
115
  end
113
116
 
114
- driver_name += '_headless' if @headless
115
-
116
117
  driver_name.to_sym
117
118
  end
118
119
  end
@@ -0,0 +1,24 @@
1
+ require 'tty-cursor'
2
+
3
+ require 'thor'
4
+
5
+ module Robro
6
+ class CLI < Thor
7
+ module Helpers
8
+ def self.show_download_progress(changes, details)
9
+ if changes['filename']
10
+ puts "Downloading '#{details['filename']}' (size: #{details['size']})"
11
+ puts " progress: 0% rate: --- remaining time: ---"
12
+ elsif changes['progress']
13
+ print TTY::Cursor.prev_line
14
+ print TTY::Cursor.clear_line
15
+ puts " progress: #{details['progress']} rate: #{details['rate']} remaining time: #{details['remaining_time']}"
16
+ elsif changes['rate_average']
17
+ puts " rate average: #{details['rate_average']}"
18
+ elsif changes['message']
19
+ puts "Download message: #{changes['message']}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
data/lib/robro/cli.rb CHANGED
@@ -4,8 +4,6 @@ require 'robro/user_scripts'
4
4
  require 'thor'
5
5
  require 'json'
6
6
 
7
- require 'active_support/inflector'
8
-
9
7
  module Robro
10
8
  class CLI < Thor
11
9
  desc 'browse URL', 'Start browser at URL, drop a shell'
@@ -18,22 +16,19 @@ module Robro
18
16
 
19
17
  quit = false
20
18
  until quit
21
- UserScripts.all.each do |us_class|
22
- us = us_class.new
23
- next unless uri.host.start_with? *(us.supported_urls)
19
+ us = UserScripts.find_for uri: uri
24
20
 
25
- unless us.nil?
26
- puts "Commands for this URL: #{us.supported_url_commands}"
21
+ unless us.nil?
22
+ puts "Commands for this URL: #{us.supported_url_commands}"
27
23
 
28
- us.supported_url_commands.each do |command|
29
- define_singleton_method command do |*args|
30
- us.send(command, *args)
31
- end
24
+ us.supported_url_commands.each do |command|
25
+ define_singleton_method command do |*args|
26
+ us.send(command, *args)
32
27
  end
33
28
  end
34
29
  end
35
30
 
36
- byebug
31
+ debugger
37
32
  end
38
33
  end
39
34
 
@@ -54,22 +49,20 @@ module Robro
54
49
  end
55
50
  end
56
51
 
57
- UserScripts.all.each do |us_class|
58
- us = us_class.new
59
- us.supported_url_commands.each do |command|
60
- desc "#{command} URL", command.to_s
61
- method_option :browser, :type => :string, :description => 'Supported values: firefox or chromium', :default => 'chrome'
62
- define_method command do |*args|
63
- url = args.shift
64
- raise Thor::Error, 'URL argument is missing' if url.nil?
52
+ UserScripts.all_commands.each do |command|
53
+ desc "#{command} URL", command.to_s
54
+ method_option :browser, :type => :string, :description => 'Supported values: firefox or chromium', :default => 'firefox'
55
+ define_method command do |*args|
56
+ url = args.shift
57
+ raise Thor::Error, 'URL argument is missing' if url.nil?
65
58
 
66
- uri = validate_url(url)
59
+ uri = validate_url(url)
67
60
 
68
- Robro.browser = Browser.new options[:browser]
69
- Robro.browser.visit uri
61
+ Robro.browser = Browser.new options[:browser]
70
62
 
71
- puts JSON.pretty_generate(us.send(command, *args))
72
- end
63
+ result = UserScripts.execute command, uri
64
+
65
+ puts JSON.pretty_generate(result)
73
66
  end
74
67
  end
75
68
  end
@@ -0,0 +1,123 @@
1
+ require 'open3'
2
+
3
+ module Robro
4
+ class Download
5
+ class Error < StandardError; end
6
+
7
+ attr_reader :details
8
+
9
+ def initialize(url)
10
+ @url = url.sub /^http:/, 'https:'
11
+ Robro.logger.debug "Attempt to download: #{@url}"
12
+ end
13
+
14
+ FILTERS = [
15
+ #--2020-11-10 22:30:31-- https://kubuntu.org/wp-content/uploads/2020/10/6ac0/GroovyBannerv4-1024x273.png
16
+ /^--\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}-- http/,
17
+ #Resolving kubuntu.org (kubuntu.org)... 162.213.33.214
18
+ /^Resolving /,
19
+ #Connecting to kubuntu.org (kubuntu.org)|162.213.33.214|:443... connected.
20
+ /^Connecting /,
21
+ #Reusing existing connection to kubuntu.org:443.
22
+ /^Reusing /,
23
+ ]
24
+
25
+ def run(&block)
26
+ @details = {}
27
+
28
+ result = false
29
+
30
+ Open3.popen2e(
31
+ { "LANG" => 'C'},
32
+ 'wget', '--continue', '--content-disposition', '--progress=dot:mega', @url,
33
+ ) do |stdin, stdout_and_err, thread|
34
+ stdout_and_err.each do |line|
35
+ line.chomp!
36
+ next if line.empty?
37
+
38
+ data = extract_details line
39
+
40
+ unless data.nil?
41
+ data['filename'] = eval "\"#{data['filename']}\"" unless data['filename'].nil? # Handle escaped UTF-8 chars
42
+ @details.merge! data
43
+ block.call data, @details
44
+ else
45
+ puts "==='#{line}'===" unless filtred?(line)
46
+ end
47
+ end
48
+
49
+ exit_status = thread.value
50
+ @details.merge!({ exit_status: exit_status })
51
+
52
+ raise Error.new "Error while downloading: #{error}" unless error.nil?
53
+ end
54
+ end
55
+
56
+ def downloaded?
57
+ success?
58
+ end
59
+
60
+ def success?
61
+ error.nil?
62
+ end
63
+
64
+ def error
65
+ return "#{details['error_code']}: #{details['error_text']}" unless details['error_code'].nil?
66
+ return "#{details['error_text']}" unless details['error_text'].nil?
67
+ return "Command execution failed with exit code: #{details[:exit_status].exitstatus}" unless details[:exit_status].success?
68
+
69
+ nil
70
+ end
71
+
72
+ private
73
+
74
+ def filtred?(line)
75
+ FILTERS.each do |regexp|
76
+ match = regexp.match line
77
+ return true unless match.nil?
78
+ end
79
+
80
+ false
81
+ end
82
+
83
+ EXTRACTORS = [
84
+ /^Length: (?<size>\d+)/,
85
+ /^Saving to: '(?<filename>.*)'$/,
86
+ # 64512K ,,,,,,,. ........ ........ ........ ........ ........ 2% 1.26M 37m23s
87
+ # 67584K ........ ........ ........ ........ ........ ........ 2% 870K 42m29s
88
+ # 101376K ........ ........ ........ ........ ........ ........ 4% 4.70M 8m56s
89
+ # 104448K ........ ........ ........ ........ ........ ........ 4% 5.87M 8m41s
90
+ # 107520K ........ ........ ........ ........ ........ ........ 4% 6.17M 8m27s
91
+ #2472960K ........ ........ .. 100% 5.80M=5m57s
92
+ /^.* [,. ]{8} [,. ]{8} [,. ]{8} [,. ]{8} [,. ]{8} [,. ]{8} *(?<progress>\d+%) (?<rate>.*)[ =](?<remaining_time>.*)$/,
93
+ #2020-11-08 09:29:55 ERROR 410: Gone.
94
+ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} ERROR (?<error_code>\d+): (?<error_text>.*)$/,
95
+ # [ skipping 79872K ]
96
+ /^ +\[ skipping (?<skipping>.*) \]/,
97
+ #2020-11-10 22:25:48 (1.19 MB/s) - 'GroovyBannerv4-1024x273.png' saved [278174/278174]
98
+ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \((?<rate_average>.*)\) - '.*' saved/,
99
+ # The file is already fully retrieved; nothing to do.
100
+ /^ (?<message>The file is already fully retrieved; nothing to do\.)$/,
101
+ #HTTP request sent, awaiting response... 200 OK
102
+ /^HTTP request sent, awaiting response... (?<http_status_code>\d+) (?<http_status_text>.*)$/,
103
+ #wget: unable to resolve host address 'kuubuntu.org'
104
+ /^wget: (?<error_text>unable to resolve host address '.*')$/,
105
+ #Cannot write to 'kubuntu.iso' (Success).
106
+ /^(?<error_text>Cannot write to .*)$/,
107
+ ]
108
+
109
+ def extract_details(line)
110
+ result = {}
111
+ EXTRACTORS.each do |extractor|
112
+ result.merge! extract(extractor, line)
113
+ end
114
+ result == {} ? nil : result
115
+ end
116
+
117
+ def extract(regexp, line)
118
+ match = regexp.match line
119
+ return {} if match.nil?
120
+ match.named_captures
121
+ end
122
+ end
123
+ end
@@ -1,3 +1,5 @@
1
+ require 'active_support/inflector'
2
+
1
3
  module Robro
2
4
  module UserScripts
3
5
  def self.all
@@ -8,7 +10,33 @@ module Robro
8
10
  end
9
11
  end
10
12
 
13
+ def self.all_commands
14
+ user_scripts = UserScripts.all.map(&:new)
15
+ user_scripts.map(&:supported_url_commands).flatten.uniq
16
+ end
17
+
18
+ def self.find_for(uri:)
19
+ user_scripts = UserScripts.all.map(&:new)
20
+ user_scripts.find { |us| uri.host.start_with? *(us.supported_urls) }
21
+ end
22
+
23
+ def self.execute(command, uri, *args)
24
+ us = find_for uri: uri
25
+
26
+ raise "No user scripts found for URI: #{uri}" if us.nil?
27
+
28
+ Robro.logger.info "Opening URL: #{uri}"
29
+ Robro.browser.visit uri
30
+
31
+ Robro.logger.info "User script: '#{us.class}' will process commnand '#{command}'"
32
+ us.send(command, uri)
33
+ end
34
+
11
35
  class Base
36
+ def browser
37
+ Robro.browser
38
+ end
39
+
12
40
  def commands
13
41
  raise NotImplementedError
14
42
  end
data/lib/robro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Robro
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/robro.rb CHANGED
@@ -2,8 +2,7 @@ require "robro/browser"
2
2
  require "robro/version"
3
3
 
4
4
  require 'tty/logger'
5
- require 'byebug'
6
- require 'webdrivers'
5
+ require 'debug'
7
6
 
8
7
  module Robro
9
8
  class Error < StandardError; end
@@ -13,6 +12,7 @@ module Robro
13
12
  config.handlers = [
14
13
  [:console, { output: $stderr, level: :debug }],
15
14
  ]
15
+ config.metadata = %i[date time]
16
16
  end
17
17
  end
18
18
 
data/robro.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
 
9
9
  spec.summary = %q{Robotized Browser}
10
10
  spec.description = %q{Automate tasks that require a _real_ browser}
11
- spec.homepage = "https://github.com/opus-codium/robro"
11
+ spec.homepage = "https://github.com/neomilium/robro"
12
12
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
13
13
 
14
14
  spec.metadata["homepage_uri"] = spec.homepage
@@ -29,9 +29,9 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency "capybara-screenshot"
30
30
  spec.add_dependency "selenium-webdriver"
31
31
  spec.add_dependency "thor"
32
+ spec.add_dependency "tty-cursor"
32
33
  spec.add_dependency "tty-logger"
33
- spec.add_dependency "webdrivers"
34
- spec.add_development_dependency "byebug"
34
+ spec.add_development_dependency "debug"
35
35
  spec.add_development_dependency "bundler"
36
36
  spec.add_development_dependency "rake"
37
37
  spec.add_development_dependency "rspec"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romuald Conty
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-12 00:00:00.000000000 Z
11
+ date: 2025-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: tty-logger
84
+ name: tty-cursor
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: webdrivers
98
+ name: tty-logger
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: byebug
112
+ name: debug
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -183,17 +183,20 @@ files:
183
183
  - exe/robro
184
184
  - lib/robro.rb
185
185
  - lib/robro/browser.rb
186
+ - lib/robro/browser/helpers.rb
186
187
  - lib/robro/cli.rb
188
+ - lib/robro/cli/helpers.rb
189
+ - lib/robro/download.rb
187
190
  - lib/robro/user_scripts.rb
188
191
  - lib/robro/version.rb
189
192
  - robro.gemspec
190
- homepage: https://github.com/opus-codium/robro
193
+ homepage: https://github.com/neomilium/robro
191
194
  licenses: []
192
195
  metadata:
193
- homepage_uri: https://github.com/opus-codium/robro
194
- source_code_uri: https://github.com/opus-codium/robro.git
195
- changelog_uri: https://github.com/opus-codium/robro/Changelog.md
196
- post_install_message:
196
+ homepage_uri: https://github.com/neomilium/robro
197
+ source_code_uri: https://github.com/neomilium/robro.git
198
+ changelog_uri: https://github.com/neomilium/robro/Changelog.md
199
+ post_install_message:
197
200
  rdoc_options: []
198
201
  require_paths:
199
202
  - lib
@@ -208,8 +211,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
211
  - !ruby/object:Gem::Version
209
212
  version: '0'
210
213
  requirements: []
211
- rubygems_version: 3.1.2
212
- signing_key:
214
+ rubygems_version: 3.3.15
215
+ signing_key:
213
216
  specification_version: 4
214
217
  summary: Robotized Browser
215
218
  test_files: []