diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3560b67..cbe7a37 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception def best_deals - all_games = Game.includes(:prices).by_game_code + all_games = Game.includes(:prices).with_game_code.by_game_code currencies = Price.distinct.pluck(:currency).sort csv = CSV.generate(headers: true) do |rows| diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index 6d552f0..cee0894 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -1,6 +1,6 @@ class GamesController < ApplicationController def index @current_page = 'games' - @games = Game.by_game_code + @games = Game.with_game_code.by_game_code end end diff --git a/app/controllers/prices_controller.rb b/app/controllers/prices_controller.rb index 355c5e5..b56ec1a 100644 --- a/app/controllers/prices_controller.rb +++ b/app/controllers/prices_controller.rb @@ -1,7 +1,7 @@ class PricesController < ApplicationController def index @current_page = 'prices' - @games = Game.includes(:prices).by_game_code + @games = Game.includes(:prices).with_game_code.by_game_code @countries = Price.distinct.pluck(:country).sort @currencies = Price.distinct.pluck(:currency).sort @currency = @currencies.include?(params[:currency]) ? params[:currency] : nil diff --git a/app/models/game.rb b/app/models/game.rb index 239a362..2b4aa47 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -17,6 +17,12 @@ class Game < ApplicationRecord has_many :prices + scope :with_nsuid, -> { where.not(nsuid: nil) } + scope :with_game_code, -> { where.not(game_code: nil) } + scope :from_asia, -> { where(region: 'asia') } + scope :from_americas, -> { where(region: 'americas') } + scope :from_europe, -> { where(region: 'europe') } + scope :order_by_title, -> { order('LOWER(title COLLATE "C")') } scope :order_by_region, lambda { diff --git a/lib/eshop.rb b/lib/eshop.rb index a7b580d..b37aa34 100644 --- a/lib/eshop.rb +++ b/lib/eshop.rb @@ -25,4 +25,6 @@ module Eshop AT AU BE BG CA CH CY CZ DE DK EE ES FI FR GB GR HR HU IE IT JP LT LU LV MT MX NL NO NZ PL PT RO RU SE SI SK US ZA ].freeze + + FIRST_NSUID = 70_010_000_000_000 end diff --git a/lib/eshop/games.rb b/lib/eshop/games.rb index b38bfe0..32bb724 100644 --- a/lib/eshop/games.rb +++ b/lib/eshop/games.rb @@ -1,11 +1,12 @@ require 'httparty' +require_relative 'games/asia' require_relative 'games/americas' require_relative 'games/europe' module Eshop class Games def self.list - Americas.list + Europe.list + Asia.list + Americas.list + Europe.list end end end diff --git a/lib/eshop/games/asia.rb b/lib/eshop/games/asia.rb index 9398c66..44b8180 100644 --- a/lib/eshop/games/asia.rb +++ b/lib/eshop/games/asia.rb @@ -1,12 +1,40 @@ require 'httparty' +require_relative '../../eshop' +require_relative '../../eshop/prices' module Eshop class Games class Asia include HTTParty + URL = 'https://ec.nintendo.com/JP/ja/titles/'.freeze + JSON_REGEX = /NXSTORE\.titleDetail\.jsonData = ([^;]+);/ + def self.list - # TODO + games = [] + guess_new_ids.map do |id| + response = get(URI.join(URL, id)) + next unless response.code == 200 + games << JSON.parse(response.body.scan(JSON_REGEX).last.first, symbolize_names: true) + end + + games.compact.map { |g| coerce(g) } + end + + def self.guess_new_ids + actual_ids = Game.from_asia.with_nsuid.pluck(:nsuid) + ids = (FIRST_NSUID..(FIRST_NSUID + 1_500)).map(&:to_s) - actual_ids + Eshop::Prices.list(country: 'JP', ids: ids).map { |p| p[:nsuid].to_s } + end + + def self.coerce(game) + { + region: 'asia', + title: game[:formal_name], + release_date: Date.parse(game[:release_date_on_eshop]), + nsuid: game[:id], + cover_url: game[:hero_banner_url], + } end end end diff --git a/lib/eshop/prices.rb b/lib/eshop/prices.rb index fc6a2e7..506589c 100644 --- a/lib/eshop/prices.rb +++ b/lib/eshop/prices.rb @@ -12,11 +12,12 @@ class Prices def self.list(country: 'US', ids: [], limit: 50) prices = ids.in_groups_of(limit).flat_map do |ids_to_fetch| + Rails.logger.debug "Retrieving #{ids_to_fetch.count} prices..." query = DEFAULT_PARAMS.merge(country: country, ids: ids_to_fetch.join(',')) response = get(URL, query: query) JSON.parse(response.body, symbolize_names: true)[:prices] end - prices.select! { |p| p.include? :regular_price } + prices.select! { |p| p && p.include?(:regular_price) } prices.map { |price| coerce(price, country) } end diff --git a/lib/tasks/eshop.rake b/lib/tasks/eshop.rake index ca58c50..9c52bfc 100644 --- a/lib/tasks/eshop.rake +++ b/lib/tasks/eshop.rake @@ -4,8 +4,16 @@ namespace :eshop do desc 'Get all games from eShop API' task retrieve_games: :environment do Eshop::Games.list.map do |raw_game| - Game.find_or_create_by!(region: raw_game[:region], game_code: raw_game[:game_code]) - .update_attributes!(raw_game) + if raw_game[:game_code].present? + game = Game.where(region: raw_game[:region]) + .find_or_initialize_by(game_code: raw_game[:game_code]) + elsif raw_game[:nsuid].present? + game = Game.where(region: raw_game[:region]) + .find_or_initialize_by(nsuid: raw_game[:nsuid]) + else + next + end + game.update_attributes!(raw_game) end end