thegamesdb 1.1.2 → 2.0.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/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake/testtask'
2
4
  require 'bundler/gem_tasks'
3
5
 
@@ -5,6 +7,7 @@ Rake::TestTask.new('test') do |t|
5
7
  t.pattern = 'test/**/*_test.rb'
6
8
  end
7
9
 
10
+ desc 'Run a Ruby console with gamesdb already loaded'
8
11
  task :console do
9
12
  require 'irb'
10
13
  require 'irb/completion'
@@ -1,246 +1,146 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thegamesdb/version'
2
- require 'thegamesdb/config'
4
+ require 'thegamesdb/developers'
5
+ require 'thegamesdb/games'
6
+ require 'thegamesdb/genres'
7
+ require 'thegamesdb/platforms'
8
+ require 'thegamesdb/publishers'
3
9
  require 'net/http'
4
10
  require 'json'
5
11
 
6
- # Client for TheGamesDB API (thegamesdb.net)
7
12
  module Gamesdb
8
- BASE_URL = 'https://api.thegamesdb.net/v1/'.freeze
9
- IMAGES_BASE_URL = 'https://legacy.thegamesdb.net/banners/'.freeze
10
-
11
- # Method for listing platform's games
12
- #
13
- # See: https://api.thegamesdb.net/#/operations/Games/GamesByPlatformID
14
- #
15
- # Parameters: platform id (int), page (int)
16
- #
17
- # = Returns:
18
- # Array of Hashes with games info
19
- #
20
- def self.games_by_platform_id(platform_id, page = 1)
21
- url = 'Games/ByPlatformID'
22
- params = {id: platform_id, page: page, include: 'boxart'}
23
- data = json_response(url, params)
24
- process_platform_games(data)
25
- end
13
+ # Client for TheGamesDB API (thegamesdb.net)
14
+ class Client
15
+ include Gamesdb::Developers
16
+ include Gamesdb::Games
17
+ include Gamesdb::Genres
18
+ include Gamesdb::Platforms
19
+ include Gamesdb::Publishers
26
20
 
27
- # Method for listing platforms
28
- # https://api.thegamesdb.net/#/operations/Platforms/Platforms
29
- #
30
- # Parameters: none
31
- #
32
- # == Returns:
33
- # Array of Hashes with platforms info
34
- #
35
- def self.platforms
36
- url = 'Platforms'
37
- params = { fields: 'icon,console,controller,developer,manufacturer,media,cpu,memory,graphics,sound,maxcontrollers,display,overview,youtube' }
38
- data = json_response(url, params)
39
-
40
- data['data']['platforms'].map do |p|
41
- symbolize_keys(p.last)
42
- end
43
- end
21
+ BASE_URL = 'https://api.thegamesdb.net/v1/'
22
+ IMAGES_BASE_URL = 'https://legacy.thegamesdb.net/banners/'
44
23
 
45
- # This API feature returns a set of metadata and artwork data for a
46
- # specified Platform ID.
47
- # https://api.thegamesdb.net/#/operations/Platforms/PlatformsByPlatformID
48
- #
49
- # Parameters:
50
- # - id - (int) The numeric ID of the platform in the GamesDB database
51
- #
52
- # == Returns:
53
- # Hash with platform info
54
- #
55
- def self.platform_by_id(id)
56
- url = 'Platforms/ByPlatformID'
57
- params = {
58
- id: id,
59
- fields: 'icon,console,controller,developer,manufacturer,media,cpu,memory,graphics,sound,maxcontrollers,display,overview,youtube'
60
- }
61
- data = json_response(url, params)
62
-
63
- response = data['data']['platforms'].values.first
64
- symbolize_keys(response)
65
- end
24
+ attr_reader :remaining_monthly_allowance, :extra_allowance, :allowance_refresh_timer
66
25
 
67
- # Method for getting game info
68
- # TODO: check (and test) that we support ',' delimited list
69
- # https://api.thegamesdb.net/#/operations/Games/GamesByGameID
70
- #
71
- # Parameters:
72
- # - id - (int) Game id
73
- #
74
- # == Returns:
75
- # Hash with game info
76
- #
77
- def self.game_by_id(id)
78
- url = 'Games/ByGameID'
79
- params = {
80
- id: id,
81
- fields: 'players,publishers,genres,overview,last_updated,rating,platform,coop,youtube,os,processor,ram,hdd,video,sound,alternates',
82
- include: 'boxart,platform'
83
- }
84
- data = json_response(url, params)
85
- return [] if data['data']['count'] == 0
86
- symbolize_keys(data['data']['games'].first)
87
- end
26
+ def initialize(api_key)
27
+ @api_key = api_key
28
+ end
88
29
 
89
- # The GetGamesList API search returns a listing of games matched up
90
- # with loose search terms.
91
- # https://api.thegamesdb.net/#/operations/Games/GamesByGameName
92
- #
93
- # Parameters:
94
- # - name (required)
95
- # - platform (optional - platform id)
96
- # - page (optional)
97
- #
98
- # == Returns:
99
- # Hash with game info: id, name (not-unique), release_date,
100
- # platform, etc.
101
- #
102
- def self.games_by_name(name, platform: nil, page: 1)
103
- url = 'Games/ByGameName'
104
- params = {
105
- fields: 'players,publishers,genres,overview,last_updated,rating,platform,coop,youtube,os,processor,ram,hdd,video,sound,alternates',
106
- include: 'boxart',
107
- name: name,
108
- page: page
109
- }
110
- unless platform.nil?
111
- params.merge!("filter[platform]" => platform)
30
+ # Perform request
31
+ #
32
+ # Used by every API endpoint, but can also be used manually.
33
+ #
34
+ # @param url [String] Required
35
+ # @param params [Hash] optional
36
+ #
37
+ # @return [Hash] Parsed JSON response
38
+ def perform_request(url, params = {})
39
+ raise ArgumentError, 'You need to set the API KEY to use the GamesDB API' unless @api_key
40
+
41
+ params = params.merge({ apikey: @api_key })
42
+ uri = URI(BASE_URL + url)
43
+ uri.query = URI.encode_www_form(params)
44
+ response = JSON.parse(Net::HTTP.get_response(uri).body)
45
+ refresh_allowances(response)
46
+ response
47
+ rescue StandardError => e
48
+ # TODO: Handle errors
49
+ raise e
112
50
  end
113
51
 
114
- data = json_response(url, params)
115
- process_platform_games(data)
116
- end
52
+ private
117
53
 
118
- # This API feature returns a list of available artwork types and
119
- # locations specific to the requested game id in the database. It
120
- # also lists the resolution of any images available. Scrapers can be
121
- # set to use a minimum or maximum resolution for specific images
122
- # https://api.thegamesdb.net/#/operations/Games/GamesImages
123
- #
124
- # Parameters
125
- # - id - (integer) The numeric ID of the game in Gamesdb that you
126
- # like to fetch artwork details for
127
- #
128
- # == Returns:
129
- # Hash with game art info: fanart (array), boxart (Hash, :front,
130
- # :back), screenshots (array), fanart (array)
131
- #
132
- def self.game_images(id)
133
- url = 'Games/Images'
134
- data = json_response(url, games_id: id)
135
- return [] if data.dig('data', 'count') == (0 || nil)
136
-
137
- response = {}
138
- response[:base_url] = data['data']['base_url']['original']
139
- response[:logo] = process_logo(data['data'], id)
140
- response[:boxart] = process_covers(data['data'], id)
141
- response[:screenshot] = process_screenshots(data['data'], id)
142
- response[:fanart] = process_fanart(data['data'], id)
143
- response
144
- end
145
-
146
- def self.process_logo(data, id)
147
- logo = data['images'][id.to_s].select { |a| a['type'] == "clearlogo" }
148
- logo.empty? ? '' : logo.first['filename']
149
- end
54
+ def refresh_allowances(response)
55
+ @remaining_monthly_allowance = response['remaining_monthly_allowance']
56
+ @extra_allowance = response['extra_allowance']
57
+ @allowance_refresh_timer = response['allowance_refresh_timer']
58
+ end
150
59
 
151
- def self.process_fanart(data, id)
152
- fanarts = []
153
- fanart = data['images'][id.to_s].select do |a|
154
- a['type'] == 'fanart'
60
+ def process_logo(data, id)
61
+ logo = data['images'][id.to_s].select { |a| a['type'] == 'clearlogo' }
62
+ logo.empty? ? '' : logo.first['filename']
155
63
  end
156
- return [] if fanart.empty?
157
- fanart.each do |art|
158
- width, height = art['resolution'].split("x") unless art['resolution'].nil?
159
- fanarts << {
160
- url: art['filename'],
161
- resolution: art['resolution'],
162
- width: width,
163
- height: height
164
- }
64
+
65
+ def process_fanart(data, id)
66
+ fanart = select_images(data, id, 'fanart')
67
+ return [] if fanart.empty?
68
+
69
+ fanart.map { |art| build_individual_fanart(art) }
165
70
  end
166
- fanarts
167
- end
168
71
 
169
- def self.process_screenshots(data, id)
170
- data['images'][id.to_s].select do |a|
171
- a['type'] == 'screenshot'
172
- end.map { |b| symbolize_keys(b) }
173
- end
72
+ def process_covers(data, id)
73
+ covers = {}
74
+ boxart = select_images(data, id, 'boxart')
75
+ return [] if boxart.empty?
174
76
 
175
- def self.process_covers(data, id)
176
- covers = {}
177
- boxart = data['images'][id.to_s].select do |a|
178
- a['type'] == "boxart"
77
+ boxart.each do |art|
78
+ width, height = art['resolution'].split('x') unless art['resolution'].nil?
79
+ covers[art['side'].to_sym] = art_structure(art, width, height)
80
+ end
81
+ covers
179
82
  end
180
- return [] if boxart.empty?
181
- boxart.each do |art|
182
- width, height = art['resolution'].split("x") unless art['resolution'].nil?
183
- covers[art['side'].to_sym] = {
83
+
84
+ def build_individual_fanart(art)
85
+ width, height = art['resolution'].split('x') unless art['resolution'].nil?
86
+ art_structure(art, width, height)
87
+ end
88
+
89
+ def art_structure(art, width, height)
90
+ {
184
91
  url: art['filename'],
185
92
  resolution: art['resolution'],
186
93
  width: width,
187
94
  height: height
188
95
  }
189
96
  end
190
- covers
191
- end
192
97
 
193
- private
194
-
195
- def self.configuration
196
- @configuration ||= Config.new
197
- end
198
-
199
- # Api call and xml parsing
200
- def self.json_response(url, params = {})
201
- params = params.merge({apikey: configuration.api_key})
202
-
203
- uri = URI(BASE_URL + url)
204
- uri.query = URI.encode_www_form(params)
205
- request = Net::HTTP.get_response(uri)
206
- response = JSON.parse(request.body)
207
- response
208
- end
98
+ def process_screenshots(data, id)
99
+ select_images(data, id, 'screenshot').map { |b| symbolize_keys(b) }
100
+ end
209
101
 
210
- # Process games for platform_games
211
- def self.process_platform_games(data)
212
- games = []
213
-
214
- data['data']['games'].each do |elem|
215
- id = elem['id']
216
- games << {
217
- name: elem['game_title'],
218
- id: id,
219
- release_date: elem['release_date'],
220
- platform: elem['platform'],
221
- developers: elem['developers'],
222
- players: elem['players'],
223
- publishers: elem['publishers'],
224
- genres: elem['genres'],
225
- overview: elem['overview'],
226
- last_updated: elem['last_updated'],
227
- rating: elem['rating'],
228
- coop: elem['coop'],
229
- youtube: elem['youtube'],
230
- alternates: elem['alternates'],
231
- image: if boxart = data.dig('include', 'boxart', 'data', id.to_s)
232
- data['include']['boxart']['base_url']['original'] +
233
- boxart.select { |a| a['side'] == 'front' }.first['filename'] || ''
234
- end
235
- }
102
+ def select_images(data, id, image_type)
103
+ data['images'][id.to_s].select do |a|
104
+ a['type'] == image_type
105
+ end
236
106
  end
237
- games
238
- end
239
107
 
240
- def self.symbolize_keys(hash)
241
- hash.keys.each do |key|
242
- hash[key.to_sym] = hash.delete(key)
108
+ # Process games for platform_games
109
+ # rubocop:disable Metrics/AbcSize
110
+ # rubocop:disable Metrics/MethodLength
111
+ def process_platform_games(data)
112
+ data['data']['games'].map do |elem|
113
+ {
114
+ name: elem['game_title'],
115
+ id: elem['id'],
116
+ release_date: elem['release_date'],
117
+ platform: elem['platform'],
118
+ developers: elem['developers'],
119
+ players: elem['players'],
120
+ publishers: elem['publishers'],
121
+ genres: elem['genres'],
122
+ overview: elem['overview'],
123
+ last_updated: elem['last_updated'],
124
+ rating: elem['rating'],
125
+ coop: elem['coop'],
126
+ youtube: elem['youtube'],
127
+ alternates: elem['alternates'],
128
+ image: if (boxart = data.dig('include', 'boxart', 'data', elem['id'].to_s))
129
+ data['include']['boxart']['base_url']['original'] +
130
+ boxart.select { |a| a['side'] == 'front' }.first['filename'] || ''
131
+ end
132
+ }
133
+ end
134
+ end
135
+ # rubocop:enable Metrics/AbcSize
136
+ # rubocop:enable Metrics/MethodLength
137
+
138
+ def symbolize_keys(hash)
139
+ new_hash = {}
140
+ hash.each_key do |key|
141
+ new_hash[key.to_sym] = hash.delete(key)
142
+ end
143
+ new_hash
243
144
  end
244
- hash
245
145
  end
246
146
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamesdb
4
+ # Developers related API Endpoints
5
+ module Developers
6
+ # Fetches Developers list
7
+ #
8
+ # @see https://api.thegamesdb.net/#/Developers/Developers
9
+ #
10
+ # @return Array of Hashes with id and name as keys
11
+ def developers
12
+ url = 'Developers'
13
+ data = perform_request(url)
14
+ data['data']['developers'].map { |_id, developer| developer }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamesdb
4
+ # Games related API Endpoints
5
+ module Games
6
+ # Method for listing platform's games
7
+ #
8
+ # @see https://api.thegamesdb.net/#/Games/GamesByPlatformID
9
+ #
10
+ # @param id [Integer]
11
+ # @param page [Integer]
12
+ #
13
+ # @return [Array] Array of Hashes with games info
14
+ #
15
+ def games_by_platform_id(platform_id, page = 1)
16
+ url = 'Games/ByPlatformID'
17
+ params = { id: platform_id, page: page, include: 'boxart' }
18
+ data = perform_request(url, params)
19
+ process_platform_games(data)
20
+ end
21
+
22
+ # Method for getting game info
23
+ #
24
+ # @see https://api.thegamesdb.net/#/Games/GamesByGameID
25
+ #
26
+ # @param id [Integer|String] Game id or string of ',' delimited list
27
+ #
28
+ # @return [Array|Hash] Hash with game info
29
+ #
30
+ # rubocop:disable Metrics/MethodLength
31
+ def games_by_id(id)
32
+ url = 'Games/ByGameID'
33
+ params = {
34
+ id: id,
35
+ fields:
36
+ 'players,publishers,genres,overview,last_updated,rating,platform,coop,youtube,os,processor,ram,hdd,'\
37
+ 'video,sound,alternates',
38
+ include: 'boxart,platform'
39
+ }
40
+ data = perform_request(url, params)
41
+ return [] if (data['data']['count']).zero?
42
+
43
+ games = data['data']['games']
44
+ return symbolize_keys(games.first) if games.count == 1
45
+
46
+ games.map { |game| symbolize_keys(game) }
47
+ end
48
+ # rubocop:enable Metrics/MethodLength
49
+
50
+ # The GetGamesList API search returns a listing of games matched up with loose search terms.
51
+ #
52
+ # @see https://api.thegamesdb.net/#/Games/GamesByGameName
53
+ #
54
+ # @param name [String] game name (required)
55
+ # @param platform [Integer] (optional - platform id)
56
+ # @param page [Integer] (optional)
57
+ #
58
+ # @return [Hash] Hash with game info: id, name (not-unique), release_date, platform, etc.
59
+ #
60
+ # rubocop:disable Metrics/MethodLength
61
+ def games_by_name(name, platform: nil, page: 1)
62
+ url = 'Games/ByGameName'
63
+ params = {
64
+ fields:
65
+ 'players,publishers,genres,overview,last_updated,rating,platform,coop,youtube,os,processor,ram,hdd'\
66
+ ',video,sound,alternates',
67
+ include: 'boxart',
68
+ name: name,
69
+ page: page
70
+ }
71
+ params.merge!('filter[platform]' => platform) unless platform.nil?
72
+
73
+ data = perform_request(url, params)
74
+ process_platform_games(data)
75
+ end
76
+ # rubocop:enable Metrics/MethodLength
77
+
78
+ # This API feature returns a list of available artwork types and
79
+ # locations specific to the requested game id in the database. It
80
+ # also lists the resolution of any images available. Scrapers can be
81
+ # set to use a minimum or maximum resolution for specific images
82
+ #
83
+ # @see https://api.thegamesdb.net/#/Games/GamesImages
84
+ #
85
+ # @param id [Integer] The numeric ID of the game in Gamesdb that you like to fetch artwork details for
86
+ #
87
+ # @return [Hash] Hash with game art info: fanart (array), boxart (Hash,
88
+ # :front, :back), screenshots (array), fanart (array)
89
+ #
90
+ # rubocop:disable Metrics/AbcSize
91
+ def games_images(id)
92
+ url = 'Games/Images'
93
+ data = perform_request(url, games_id: id)
94
+ return [] if data.dig('data', 'count') == (0 || nil)
95
+
96
+ response = {}
97
+ response[:base_url] = data['data']['base_url']['original']
98
+ response[:logo] = process_logo(data['data'], id)
99
+ response[:boxart] = process_covers(data['data'], id)
100
+ response[:screenshot] = process_screenshots(data['data'], id)
101
+ response[:fanart] = process_fanart(data['data'], id)
102
+ response
103
+ end
104
+
105
+ # Fetch games update
106
+ #
107
+ # @see https://api.thegamesdb.net/#/Games/GamesUpdates
108
+ #
109
+ # @param last_edit_id [Integer] Required
110
+ # @param time [Integer] (optional)
111
+ # @param page [Integer] results page offset to return (optional)
112
+ # rubocop:disable Metrics/CyclomaticComplexity
113
+ # rubocop:disable Metrics/PerceivedComplexity
114
+ def games_update(last_edit_id, arguments = {})
115
+ url = 'Games/Updates'
116
+ params = arguments.merge({ last_edit_id: last_edit_id })
117
+ data = perform_request(url, params)
118
+
119
+ regexp = /page=([0-9]+)/
120
+ response = {}
121
+ response[:updates] = data['data']['updates']
122
+ response[:previous_page] = data.dig('pages', 'previous')&.match(regexp)&.captures&.first&.to_i
123
+ response[:next_page] = data.dig('pages', 'next')&.match(regexp)&.captures&.first&.to_i
124
+ response
125
+ end
126
+ # rubocop:enable Metrics/AbcSize
127
+ # rubocop:enable Metrics/CyclomaticComplexity
128
+ # rubocop:enable Metrics/PerceivedComplexity
129
+ end
130
+ end