gwitch 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d5d7c8e1ed024ba5333231113ae82e55743789dbf45eef7c5d7fd3fdcd50caeb
4
+ data.tar.gz: dc6eba3677e8fcf0ee4038dfc275398b2ddc31e1fd1a70793c7505fc2eb60298
5
+ SHA512:
6
+ metadata.gz: 1e78faf779696cf21b962d04085eb0dea98f14a9c2a9baca056109f12a0c3099c370fb12c43f4e02a74aad7a1b20f8af82a585ce84f7f14ca5be23b587e6bb85
7
+ data.tar.gz: 9f5d471a7c462a01744eafa8560dddc82edb7f8fc864ddd36b6ce450d8741c27d70844c912540ca375048ab96055ee4a81aa567dd1816d2b27f49ab9fad5e0ad
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## [0.0.1](https://github.com/dounx/gwitch/releases/tag/0.0.1) (2020-05-21)
2
+
3
+ * Initial import
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2005-2020 Dounx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Gwitch
2
+
3
+ Gwitch can get switch games info (including price) from nintendo official API.
4
+
5
+ ## Prerequisites
6
+
7
+ * ruby >= 2.3
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ gem install gwitch
13
+ ```
14
+
15
+ Or you can install via Bundler if you are using Rails. Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'gwitch'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ ## Basic Usage
26
+
27
+ ```ruby
28
+ require 'gwitch'
29
+ ```
30
+
31
+ Get all games from americas, asia and europe eshops.
32
+
33
+ ```ruby
34
+ games = Gwitch::Game.all
35
+ ```
36
+
37
+ Get all games from one eshops.
38
+
39
+ ```ruby
40
+ # Americas, Asia and Europe
41
+ games = Gwitch::Game.all('Americas')
42
+ ```
43
+
44
+ Get all avaliable countries.
45
+
46
+ ```ruby
47
+ countries = Gwitch::Country.all
48
+ ```
49
+
50
+ Get country's info.
51
+
52
+ ```ruby
53
+ country = Gwitch::Country.new('US')
54
+ country.alpha2 # => 'US'
55
+ country.region # => 'Americas'
56
+ country.currency # => 'USD'
57
+ ```
58
+
59
+ Query game's price.
60
+
61
+ ```ruby
62
+ price = Gwitch::Game.price('US', 'en', '70010000000141')
63
+ ```
64
+
65
+ ## Build
66
+
67
+ ```bash
68
+ git clone https://github.com/Dounx/gwitch
69
+ cd gwitch
70
+ gem build gwitch.gemspec
71
+ gem install --local gwitch-0.0.1.gem
72
+ ```
73
+
74
+ ## License
75
+
76
+ Gwitch is an open-sourced software licensed under the [MIT license](LICENSE).
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'countries'
4
+ require_relative 'game'
5
+
6
+ module Gwitch
7
+ class Country
8
+ class << self
9
+ # All avaliable countries
10
+ def all
11
+ ISO3166::Country.all.map(&:alpha2).select do |alpha2|
12
+ avaliable?(alpha2)
13
+ end.map { |alpha2| Country.new(alpha2) }
14
+ end
15
+
16
+ private
17
+
18
+ def avaliable?(alpha2)
19
+ # An americas game
20
+ nsuid = '70010000000141'
21
+
22
+ !Game.price(alpha2, nsuid).nil?
23
+ end
24
+ end
25
+
26
+ def initialize(alpha2)
27
+ @country = ISO3166::Country[alpha2]
28
+ end
29
+
30
+ def alpha2
31
+ @country.alpha2
32
+ end
33
+
34
+ def region
35
+ @country.region
36
+ end
37
+
38
+ def currency
39
+ @country.currency_code
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'region'
4
+
5
+ module Gwitch
6
+ class Game
7
+ IdsExceedMaxError = Class.new(StandardError)
8
+
9
+ class << self
10
+ def all(area = nil)
11
+ case area
12
+ when 'Americas'
13
+ Region::Americas.games
14
+ when 'Asia'
15
+ Region::Asia.games
16
+ when 'Europe'
17
+ Region::Europe.games
18
+ else
19
+ Region.games
20
+ end
21
+ end
22
+
23
+ # ids can be String or Array
24
+ def price(alpha2, ids, lang = 'en')
25
+ raise IdsExceedMaxError if ids.is_a?(Array) && ids.size > 50
26
+
27
+ api_url = 'https://api.ec.nintendo.com/v1/price'
28
+ queries = {
29
+ country: alpha2,
30
+ lang: lang,
31
+ ids: ids
32
+ }
33
+
34
+ uri = URI.parse(api_url)
35
+ uri.query = URI.encode_www_form(queries)
36
+
37
+ JSON.parse(uri.read)
38
+ rescue OpenURI::HTTPError
39
+ nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'algoliasearch'
4
+
5
+ module Gwitch
6
+ class Region
7
+
8
+ # A class which get games from americas eshop.
9
+ class Americas
10
+ CLIENT = Algolia::Client.new(
11
+ application_id: 'U3B6GR4UA3',
12
+ api_key: '9a20c93440cf63cf1a7008d75f7438bf'
13
+ )
14
+
15
+ INDEX = CLIENT.init_index('noa_aem_game_en_us')
16
+
17
+ PLATFORM = 'platform:Nintendo Switch'
18
+
19
+ # Trick for API limitation.
20
+ # Nintendo limit each facet can only get 1000 results.
21
+ # So we use as much as possible to get results.
22
+ # Maybe incompletely got.
23
+ # DON'T use this directly.
24
+ # Use filters method.
25
+ FACETS = {
26
+ generalFilters: ['Deals', 'DLC available', 'Demo available', 'Online Play via Nintendo Switch Online', 'Nintendo Switch Game Voucher'],
27
+ availability: ['New releases', 'Available now', 'Pre-purchase', 'Coming soon'],
28
+ categories: ['Action', 'Adventure', 'Application', 'Education', 'Fitness', 'Indie', 'Music', 'Party', 'Puzzle', 'Racing', 'Role-Playing', 'Simulation', 'Sports', 'Strategy'],
29
+ filterShops: ['At retail', 'On Nintendo.com'],
30
+ virtualConsole: ['NES', 'Super NES', 'Game Boy', 'Game Boy Color', 'Nintendo 64', 'Game Boy Advance', 'Nintendo DS', 'Other'],
31
+ characters: ['Mario', 'Zelda', 'Donkey Kong', 'Metroid', 'Pokémon', 'Mii', 'Kirby', 'Animal Crossing'],
32
+ priceRange: ['Free to start', '$0 - $4.99', '$5 - $9.99', '$10 - $19.99', '$20 - $39.99', '$40+'],
33
+ esrb: ['Everyone', 'Everyone 10+', 'Teen', 'Mature'],
34
+ filterPlayers: ['1+', '2+', '3+', '4+']
35
+ }.freeze
36
+
37
+ class << self
38
+ def games
39
+ games = []
40
+
41
+ # No facets
42
+ games += fetch
43
+
44
+ # Each facet
45
+ filters.each do |filter|
46
+ games += fetch(filter)
47
+ end
48
+
49
+ parse(games.uniq)
50
+ end
51
+
52
+ private
53
+
54
+ def fetch(filter = nil)
55
+ hits = []
56
+
57
+ # Empty string means all
58
+ query = ''
59
+
60
+ # histPerPage max can be 500
61
+ search_params = {
62
+ hitsPerPage: 500
63
+ }
64
+
65
+ search_params.merge!(facetFilters: filter) if filter
66
+
67
+ page = 0
68
+
69
+ loop do
70
+ response = INDEX.search(query, search_params.merge(page: page))
71
+ total_pages = response['nbPages']
72
+ hits += response['hits']
73
+ page += 1
74
+
75
+ break unless page < total_pages
76
+ end
77
+
78
+ hits
79
+ end
80
+
81
+ # GalleryParsedError = Class.new
82
+
83
+ def parse(raw)
84
+ host = 'https://www.nintendo.com'
85
+ microsite_host = 'https://assets.nintendo.com/image/upload/f_auto,q_auto,w_960,h_540'
86
+ legacy_host = 'https://assets.nintendo.com/video/upload/f_auto,q_auto,w_960,h_540'
87
+ asset_host = 'https://assets.nintendo.com/image/upload/f_auto,q_auto,w_960,h_540/Legacy%20Videos/posters/'
88
+
89
+ raw.map do |game|
90
+ image_urls = []
91
+ image_urls << (host + game['boxArt']) if game['boxArt']
92
+
93
+ gallery_path = game['gallery']
94
+ if gallery_path.nil?
95
+ nil
96
+ # Begin with '/'
97
+ elsif gallery_path[0] == '/'
98
+ # If prefix is 'content'
99
+ if gallery_path[1] == 'c'
100
+ image_urls << host + gallery_path
101
+ # Prefix is 'Microsites'
102
+ # Just one game
103
+ elsif gallery_path[1] == 'M'
104
+ url = microsite_host + gallery_path
105
+ last_slash = url.rindex('/')
106
+ image_urls << url.insert(last_slash + 1, 'posters/')
107
+ # Prefix is 'Nintendo'
108
+ elsif gallery_path[1] == 'N'
109
+ # TODO Nintendo* url have many situations
110
+ # https://assets.nintendo.com/image/upload/f_auto,q_auto,w_960,h_540/Nintendo Switch/Games/Third Party/Overcooked 2/Video/posters/Overcooked_2_Gourmet_Edition_Trailer
111
+ # /Nintendo Switch/Games/Third Party/Overcooked 2/Video/Overcooked_2_Gourmet_Edition_Trailer
112
+
113
+ # https://assets.nintendo.com/video/upload/f_auto,q_auto,w_960,h_540/Nintendo Switch/Games/NES and Super NES/Video/NES_Super_NES_May_2020_Game_Updates_Nintendo_Switch_Online
114
+ # /Nintendo Switch/Games/NES and Super NES/Video/NES_Super_NES_May_2020_Game_Updates_Nintendo_Switch_Online
115
+ # Prefix is 'Legacy Videos'
116
+ elsif gallery_path[1] == 'L'
117
+ image_urls << legacy_host + gallery_path
118
+ else
119
+ raise GalleryParsedError
120
+ end
121
+ # Just id
122
+ else
123
+ image_urls << asset_host + gallery_path
124
+ end
125
+
126
+ url = game['url'] ? host + game['url'] : nil
127
+
128
+ {
129
+ nsuid: game['nsuid'],
130
+ title: game['title'],
131
+ description: game['description'],
132
+ categories: game['categories'],
133
+ maker: game['publishers']&.join(', '),
134
+ player: game['players'],
135
+ images: image_urls,
136
+ url: url,
137
+ release_at: game['releaseDateMask']
138
+ }
139
+ end
140
+ end
141
+
142
+ def filters
143
+ filters = []
144
+
145
+ FACETS.each do |facet, options|
146
+ options.each do |option|
147
+ filters << [PLATFORM, "#{facet}:#{option}"]
148
+ end
149
+ end
150
+
151
+ filters
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open-uri'
4
+ require 'json'
5
+
6
+ module Gwitch
7
+ class Region
8
+
9
+ # A class which get games from asia eshop.
10
+ class Asia
11
+ API_URL = 'https://search.nintendo.jp/nintendo_soft/search.json'
12
+ QUERIES = {
13
+ opt_sshow: 1,
14
+ opt_osale: 1,
15
+ opt_hard: '1_HAC',
16
+ limit: 300
17
+ }.freeze
18
+
19
+ class << self
20
+ # Get all games from asia eshop.
21
+ def games
22
+ games = []
23
+ uri = URI.parse(API_URL)
24
+ page = 1
25
+
26
+ loop do
27
+ uri.query = URI.encode_www_form(QUERIES.merge(page: page))
28
+
29
+ result = JSON.parse(uri.read)['result']
30
+
31
+ total = result['total']
32
+ games += result['items']
33
+ page += 1
34
+
35
+ break unless games.size < total
36
+ end
37
+
38
+ parse(games)
39
+ end
40
+
41
+ private
42
+
43
+ def parse(raw)
44
+ host = 'https://ec.nintendo.com/JP/ja/titles/'
45
+ image_host = 'https://img-eshop.cdn.nintendo.net/i/'
46
+ image_extension = '.jpg'
47
+
48
+ raw.map do |game|
49
+ modes = []
50
+ modes += game['pmode']&.map { |mode| mode.delete_suffix('_MODE') } || []
51
+
52
+ image_urls = []
53
+ image_urls += game['sslurl']&.map { |id| image_host + id + image_extension } if game['sslurl']
54
+ image_urls << image_host + game['iurl'] + image_extension if game['iurl']
55
+
56
+ url = game['nsuid'] ? host + game['nsuid'] : nil
57
+
58
+ {
59
+ nsuid: game['nsuid'],
60
+ code: game['icode'],
61
+ title: game['title'],
62
+ description: game['text'],
63
+ categories: game['genre'],
64
+ maker: game['maker'],
65
+ player: game['player']&.first,
66
+ languages: game['lang'],
67
+ modes: modes,
68
+ dlcs: game['cnsuid'] || [],
69
+ images: image_urls,
70
+ url: url,
71
+ release_at: game['pdate']
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open-uri'
4
+ require 'json'
5
+
6
+ module Gwitch
7
+ class Region
8
+
9
+ # A class which get games from europe eshop.
10
+ class Europe
11
+ RowsTooSmallError = Class.new(StandardError)
12
+
13
+ API_URL = 'https://search.nintendo-europe.com/en/select'
14
+ MAX_ROWS = 100000
15
+
16
+ # ((playable_on_txt:"HAC")) means platform is nintendo switch
17
+ QUERIES = {
18
+ q: '*',
19
+ fq: '((playable_on_txt:"HAC"))',
20
+ wt: 'json',
21
+ rows: MAX_ROWS,
22
+ start: 0
23
+ }.freeze
24
+
25
+ class << self
26
+ # Get all games from asia eshop.
27
+ def games
28
+ uri = URI.parse(API_URL)
29
+ uri.query = URI.encode_www_form(QUERIES)
30
+ response = JSON.parse(uri.read)['response']
31
+
32
+ raise RowsTooSmallError if response['numFound'] > MAX_ROWS
33
+
34
+ parse(response['docs'])
35
+ end
36
+
37
+ private
38
+
39
+ def parse(raw)
40
+ host = 'https://www.nintendo.co.uk'
41
+ schema = 'https:'
42
+
43
+ raw.map do |game|
44
+ code = game['product_code_txt']&.first
45
+ code = code[4..8] if code
46
+
47
+ modes = []
48
+ modes << 'TV' if game['play_mode_tv_mode_b']
49
+ modes << 'TABLETOP' if game['play_mode_tabletop_mode_b']
50
+ modes << 'HANDHELD' if game['play_mode_handheld_mode_b']
51
+
52
+ url = game['url'] ? host + game['url'] : nil
53
+
54
+ {
55
+ nsuid: game['nsuid_txt'] || [],
56
+ code: code,
57
+ title: game['title'],
58
+ description: game['excerpt'],
59
+ categories: game['pretty_game_categories_txt'] || [],
60
+ maker: game['publisher'],
61
+ player: game['players_to'],
62
+ languages: game['language_availability']&.first&.split(',') || [],
63
+ modes: modes,
64
+ cloud_save: game['cloud_saves_b'],
65
+ images: [
66
+ schema + game['image_url'],
67
+ schema + game['image_url_sq_s'],
68
+ schema + game['image_url_h2x1_s'],
69
+ schema + game['gift_finder_carousel_image_url_s'],
70
+ schema + game['gift_finder_detail_page_image_url_s'],
71
+ schema + game['gift_finder_wishlist_image_url_s'],
72
+ schema + game['wishlist_email_square_image_url_s'],
73
+ schema + game['wishlist_email_banner460w_image_url_s'],
74
+ schema + game['wishlist_email_banner640w_image_url_s']
75
+ ],
76
+ url: url,
77
+ release_at: game['dates_released_dts']&.first
78
+ }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'region/americas'
4
+ require_relative 'region/asia'
5
+ require_relative 'region/europe'
6
+
7
+ module Gwitch
8
+
9
+ # Get all games from americas, asia and europe eshops
10
+ class Region
11
+ def self.games
12
+ Hash[
13
+ [Americas, Asia, Europe].collect do |region|
14
+ [region.name.split('::').last, region.games]
15
+ end
16
+ ]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gwitch
4
+ VERSION = '0.0.1'
5
+ end
data/lib/gwitch.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'gwitch/game'
4
+ require_relative 'gwitch/country'
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gwitch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dounx
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: algoliasearch
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.27'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.27'
27
+ - !ruby/object:Gem::Dependency
28
+ name: countries
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ description: This gem can get switch games info from nintendo official API.
42
+ email: imdounx@gmail.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - CHANGELOG.md
48
+ - LICENSE
49
+ - README.md
50
+ - lib/gwitch.rb
51
+ - lib/gwitch/country.rb
52
+ - lib/gwitch/game.rb
53
+ - lib/gwitch/region.rb
54
+ - lib/gwitch/region/americas.rb
55
+ - lib/gwitch/region/asia.rb
56
+ - lib/gwitch/region/europe.rb
57
+ - lib/gwitch/version.rb
58
+ homepage: https://github.com/dounx/gwitch
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ bug_tracker_uri: https://github.com/dounx/gwitch/issues
63
+ changelog_uri: https://github.com/dounx/gwitch/blob/master/CHANGELOG.md
64
+ documentation_uri: https://github.com/dounx/gwitch/blob/master/README.md
65
+ source_code_uri: https://github.com/dounx/gwitch
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.3.0
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubygems_version: 3.1.2
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Nintendo switch game API.
85
+ test_files: []