gamerom 0.4.1 → 0.6.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.
data/lib/gamerom/cli.rb CHANGED
@@ -31,11 +31,11 @@ module Gamerom
31
31
  validate_platform repo, options[:platform]
32
32
  puts "showing info for game #{game_identifier} on #{options[:platform]} platform on #{options[:repo]} repo..."
33
33
  game = repo.find(options[:platform], game_identifier)
34
- if !game.nil?
34
+ if game.nil?
35
+ shell.say "Game #{game_identifier} not found", :red
36
+ else
35
37
  puts game
36
38
  puts game.filenames if game.installed?
37
- else
38
- shell.say "Game #{game_identifier} not found", :red
39
39
  end
40
40
  rescue StandardError => e
41
41
  render_error e, options
@@ -61,6 +61,8 @@ module Gamerom
61
61
  end
62
62
  game.install
63
63
  shell.say 'Game installed', :green
64
+ rescue Gamerom::ManualDownloadRequired => e
65
+ shell.say e.message, :yellow
64
66
  rescue StandardError => e
65
67
  render_error e, options
66
68
  exit 1
@@ -75,7 +77,13 @@ module Gamerom
75
77
  validate_platform repo, options[:platform]
76
78
  games = repo.games options[:platform], region: options[:region]
77
79
  games.each do |game|
78
- install(game.id) unless game.installed?
80
+ if game.installed?
81
+ shell.say "Game #{game.name} already installed", :yellow
82
+ next
83
+ end
84
+ install(game.id)
85
+ rescue StandardError, SystemExit => e
86
+ shell.say "Error installing game #{game.name}: #{e.message}", :red
79
87
  end
80
88
  rescue StandardError => e
81
89
  render_error e, options
@@ -116,28 +124,12 @@ module Gamerom
116
124
  validate_platform repo, options[:platform]
117
125
  puts "recovering state of roms for #{options[:platform]} platform on #{options[:repo]} repo..."
118
126
  games = repo.games options[:platform]
119
- games_not_found = []
120
- games.each do |game|
121
- filename = nil
122
- basename = "#{Gamerom::GAME_DIR}/#{repo.name}/#{options[:platform]}/#{game[:region]}/#{game[:name]}"
123
- %w[zip 7z rar].each do |ext|
124
- fullname = "#{basename}.#{ext}"
125
- filename = fullname if File.exist? fullname
126
- end
127
+ game_names = games.to_h { |game| [game.id, game.name] }
128
+ results = games.group_by { |game| recover_game(game, game_names) }
127
129
 
128
- if filename
129
- game.update_state File.basename(filename)
130
- puts "Found game #{game[:name]}"
131
- else
132
- games_not_found << game[:name]
133
- end
134
- end
135
- if games_not_found.count.positive?
136
- puts 'Games not found:'
137
- puts games_not_found
138
- end
130
+ print_recover_summary(results.fetch(:found, []), results.fetch(:already_installed, []), results.fetch(:not_found, []))
139
131
  rescue StandardError => e
140
- puts e.message
132
+ render_error e, options
141
133
  exit 1
142
134
  end
143
135
 
@@ -308,10 +300,8 @@ module Gamerom
308
300
  private
309
301
 
310
302
  def print_game_table(games)
311
- results = []
312
-
313
- games.each do |game|
314
- results << [
303
+ results = games.map do |game|
304
+ [
315
305
  game.id,
316
306
  game.name,
317
307
  game.region,
@@ -334,5 +324,113 @@ module Gamerom
334
324
 
335
325
  raise "Expected '--platform' to be one of #{repo.platforms.keys.join(", ")}; got #{platform}"
336
326
  end
327
+
328
+ # Recover helpers
329
+
330
+ def recover_game(game, game_names)
331
+ puts
332
+ puts "Checking game #{game}"
333
+ if game.filenames.any?
334
+ puts "#{shell.set_color("*", :green)} Found game at: #{game.filenames.first}"
335
+ return :already_installed
336
+ end
337
+
338
+ game_files = glob_game_files(game).select { |file| file_belongs_to_game?(file, game, game_names) }.sort
339
+ if game_files.empty?
340
+ puts "#{shell.set_color("*", :red)} not found"
341
+ return :not_found
342
+ end
343
+
344
+ game.update_state(game_files.map { |file| File.basename(file) })
345
+ print_recovered_files(game_files)
346
+ :found
347
+ end
348
+
349
+ def glob_game_files(game)
350
+ patterns = [
351
+ glob_escape(game.name.tr(' ', '_'), '_'),
352
+ glob_escape(game.name, ' ')
353
+ ]
354
+ patterns.flat_map { |pattern| Dir.glob("#{game.filepath}/#{pattern}*") }.uniq
355
+ end
356
+
357
+ def glob_escape(str, spacer)
358
+ str
359
+ .gsub(/([\\\[\]*?{}) ,])/, '\\\\\1')
360
+ .gsub(':', "#{spacer}-")
361
+ .gsub('!', '\!*')
362
+ .gsub('(', '*\(')
363
+ end
364
+
365
+ # A globbed file is kept for a game unless it is a better match for another
366
+ # game whose name starts with this game's name (e.g. "Kung-Fu" vs "Kung-Fu Master").
367
+ def file_belongs_to_game?(file, game, game_names)
368
+ filename = File.basename(file).downcase
369
+ return true if exact_filename_match?(filename, game.name.downcase)
370
+
371
+ number = sequel_number(game.name)
372
+ return true if number && filename.include?(number)
373
+ return true if game.name.include?('Limited Run Games') && filename.include?('limited_run')
374
+
375
+ !claimed_by_other_game?(filename, game, game_names)
376
+ end
377
+
378
+ # "Game.zip", "Game_Name.zip" or "Game (USA).zip"
379
+ def exact_filename_match?(filename, name)
380
+ [name, name.tr(' ', '_')].any? do |variant|
381
+ filename.match?(/\A#{Regexp.escape(variant)}(\s*\(\w+\))?\.\w+\z/i)
382
+ end
383
+ end
384
+
385
+ # The number that identifies a sequel, e.g. "2" in "Tony Hawk's Pro Skater 2"
386
+ def sequel_number(name)
387
+ match = name.match(/(\d+|\s+\d+)[\s':]/) || name.match(/\s(\d+)$/)
388
+ match && match[1].strip
389
+ end
390
+
391
+ def claimed_by_other_game?(filename, game, game_names)
392
+ name = game.name.downcase
393
+ game_names.any? do |other_id, other_name|
394
+ next false if other_id == game.id
395
+
396
+ other = other_name.downcase
397
+ next false unless other.length > name.length && other.start_with?(name)
398
+
399
+ filename_matches_other_game?(filename, other_name)
400
+ end
401
+ end
402
+
403
+ def filename_matches_other_game?(filename, other_name)
404
+ other = other_name.downcase
405
+ other_underscored = other.tr(' ', '_')
406
+ return false unless filename.include?(other_underscored) || filename.include?(other)
407
+
408
+ number = sequel_number(other_name)
409
+ return filename.include?(number) if number
410
+
411
+ filename.start_with?(other_underscored) ||
412
+ filename.start_with?(other) ||
413
+ filename.include?(other_underscored.tr(':', '_')) ||
414
+ filename.include?(other.tr(':', '-'))
415
+ end
416
+
417
+ def print_recovered_files(game_files)
418
+ if game_files.size > 1
419
+ puts "#{shell.set_color("*", :green)} Found #{game_files.size} disks for game:"
420
+ game_files.each { |file| puts " - #{file}" }
421
+ else
422
+ puts "#{shell.set_color("*", :green)} Found game at: #{game_files.first}"
423
+ end
424
+ end
425
+
426
+ def print_recover_summary(games_found, games_already_installed, games_not_found)
427
+ if games_not_found.empty?
428
+ puts "All #{games_found.count + games_already_installed.count} games found"
429
+ else
430
+ puts "#{shell.set_color(games_found.count, :green)} games found"
431
+ puts "#{shell.set_color(games_already_installed.count, :yellow)} games already installed"
432
+ puts "#{shell.set_color(games_not_found.count, :red)} games not found"
433
+ end
434
+ end
337
435
  end
338
436
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamerom
4
+ class Error < StandardError; end
5
+
6
+ # Raised by repo adapters whose site does not allow automated downloads.
7
+ # The message tells the user where to download the game and where to save it.
8
+ class ManualDownloadRequired < Error; end
9
+ end
data/lib/gamerom/game.rb CHANGED
@@ -1,14 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fileutils'
4
- require 'ostruct'
5
4
  require 'yaml'
6
5
 
7
6
  module Gamerom
8
7
  # Game - Represents a game ROM
9
- class Game < OpenStruct
8
+ class Game
9
+ attr_accessor :id, :name, :platform, :region, :repo, :tags, :url
10
+
11
+ def initialize(attributes = {})
12
+ @tags = []
13
+ attributes.each do |key, value|
14
+ instance_variable_set("@#{key}", value)
15
+ end
16
+ end
17
+
10
18
  def filenames
11
- YAML.load_file(state_filename).map do |filename|
19
+ return [] unless File.exist? state_filename
20
+
21
+ Array(YAML.load_file(state_filename)).map do |filename|
12
22
  "#{filepath}/#{filename}"
13
23
  end
14
24
  end
@@ -84,7 +84,7 @@ module Gamerom
84
84
  tags = []
85
85
  codes = @name.scan(/\[(?<code>[^\]]+)\]/).flatten
86
86
  codes.each do |code|
87
- code = Regexp.last_match(1) if code.match /^(?<code>[abcfhop])[0-9]*/
87
+ code = Regexp.last_match(1) if code.match(/^(?<code>[abcfhop])[0-9]*/)
88
88
  tags << TAGS[code] if TAGS.include?(code)
89
89
  end
90
90
  tags
data/lib/gamerom/repo.rb CHANGED
@@ -27,8 +27,8 @@ module Gamerom
27
27
  @repo = Gamerom::RepoAdapters.const_get(name.capitalize)
28
28
  end
29
29
 
30
- def install(game, &block)
31
- @repo.install game, &block
30
+ def install(game, &)
31
+ @repo.install game, &
32
32
  end
33
33
 
34
34
  def find(platform, game_identifier)
@@ -12,14 +12,25 @@ module Gamerom
12
12
 
13
13
  def games(platform)
14
14
  games = []
15
- progress_bar = ProgressBar.new(platform, sections.count)
15
+
16
+ columns = `tput cols`.to_i
17
+ length = [120, columns].min
18
+
19
+ progress_bar = ProgressBar.create(
20
+ title: platform,
21
+ total: sections.count,
22
+ autofinish: true,
23
+ length: length,
24
+ format: "%t: %b\e[0;93m\u{15E7}\e[0m%i %j%% %e",
25
+ progress_mark: ' ',
26
+ remainder_mark: "\e[0;34m\u{FF65}\e[0m"
27
+ )
16
28
 
17
29
  extract_games(platform) do |section_games, section_index|
18
30
  games.append(*section_games)
19
- progress_bar.set(section_index + 1)
31
+ progress_bar.progress = section_index + 1
20
32
  end
21
33
 
22
- progress_bar.finish
23
34
  games
24
35
  end
25
36
  end
@@ -33,6 +33,7 @@ module Gamerom
33
33
  'saturn' => 'Sega Saturn',
34
34
  'psx' => 'Sony Playstation',
35
35
  'ps2' => 'Sony Playstation 2',
36
+ 'ps3' => 'Sony Playstation 3',
36
37
  'psp' => 'Sony Playstation Portable',
37
38
  }.freeze
38
39
 
@@ -48,10 +49,12 @@ module Gamerom
48
49
  sections.each_with_index do |section, index|
49
50
  page = nokogiri_get("https://coolrom.com.au/roms/#{platform}/#{section}/")
50
51
  regions = page.css('input.region').map { |i| i['name'] }
52
+ game_links = []
51
53
  regions.each do |region|
52
- game_links = page.css("div.#{region} a")
53
- yield game_links.map { |game_link| game(game_link, region) }, index
54
+ region_game_links = page.css("div.#{region} a")
55
+ game_links.append(*region_game_links.map { |game_link| game(game_link, region) })
54
56
  end
57
+ yield game_links, index
55
58
  end
56
59
  end
57
60
 
@@ -78,6 +81,7 @@ module Gamerom
78
81
  filename = response.filename
79
82
  FileUtils.mkdir_p(game.filepath)
80
83
  response.save!("#{game.filepath}/#{filename}")
84
+ puts "Downloaded: #{filename}"
81
85
  yield [filename]
82
86
  end
83
87
  end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mechanize'
4
+ require 'uri'
5
+ require 'mechanize/progressbar'
6
+ require 'mechanizeprogress'
7
+
8
+ module Gamerom
9
+ module RepoAdapters
10
+ # Edgeemu - An adapter for the Edge Emulation repository website
11
+ class Edgeemu
12
+ extend Gamerom::RepoAdapter
13
+
14
+ BASE_URL = 'https://edgeemu.net'
15
+
16
+ PLATFORM = {
17
+ 'atari-2600' => 'Atari 2600',
18
+ 'atari-5200' => 'Atari 5200',
19
+ 'atari-7800' => 'Atari 7800',
20
+ 'atari-jaguar' => 'Atari Jaguar',
21
+ 'atari-jaguar-cd' => 'Atari Jaguar CD',
22
+ 'atari-lynx' => 'Atari Lynx',
23
+ 'atari-st' => 'Atari ST',
24
+ 'bandai-wonderswan' => 'Bandai WonderSwan',
25
+ 'colecovision' => 'Coleco ColecoVision',
26
+ 'commodore-64' => 'Commodore 64',
27
+ 'commodore-amiga' => 'Commodore Amiga',
28
+ 'commodore-amiga-cd' => 'Commodore Amiga CD',
29
+ 'commodore-amiga-cd32' => 'Commodore Amiga CD32',
30
+ 'commodore-plus-4' => 'Commodore Plus-4',
31
+ 'commodore-vic-20' => 'Commodore VIC-20',
32
+ 'fairchild-channel-f' => 'Fairchild Channel F',
33
+ 'gce-vectrex' => 'GCE Vectrex',
34
+ 'microsoft-msx' => 'Microsoft MSX / MSX2',
35
+ 'nec-pc-engine-cd-turbografx-cd' => 'NEC PC Engine CD / TurboGrafx CD',
36
+ 'nec-pc-engine-supergrafx' => 'NEC PC Engine SuperGrafx',
37
+ 'nec-pc-engine-turbografx-16' => 'NEC PC Engine / TurboGrafx 16',
38
+ 'nintendo-64' => 'Nintendo 64',
39
+ 'nintendo-ds' => 'Nintendo DS',
40
+ 'nintendo-fds' => 'Nintendo Famicom Disk System (FDS)',
41
+ 'nintendo-gameboy' => 'Nintendo Game Boy',
42
+ 'nintendo-gameboy-advance' => 'Nintendo Game Boy Advance',
43
+ 'nintendo-gameboy-color' => 'Nintendo Game Boy Color',
44
+ 'nintendo-gamecube' => 'Nintendo Gamecube',
45
+ 'nintendo-nes' => 'Nintendo Entertainment System (NES)',
46
+ 'nintendo-satellaview' => 'Nintendo Satellaview',
47
+ 'nintendo-snes' => 'Super NES (SNES)',
48
+ 'nintendo-virtualboy' => 'Nintendo Virtual Boy',
49
+ 'panasonic-3do' => 'Panasonic 3DO',
50
+ 'philips-cdi' => 'Philips CDi',
51
+ 'rca-studioii' => 'RCA Studio II',
52
+ 'sega-32x' => 'Sega 32X',
53
+ 'sega-cd' => 'Sega Mega-CD / Sega CD',
54
+ 'sega-dreamcast' => 'Sega Dreamcast',
55
+ 'sega-gamegear' => 'Sega Game Gear',
56
+ 'sega-genesis' => 'Sega Mega Drive / Genesis',
57
+ 'sega-pico' => 'Sega PICO',
58
+ 'sega-saturn' => 'Sega Saturn',
59
+ 'sega-sg1000' => 'Sega SG-1000',
60
+ 'sega-sms' => 'Sega Master System / Mark III',
61
+ 'sinclair-zx-spectrum-3' => 'Sinclair ZX Spectrum +3',
62
+ 'snk-neo-geo-cd' => 'SNK Neo Geo CD',
63
+ 'snk-ngpc' => 'SNK Neo Geo Pocket Color',
64
+ 'watara-supervision' => 'Watara Supervision',
65
+ }.freeze
66
+
67
+ # No-Intro region tags, as they appear in parentheses in the file names
68
+ REGIONS = [
69
+ 'World', 'USA', 'Europe', 'Japan', 'Asia', 'Australia', 'Brazil', 'Canada', 'China', 'France',
70
+ 'Germany', 'Greece', 'Hong Kong', 'Italy', 'Korea', 'Netherlands', 'Norway', 'Poland', 'Portugal',
71
+ 'Russia', 'Scandinavia', 'Spain', 'Sweden', 'Taiwan', 'UK', 'Unknown', 'Latin America'
72
+ ].freeze
73
+
74
+ def self.platforms
75
+ PLATFORM
76
+ end
77
+
78
+ def self.sections
79
+ ('a'..'z').to_a.unshift('1')
80
+ end
81
+
82
+ def self.extract_games(platform)
83
+ sections.each_with_index do |section, index|
84
+ page = nokogiri_get("#{BASE_URL}/browse/#{platform}/#{section}")
85
+ yield page.css('div.item details').map { |item| game(item) }, index
86
+ rescue RestClient::NotFound
87
+ yield [], index
88
+ end
89
+ end
90
+
91
+ # Each item looks like:
92
+ # <details data-name="Espial (USA).zip">
93
+ # <summary>Espial (USA)</summary>
94
+ # <p><a href="/download/atari-2600/Espial%20%28USA%29.zip">download</a> ...</p>
95
+ # <p>hash:&nbsp;<span>931A0BDC</span></p>
96
+ # </details>
97
+ # The hash is the CRC32 of the ROM, which is used as the game id.
98
+ def self.game(item)
99
+ name = item.at_css('summary').text.strip
100
+ {
101
+ id: item.css('p').find { |p| p.text.start_with?('hash') }.at_css('span').text.strip.to_i(16),
102
+ name: name,
103
+ region: region(name),
104
+ url: "#{BASE_URL}#{item.at_css('a[href^="/download/"]')["href"]}",
105
+ }
106
+ end
107
+
108
+ # "Espial (USA)" => "USA", "Game (USA, Europe) (Proto)" => "USA, Europe"
109
+ def self.region(name)
110
+ groups = name.scan(/\(([^)]+)\)/).flatten
111
+ groups.find { |group| REGIONS.include?(group.split(',').first.strip) } || 'Unknown'
112
+ end
113
+
114
+ def self.install(game)
115
+ agent = Mechanize.new
116
+ agent.pluggable_parser.default = Mechanize::Download
117
+ agent.user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'
118
+
119
+ response = nil
120
+ agent.progressbar do
121
+ response = agent.get(game.url)
122
+ end
123
+
124
+ return unless response.code.to_i == 200
125
+
126
+ # The Content-Disposition header ends with a stray ";" that Mechanize cannot parse,
127
+ # so it falls back to the percent-encoded URL basename. Decode it instead.
128
+ filename = URI.decode_uri_component(File.basename(URI.parse(game.url).path))
129
+ FileUtils.mkdir_p(game.filepath)
130
+ response.save!("#{game.filepath}/#{filename}")
131
+ puts "Downloaded: #{filename}"
132
+ yield [filename]
133
+ end
134
+ end
135
+ end
136
+ end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mechanize'
4
- require 'mechanize/progressbar'
5
- require 'mechanizeprogress'
3
+ require 'fileutils'
6
4
 
7
5
  module Gamerom
8
6
  module RepoAdapters
@@ -11,6 +9,10 @@ module Gamerom
11
9
  extend Gamerom::RepoAdapter
12
10
 
13
11
  PLATFORM = {
12
+ '32X' => 'Sega 32X',
13
+ 'Atari2600' => 'Atari 2600',
14
+ 'Atari5200' => 'Atari 5200',
15
+ 'Atari7800' => 'Atari 7800',
14
16
  'Dreamcast' => 'Dreamcast',
15
17
  'DS' => 'Nintendo DS',
16
18
  'GameCube' => 'GameCube',
@@ -18,6 +20,8 @@ module Gamerom
18
20
  'GBA' => 'Game Boy Advance',
19
21
  'GBC' => 'Game Boy Color',
20
22
  'Genesis' => 'Genesis',
23
+ 'GG' => 'Game Gear',
24
+ 'Lynx' => 'Lynx',
21
25
  'N64' => 'Nintendo 64',
22
26
  'NES' => 'Nintendo',
23
27
  'PS1' => 'PlayStation',
@@ -25,9 +29,16 @@ module Gamerom
25
29
  'PS3' => 'PlayStation 3',
26
30
  'PSP' => 'PlayStation Portable',
27
31
  'Saturn' => 'Saturn',
32
+ 'SegaCD' => 'Sega CD',
33
+ 'SMS' => 'Master System',
28
34
  'SNES' => 'Super Nintendo',
35
+ 'TG16' => 'TurboGrafx-16',
36
+ 'TGCD' => 'TurboGrafx-CD',
37
+ 'VB' => 'Virtual Boy',
29
38
  'Wii' => 'Wii',
30
39
  'WiiWare' => 'WiiWare',
40
+ 'Xbox' => 'Xbox',
41
+ 'Xbox360' => 'Xbox 360',
31
42
  }.freeze
32
43
 
33
44
  def self.platforms
@@ -43,6 +54,8 @@ module Gamerom
43
54
  page = nokogiri_get("https://vimm.net/vault/?p=list&system=#{platform}&section=#{section}")
44
55
  game_links = page.css('table.hovertable td:first-child a:first-child')
45
56
  yield game_links.map { |game_link| game(game_link) }, index
57
+ rescue RestClient::NotFound
58
+ yield [], index
46
59
  end
47
60
  end
48
61
 
@@ -54,42 +67,20 @@ module Gamerom
54
67
  }
55
68
  end
56
69
 
70
+ # Vimm's Lair protects game pages with a browser challenge, so games have to be
71
+ # downloaded by hand. Prepare the target directory and tell the user what to do.
57
72
  def self.install(game)
58
73
  FileUtils.mkdir_p(game.filepath)
59
- agent = Mechanize.new
60
- agent.pluggable_parser.default = Mechanize::Download
61
- agent.user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'
62
- page = agent.get("https://vimm.net/vault/#{game.id}")
63
- form = page.form_with(id: 'download_form')
64
-
65
- filenames = []
66
- game_files = []
67
- multiple_disks = page.css('#download_disc_number')
68
-
69
- if multiple_disks.empty?
70
- game_files << { id: form['mediaId'], name: 'single file rom' }
71
- else
72
- puts 'multiple discs detected'
73
- game_files.concat(multiple_disks.children[1..-2].map { |disk| { name: disk.text, id: disk['value'] } })
74
- end
75
-
76
- game_files.each do |game_file|
77
- puts "downloading #{game_file[:name]}"
78
- form.method = 'GET'
79
- button = form.button_with(type: 'submit')
80
- response = nil
81
- form['mediaId'] = game_file[:id]
82
- agent.progressbar do
83
- response = form.click_button(button)
84
- end
85
-
86
- break unless response.code.to_i == 200
74
+ raise Gamerom::ManualDownloadRequired, <<~MSG
75
+ vimm.net does not allow automated downloads.
76
+ Download the game from #{game_url(game)} in your browser and save it to:
77
+ #{game.filepath}/
78
+ Then run `gamerom recover -r vimm -p #{game.platform}` to register it.
79
+ MSG
80
+ end
87
81
 
88
- filename = response.filename
89
- response.save!("#{game.filepath}/#{filename}")
90
- filenames << filename
91
- end
92
- yield filenames
82
+ def self.game_url(game)
83
+ "https://vimm.net/vault/#{game.id}"
93
84
  end
94
85
  end
95
86
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gamerom
4
- VERSION = '0.4.1'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/gamerom.rb CHANGED
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'gamerom/errors'
3
4
  require_relative 'gamerom/config'
4
5
  require_relative 'gamerom/game'
5
6
  require_relative 'gamerom/game_info'
6
7
  require_relative 'gamerom/repo'
7
8
  require_relative 'gamerom/cli'
8
9
  require_relative 'gamerom/version'
9
-
10
- module Gamerom
11
- class Error < StandardError; end
12
- end
@@ -3,6 +3,7 @@
3
3
  # Mechanize - A Monkeypatch for the mechanize progressbar
4
4
  class Mechanize
5
5
  include MechanizeProgressBarAPI # (1of7)a
6
+
6
7
  class HTTP
7
8
  # Agent - A Monkeypatch for the mechanize progressbar
8
9
  class Agent
@@ -31,11 +32,11 @@ class Mechanize
31
32
  log.debug("Read #{total} bytes total") if log && !mpbar.suppress_logger? # (7of7)a
32
33
 
33
34
  raise Mechanize::ResponseCodeError, response if
34
- Net::HTTPUnknownResponse == response
35
+ response == Net::HTTPUnknownResponse
35
36
 
36
37
  content_length = response.content_length
37
38
 
38
- unless Net::HTTP::Head == request || Net::HTTPRedirection == response
39
+ unless request == Net::HTTP::Head || response == Net::HTTPRedirection
39
40
  if content_length && content_length != body_io.length
40
41
  raise EOFError, "Content-Length (#{content_length}) does not match response body length (#{body_io.length})"
41
42
  end
@@ -46,3 +47,37 @@ class Mechanize
46
47
  end
47
48
  end
48
49
  end
50
+
51
+ # MechanizeProgressBar - A Monkeypatch for the mechanize progressbar
52
+ class MechanizeProgressBar
53
+ def inc(step)
54
+ @progressbar.progress = @progressbar.progress + step if @progressbar
55
+ end
56
+
57
+ def progressbar_new(pbar_opts, request, response)
58
+ out = pbar_opts[:out] || pbar_opts[:output] || $stderr
59
+ format = pbar_opts[:format] || "%j%% %b\e[0;93m\u{15E7}\e[0m%i Progress: %c/%C %a %e Speed: %rKB/sec %t"
60
+ if pbar_opts[:single]
61
+ title = pbar_opts[:title] || request['Host']
62
+ else
63
+ title = pbar_opts[:title] || ''
64
+ out.print "#{pbar_opts[:title] || uri(request)}\n"
65
+ end
66
+ total = pbar_opts[:total] || filesize(response)
67
+ pbar_class = pbar_opts[:reversed] ? ReversedProgressBar : ProgressBar
68
+
69
+ columns = `tput cols`.to_i
70
+ length = [120, columns].min
71
+
72
+ pbar_class.create(
73
+ title: title,
74
+ total: total,
75
+ output: out,
76
+ length: length,
77
+ format: format,
78
+ rate_scale: ->(rate) { rate / 1024 },
79
+ progress_mark: ' ',
80
+ remainder_mark: "\e[0;34m\u{FF65}\e[0m"
81
+ )
82
+ end
83
+ end