Move app/helpers/granblue_wiki to lib/parsers/wiki

This clears up the namespace beginning with "Granblue"
This commit is contained in:
Justin Edmund 2025-01-17 11:50:56 -08:00
parent 97d811cc29
commit 2242c3d167
12 changed files with 1021 additions and 995 deletions

View file

@ -1,278 +0,0 @@
# frozen_string_literal: true
require 'pry'
# CharacterParser parses character data from gbf.wiki
class CharacterParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@character = Character.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(save: false)
response = fetch_wiki_info
return false if response.nil?
redirect = handle_redirected_string(response)
return fetch(save: save) unless redirect.nil?
handle_fetch_success(response, save)
end
private
# Determines whether or not the response is a redirect
# If it is, it will update the character's wiki_en value
def handle_redirected_string(response)
redirect = extract_redirected_string(response)
return unless redirect
@character.wiki_en = redirect
if @character.save!
ap "Saved new wiki_en value for #{@character.granblue_id}: #{redirect}" if @debug
redirect
else
ap "Unable to save new wiki_en value for #{@character.granblue_id}: #{redirect}" if @debug
nil
end
end
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@character.granblue_id}: Successfully fetched info for #{@character.wiki_en}" if @debug
extracted = parse_string(response)
info = parse(extracted)
persist(info) if save
true
end
# Determines whether the response string
# should be treated as a redirect
def extract_redirected_string(string)
string.match(/#REDIRECT \[\[(.*?)\]\]/)&.captures&.first
end
# Parses the response string into a hash
def parse_string(string)
lines = string.split("\n")
data = {}
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
data[key] = value if value
end
data
end
# Fetches data from the GranblueWiki object
def fetch_wiki_info
@wiki.fetch(@character.wiki_en)
rescue WikiError => e
ap "There was an error fetching #{e.page}: #{e.message}" if @debug
nil
end
# Iterates over all characters in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false)
errors = []
count = Character.count
Character.all.each_with_index do |c, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{c.name_en}... (#{i + 1}/#{count})" if debug
next unless c.release_date.nil? || overwrite
begin
CharacterParser.new(granblue_id: c.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
chara = Character.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{chara.wiki_en}... (#{i + 1}/#{count})" if debug
next unless chara.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: chara.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:id] = hash['id']
info[:charid] = hash['charid'].scan(/\b\d{4}\b/)
info[:flb] = GranblueWiki.boolean.fetch(hash['5star'], false)
info[:ulb] = hash['max_evo'].to_i == 6
info[:rarity] = GranblueWiki.rarities.fetch(hash['rarity'], 0)
info[:element] = GranblueWiki.elements.fetch(hash['element'], 0)
info[:gender] = GranblueWiki.genders.fetch(hash['gender'], 0)
info[:proficiencies] = proficiencies_from_hash(hash['weapon'])
info[:races] = races_from_hash(hash['race'])
info[:hp] = {
min_hp: hash['min_hp'].to_i,
max_hp: hash['max_hp'].to_i,
max_hp_flb: hash['flb_hp'].to_i
}
info[:atk] = {
min_atk: hash['min_atk'].to_i,
max_atk: hash['max_atk'].to_i,
max_atk_flb: hash['flb_atk'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['5star_date']),
ulb_date: parse_date(hash['6star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
info.compact
end
# Saves select fields to the database
def persist(hash)
@character.release_date = hash[:dates][:release_date]
@character.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@character.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@character.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@character.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@character.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @character.save
ap "#{@character.granblue_id}: Successfully saved info for #{@character.name_en}" if @debug
puts
true
end
false
end
# Converts proficiencies from a string to a hash
def proficiencies_from_hash(character)
character.to_s.split(',').map.with_index do |prof, i|
{ "proficiency#{i + 1}" => GranblueWiki.proficiencies[prof] }
end.reduce({}, :merge)
end
# Converts races from a string to a hash
def races_from_hash(race)
race.to_s.split(',').map.with_index do |r, i|
{ "race#{i + 1}" => GranblueWiki.races[r] }
end.reduce({}, :merge)
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
# Unused methods for now
def extract_abilities(hash)
abilities = []
hash.each do |key, value|
next unless key =~ /^a(\d+)_/
ability_number = Regexp.last_match(1).to_i
abilities[ability_number] ||= {}
case key.gsub(/^a\d+_/, '')
when 'cd'
cooldown = parse_substring(value)
abilities[ability_number]['cooldown'] = cooldown
when 'dur'
duration = parse_substring(value)
abilities[ability_number]['duration'] = duration
when 'oblevel'
obtained = parse_substring(value)
abilities[ability_number]['obtained'] = obtained
else
abilities[ability_number][key.gsub(/^a\d+_/, '')] = value
end
end
{ 'abilities' => abilities.compact }
end
def parse_substring(string)
hash = {}
string.scan(/\|([^|=]+?)=([^|]+)/) do |key, value|
value.gsub!(/\}\}$/, '') if value.include?('}}')
hash[key] = value
end
hash
end
def extract_ougis(hash)
ougi = []
hash.each do |key, value|
next unless key =~ /^ougi(\d*)_(.*)/
ougi_number = Regexp.last_match(1)
ougi_key = Regexp.last_match(2)
ougi[ougi_number.to_i] ||= {}
ougi[ougi_number.to_i][ougi_key] = value
end
{ 'ougis' => ougi.compact }
end
end

View file

@ -1,118 +0,0 @@
# frozen_string_literal: true
require 'httparty'
# GranblueWiki fetches and parses data from gbf.wiki
class GranblueWiki
class_attribute :base_uri
class_attribute :proficiencies
class_attribute :elements
class_attribute :rarities
class_attribute :genders
class_attribute :races
class_attribute :bullets
class_attribute :boolean
self.base_uri = 'https://gbf.wiki/api.php'
self.proficiencies = {
'Sabre' => 1,
'Dagger' => 2,
'Axe' => 3,
'Spear' => 4,
'Bow' => 5,
'Staff' => 6,
'Melee' => 7,
'Harp' => 8,
'Gun' => 9,
'Katana' => 10
}.freeze
self.elements = {
'Wind' => 1,
'Fire' => 2,
'Water' => 3,
'Earth' => 4,
'Dark' => 5,
'Light' => 6
}.freeze
self.rarities = {
'R' => 1,
'SR' => 2,
'SSR' => 3
}.freeze
self.races = {
'Other' => 0,
'Human' => 1,
'Erune' => 2,
'Draph' => 3,
'Harvin' => 4,
'Primal' => 5
}.freeze
self.genders = {
'o' => 0,
'm' => 1,
'f' => 2,
'mf' => 3
}.freeze
self.bullets = {
'cartridge' => 1,
'rifle' => 2,
'parabellum' => 3,
'aetherial' => 4
}.freeze
self.boolean = {
'yes' => true,
'no' => false
}.freeze
def initialize(props: ['wikitext'], debug: false)
@debug = debug
@props = props.join('|')
end
def fetch(page)
query_params = params(page).map do |key, value|
"#{key}=#{value}"
end.join('&')
destination = "#{base_uri}?#{query_params}"
ap "--> Fetching #{destination}" if @debug
response = HTTParty.get(destination)
handle_response(response, page)
end
private
def handle_response(response, page)
case response.code
when 200
if response.key?('error')
raise WikiError.new(code: response['error']['code'],
message: response['error']['info'],
page: page)
end
response['parse']['wikitext']['*']
when 404 then puts "Page #{page} not found"
when 500...600 then puts "Server error: #{response.code}"
end
end
def params(page)
{
action: 'parse',
format: 'json',
page: page,
prop: @props
}
end
end

View file

@ -1,251 +0,0 @@
# frozen_string_literal: true
require 'pry'
# SummonParser parses summon data from gbf.wiki
class SummonParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@summon = Summon.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new(debug: debug)
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(name = nil, save: false)
response = fetch_wiki_info(name)
return false if response.nil?
if response.starts_with?('#REDIRECT')
# Fetch the string inside of [[]]
redirect = response[/\[\[(.*?)\]\]/m, 1]
fetch(redirect, save: save)
else
# return response if response[:error]
handle_fetch_success(response, save)
end
end
private
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@summon.granblue_id}: Successfully fetched info for #{@summon.wiki_en}" if @debug
extracted = parse_string(response)
unless extracted[:template].nil?
template = @wiki.fetch("Template:#{extracted[:template]}")
extracted.merge!(parse_string(template))
end
info, skills = parse(extracted)
# ap info
# ap skills
persist(info[:info]) if save
true
end
# Fetches the wiki info from the wiki
# Returns the response body
# Raises an exception if something went wrong
def fetch_wiki_info(name = nil)
@wiki.fetch(name || @summon.wiki_en)
rescue WikiError => e
ap e
# ap "There was an error fetching #{e.page}: #{e.message}" if @debug
{
error: {
name: @summon.wiki_en,
granblue_id: @summon.granblue_id
}
}
end
# Iterates over all summons in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false, start: nil)
errors = []
summons = Summon.all.order(:granblue_id)
start_index = start.nil? ? 0 : summons.index { |w| w.granblue_id == start }
count = summons.drop(start_index).count
# ap "Start index: #{start_index}"
summons.drop(start_index).each_with_index do |w, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{w.wiki_en}... (#{i + 1}/#{count})" if debug
next unless w.release_date.nil? || overwrite
begin
SummonParser.new(granblue_id: w.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
summon = Summon.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{summon.wiki_en}... (#{i + 1}/#{count})" if debug
next unless summon.release_date.nil? || overwrite
begin
SummonParser.new(granblue_id: summon.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the response string into a hash
def parse_string(string)
data = {}
lines = string.split("\n")
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
if line.starts_with?('{{')
substr = line[2..].strip! || line[2..]
# All template tags start with {{ so we can skip the first two characters
disallowed = %w[#vardefine #lsth About]
next if substr.start_with?(*disallowed)
if substr.start_with?('Summon')
ap "--> Found template: #{substr}" if @debug
substr = substr.split('|').first
data[:template] = substr if substr != 'Summon'
next
end
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
regex = /\A\{\{\{.*\|\}\}\}\z/
next if value =~ regex
data[key] = value if value
end
data
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
skills = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:flavor] = { en: hash['flavor'], ja: hash['jpflavor'] }
info[:id] = hash['id']
info[:flb] = hash['evo_max'].to_i >= 4
info[:ulb] = hash['evo_max'].to_i >= 5
info[:transcendence] = hash['evo_max'].to_i == 6
info[:rarity] = rarity_from_hash(hash['rarity'])
info[:series] = hash['series']
info[:obtain] = hash['obtain']
info[:hp] = {
min_hp: hash['hp1'].to_i,
max_hp: hash['hp2'].to_i,
max_hp_flb: hash['hp3'].to_i,
max_hp_ulb: hash['hp4'].to_i.zero? ? nil : hash['hp4'].to_i,
max_hp_xlb: hash['hp5'].to_i.zero? ? nil : hash['hp5'].to_i
}
info[:atk] = {
min_atk: hash['atk1'].to_i,
max_atk: hash['atk2'].to_i,
max_atk_flb: hash['atk3'].to_i,
max_atk_ulb: hash['atk4'].to_i.zero? ? nil : hash['atk4'].to_i,
max_atk_xlb: hash['atk5'].to_i.zero? ? nil : hash['atk5'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['4star_date']),
ulb_date: parse_date(hash['5star_date']),
transcendence_date: parse_date(hash['6star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
{
info: info.compact
# skills: skills.compact
}
end
# Saves select fields to the database
def persist(hash)
@summon.release_date = hash[:dates][:release_date]
@summon.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@summon.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@summon.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@summon.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@summon.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @summon.save
ap "#{@summon.granblue_id}: Successfully saved info for #{@summon.wiki_en}" if @debug
puts
true
end
false
end
# Converts rarities from a string to a hash
def rarity_from_hash(string)
string ? GranblueWiki.rarities[string.upcase] : nil
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
end

View file

@ -1,35 +0,0 @@
# frozen_string_literal: true
class ValidationErrorSerializer
def initialize(record, field, details)
@record = record
@field = field
@details = details
end
def serialize
{
resource: resource,
field: field,
code: code
}
end
private
def resource
@record.class.to_s
end
def field
@field.to_s
end
def code
@details[:error].to_s
end
def underscored_resource_name
@record.class.to_s.gsub('::', '').underscore
end
end

View file

@ -1,17 +0,0 @@
# frozen_string_literal: true
class ValidationErrorsSerializer
attr_reader :record
def initialize(record)
@record = record
end
def serialize
record.errors.details.map do |field, details|
details.map do |error_details|
ValidationErrorSerializer.new(record, field, error_details).serialize
end
end.flatten
end
end

View file

@ -1,296 +0,0 @@
# frozen_string_literal: true
require 'pry'
# WeaponParser parses weapon data from gbf.wiki
class WeaponParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@weapon = Weapon.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new(debug: debug)
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(save: false)
response = fetch_wiki_info
return false if response.nil?
# return response if response[:error]
handle_fetch_success(response, save)
end
private
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@weapon.granblue_id}: Successfully fetched info for #{@weapon.wiki_en}" if @debug
extracted = parse_string(response)
unless extracted[:template].nil?
template = @wiki.fetch("Template:#{extracted[:template]}")
extracted.merge!(parse_string(template))
end
info, skills = parse(extracted)
# ap info
# ap skills
persist(info[:info]) if save
true
end
# Fetches the wiki info from the wiki
# Returns the response body
# Raises an exception if something went wrong
def fetch_wiki_info
@wiki.fetch(@weapon.wiki_en)
rescue WikiError => e
ap e
# ap "There was an error fetching #{e.page}: #{e.message}" if @debug
{
error: {
name: @weapon.wiki_en,
granblue_id: @weapon.granblue_id
}
}
end
# Iterates over all weapons in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false, start: nil)
errors = []
weapons = Weapon.all.order(:granblue_id)
start_index = start.nil? ? 0 : weapons.index { |w| w.granblue_id == start }
count = weapons.drop(start_index).count
# ap "Start index: #{start_index}"
weapons.drop(start_index).each_with_index do |w, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{w.wiki_en}... (#{i + 1}/#{count})" if debug
next if w.wiki_en.include?('Element Changed') || w.wiki_en.include?('Awakened')
next unless w.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: w.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
weapon = Weapon.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{weapon.wiki_en}... (#{i + 1}/#{count})" if debug
next unless weapon.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: weapon.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the response string into a hash
def parse_string(string)
data = {}
lines = string.split("\n")
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
if line.starts_with?('{{')
substr = line[2..].strip! || line[2..]
# All template tags start with {{ so we can skip the first two characters
disallowed = %w[#vardefine #lsth About]
next if substr.start_with?(*disallowed)
if substr.start_with?('Weapon')
ap "--> Found template: #{substr}" if @debug
substr = substr.split('|').first
data[:template] = substr if substr != 'Weapon'
next
end
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
regex = /\A\{\{\{.*\|\}\}\}\z/
next if value =~ regex
data[key] = value if value
end
data
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
skills = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:flavor] = { en: hash['flavor'], ja: hash['jpflavor'] }
info[:id] = hash['id']
info[:flb] = hash['evo_max'].to_i >= 4
info[:ulb] = hash['evo_max'].to_i == 5
info[:rarity] = rarity_from_hash(hash['rarity'])
info[:proficiency] = proficiency_from_hash(hash['weapon'])
info[:series] = hash['series']
info[:obtain] = hash['obtain']
if hash.key?('bullets')
info[:bullets] = {
count: hash['bullets'].to_i,
loadout: [
bullet_from_hash(hash['bullet1']),
bullet_from_hash(hash['bullet2']),
bullet_from_hash(hash['bullet3']),
bullet_from_hash(hash['bullet4']),
bullet_from_hash(hash['bullet5']),
bullet_from_hash(hash['bullet6'])
]
}
end
info[:hp] = {
min_hp: hash['hp1'].to_i,
max_hp: hash['hp2'].to_i,
max_hp_flb: hash['hp3'].to_i,
max_hp_ulb: hash['hp4'].to_i.zero? ? nil : hash['hp4'].to_i
}
info[:atk] = {
min_atk: hash['atk1'].to_i,
max_atk: hash['atk2'].to_i,
max_atk_flb: hash['atk3'].to_i,
max_atk_ulb: hash['atk4'].to_i.zero? ? nil : hash['atk4'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['4star_date']),
ulb_date: parse_date(hash['5star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
skills[:charge_attack] = {
name: { en: hash['ougi_name'], ja: hash['jpougi_name'] },
description: {
mlb: {
en: hash['enougi'],
ja: hash['jpougi']
},
flb: {
en: hash['enougi_4s'],
ja: hash['jpougi_4s']
}
}
}
skills[:skills] = [
{
name: { en: hash['s1_name'], ja: nil },
description: { en: hash['ens1_desc'] || hash['s1_desc'], ja: nil }
},
{
name: { en: hash['s2_name'], ja: nil },
description: { en: hash['ens2_desc'] || hash['s2_desc'], ja: nil }
},
{
name: { en: hash['s3_name'], ja: nil },
description: { en: hash['ens3_desc'] || hash['s3_desc'], ja: nil }
}
]
{
info: info.compact,
skills: skills.compact
}
end
# Saves select fields to the database
def persist(hash)
@weapon.release_date = hash[:dates][:release_date]
@weapon.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@weapon.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@weapon.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@weapon.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@weapon.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @weapon.save
ap "#{@weapon.granblue_id}: Successfully saved info for #{@weapon.wiki_en}" if @debug
puts
true
end
false
end
# Converts rarities from a string to a hash
def rarity_from_hash(string)
string ? GranblueWiki.rarities[string.upcase] : nil
end
# Converts proficiencies from a string to a hash
def proficiency_from_hash(string)
GranblueWiki.proficiencies[string]
end
# Converts a bullet type from a string to a hash
def bullet_from_hash(string)
string ? GranblueWiki.bullets[string] : nil
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
end

View file

@ -0,0 +1,283 @@
# frozen_string_literal: true
require 'pry'
module Granblue
module Parsers
# CharacterParser parses character data from gbf.wiki
class CharacterParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@character = Character.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(save: false)
response = fetch_wiki_info
return false if response.nil?
redirect = handle_redirected_string(response)
return fetch(save: save) unless redirect.nil?
handle_fetch_success(response, save)
end
private
# Determines whether or not the response is a redirect
# If it is, it will update the character's wiki_en value
def handle_redirected_string(response)
redirect = extract_redirected_string(response)
return unless redirect
@character.wiki_en = redirect
if @character.save!
ap "Saved new wiki_en value for #{@character.granblue_id}: #{redirect}" if @debug
redirect
else
ap "Unable to save new wiki_en value for #{@character.granblue_id}: #{redirect}" if @debug
nil
end
end
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@character.granblue_id}: Successfully fetched info for #{@character.wiki_en}" if @debug
extracted = parse_string(response)
info = parse(extracted)
persist(info) if save
true
end
# Determines whether the response string
# should be treated as a redirect
def extract_redirected_string(string)
string.match(/#REDIRECT \[\[(.*?)\]\]/)&.captures&.first
end
# Parses the response string into a hash
def parse_string(string)
lines = string.split("\n")
data = {}
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
data[key] = value if value
end
data
end
# Fetches data from the GranblueWiki object
def fetch_wiki_info
@wiki.fetch(@character.wiki_en)
rescue WikiError => e
ap "There was an error fetching #{e.page}: #{e.message}" if @debug
nil
end
# Iterates over all characters in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false)
errors = []
count = Character.count
Character.all.each_with_index do |c, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{c.name_en}... (#{i + 1}/#{count})" if debug
next unless c.release_date.nil? || overwrite
begin
CharacterParser.new(granblue_id: c.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
chara = Character.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{chara.wiki_en}... (#{i + 1}/#{count})" if debug
next unless chara.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: chara.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:id] = hash['id']
info[:charid] = hash['charid'].scan(/\b\d{4}\b/)
info[:flb] = GranblueWiki.boolean.fetch(hash['5star'], false)
info[:ulb] = hash['max_evo'].to_i == 6
info[:rarity] = GranblueWiki.rarities.fetch(hash['rarity'], 0)
info[:element] = GranblueWiki.elements.fetch(hash['element'], 0)
info[:gender] = GranblueWiki.genders.fetch(hash['gender'], 0)
info[:proficiencies] = proficiencies_from_hash(hash['weapon'])
info[:races] = races_from_hash(hash['race'])
info[:hp] = {
min_hp: hash['min_hp'].to_i,
max_hp: hash['max_hp'].to_i,
max_hp_flb: hash['flb_hp'].to_i
}
info[:atk] = {
min_atk: hash['min_atk'].to_i,
max_atk: hash['max_atk'].to_i,
max_atk_flb: hash['flb_atk'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['5star_date']),
ulb_date: parse_date(hash['6star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
info.compact
end
# Saves select fields to the database
def persist(hash)
@character.release_date = hash[:dates][:release_date]
@character.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@character.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@character.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@character.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@character.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @character.save
ap "#{@character.granblue_id}: Successfully saved info for #{@character.name_en}" if @debug
puts
true
end
false
end
# Converts proficiencies from a string to a hash
def proficiencies_from_hash(character)
character.to_s.split(',').map.with_index do |prof, i|
{ "proficiency#{i + 1}" => GranblueWiki.proficiencies[prof] }
end.reduce({}, :merge)
end
# Converts races from a string to a hash
def races_from_hash(race)
race.to_s.split(',').map.with_index do |r, i|
{ "race#{i + 1}" => GranblueWiki.races[r] }
end.reduce({}, :merge)
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
# Unused methods for now
def extract_abilities(hash)
abilities = []
hash.each do |key, value|
next unless key =~ /^a(\d+)_/
ability_number = Regexp.last_match(1).to_i
abilities[ability_number] ||= {}
case key.gsub(/^a\d+_/, '')
when 'cd'
cooldown = parse_substring(value)
abilities[ability_number]['cooldown'] = cooldown
when 'dur'
duration = parse_substring(value)
abilities[ability_number]['duration'] = duration
when 'oblevel'
obtained = parse_substring(value)
abilities[ability_number]['obtained'] = obtained
else
abilities[ability_number][key.gsub(/^a\d+_/, '')] = value
end
end
{ 'abilities' => abilities.compact }
end
def parse_substring(string)
hash = {}
string.scan(/\|([^|=]+?)=([^|]+)/) do |key, value|
value.gsub!(/\}\}$/, '') if value.include?('}}')
hash[key] = value
end
hash
end
def extract_ougis(hash)
ougi = []
hash.each do |key, value|
next unless key =~ /^ougi(\d*)_(.*)/
ougi_number = Regexp.last_match(1)
ougi_key = Regexp.last_match(2)
ougi[ougi_number.to_i] ||= {}
ougi[ougi_number.to_i][ougi_key] = value
end
{ 'ougis' => ougi.compact }
end
end
end
end

View file

@ -0,0 +1,255 @@
# frozen_string_literal: true
require 'pry'
module Granblue
module Parsers
# SummonParser parses summon data from gbf.wiki
class SummonParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@summon = Summon.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new(debug: debug)
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(name = nil, save: false)
response = fetch_wiki_info(name)
return false if response.nil?
if response.starts_with?('#REDIRECT')
# Fetch the string inside of [[]]
redirect = response[/\[\[(.*?)\]\]/m, 1]
fetch(redirect, save: save)
else
# return response if response[:error]
handle_fetch_success(response, save)
end
end
private
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@summon.granblue_id}: Successfully fetched info for #{@summon.wiki_en}" if @debug
extracted = parse_string(response)
unless extracted[:template].nil?
template = @wiki.fetch("Template:#{extracted[:template]}")
extracted.merge!(parse_string(template))
end
info, skills = parse(extracted)
# ap info
# ap skills
persist(info[:info]) if save
true
end
# Fetches the wiki info from the wiki
# Returns the response body
# Raises an exception if something went wrong
def fetch_wiki_info(name = nil)
@wiki.fetch(name || @summon.wiki_en)
rescue WikiError => e
ap e
# ap "There was an error fetching #{e.page}: #{e.message}" if @debug
{
error: {
name: @summon.wiki_en,
granblue_id: @summon.granblue_id
}
}
end
# Iterates over all summons in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false, start: nil)
errors = []
summons = Summon.all.order(:granblue_id)
start_index = start.nil? ? 0 : summons.index { |w| w.granblue_id == start }
count = summons.drop(start_index).count
# ap "Start index: #{start_index}"
summons.drop(start_index).each_with_index do |w, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{w.wiki_en}... (#{i + 1}/#{count})" if debug
next unless w.release_date.nil? || overwrite
begin
SummonParser.new(granblue_id: w.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
summon = Summon.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{summon.wiki_en}... (#{i + 1}/#{count})" if debug
next unless summon.release_date.nil? || overwrite
begin
SummonParser.new(granblue_id: summon.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the response string into a hash
def parse_string(string)
data = {}
lines = string.split("\n")
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
if line.starts_with?('{{')
substr = line[2..].strip! || line[2..]
# All template tags start with {{ so we can skip the first two characters
disallowed = %w[#vardefine #lsth About]
next if substr.start_with?(*disallowed)
if substr.start_with?('Summon')
ap "--> Found template: #{substr}" if @debug
substr = substr.split('|').first
data[:template] = substr if substr != 'Summon'
next
end
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
regex = /\A\{\{\{.*\|\}\}\}\z/
next if value =~ regex
data[key] = value if value
end
data
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
skills = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:flavor] = { en: hash['flavor'], ja: hash['jpflavor'] }
info[:id] = hash['id']
info[:flb] = hash['evo_max'].to_i >= 4
info[:ulb] = hash['evo_max'].to_i >= 5
info[:transcendence] = hash['evo_max'].to_i == 6
info[:rarity] = rarity_from_hash(hash['rarity'])
info[:series] = hash['series']
info[:obtain] = hash['obtain']
info[:hp] = {
min_hp: hash['hp1'].to_i,
max_hp: hash['hp2'].to_i,
max_hp_flb: hash['hp3'].to_i,
max_hp_ulb: hash['hp4'].to_i.zero? ? nil : hash['hp4'].to_i,
max_hp_xlb: hash['hp5'].to_i.zero? ? nil : hash['hp5'].to_i
}
info[:atk] = {
min_atk: hash['atk1'].to_i,
max_atk: hash['atk2'].to_i,
max_atk_flb: hash['atk3'].to_i,
max_atk_ulb: hash['atk4'].to_i.zero? ? nil : hash['atk4'].to_i,
max_atk_xlb: hash['atk5'].to_i.zero? ? nil : hash['atk5'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['4star_date']),
ulb_date: parse_date(hash['5star_date']),
transcendence_date: parse_date(hash['6star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
{
info: info.compact
# skills: skills.compact
}
end
# Saves select fields to the database
def persist(hash)
@summon.release_date = hash[:dates][:release_date]
@summon.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@summon.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@summon.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@summon.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@summon.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @summon.save
ap "#{@summon.granblue_id}: Successfully saved info for #{@summon.wiki_en}" if @debug
puts
true
end
false
end
# Converts rarities from a string to a hash
def rarity_from_hash(string)
string ? GranblueWiki.rarities[string.upcase] : nil
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
end
end
end

View file

@ -0,0 +1,39 @@
# frozen_string_literal: true
module Granblue
module Parsers
class ValidationErrorSerializer
def initialize(record, field, details)
@record = record
@field = field
@details = details
end
def serialize
{
resource: resource,
field: field,
code: code
}
end
private
def resource
@record.class.to_s
end
def field
@field.to_s
end
def code
@details[:error].to_s
end
def underscored_resource_name
@record.class.to_s.gsub('::', '').underscore
end
end
end
end

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Granblue
module Parsers
class ValidationErrorsSerializer
attr_reader :record
def initialize(record)
@record = record
end
def serialize
record.errors.details.map do |field, details|
details.map do |error_details|
ValidationErrorSerializer.new(record, field, error_details).serialize
end
end.flatten
end
end
end
end

View file

@ -0,0 +1,300 @@
# frozen_string_literal: true
require 'pry'
module Granblue
module Parsers
# WeaponParser parses weapon data from gbf.wiki
class WeaponParser
attr_reader :granblue_id
def initialize(granblue_id: String, debug: false)
@weapon = Weapon.find_by(granblue_id: granblue_id)
@wiki = GranblueWiki.new(debug: debug)
@debug = debug || false
end
# Fetches using @wiki and then processes the response
# Returns true if successful, false if not
# Raises an exception if something went wrong
def fetch(save: false)
response = fetch_wiki_info
return false if response.nil?
# return response if response[:error]
handle_fetch_success(response, save)
end
private
# Handle the response from the wiki if the response is successful
# If the save flag is set, it will persist the data to the database
def handle_fetch_success(response, save)
ap "#{@weapon.granblue_id}: Successfully fetched info for #{@weapon.wiki_en}" if @debug
extracted = parse_string(response)
unless extracted[:template].nil?
template = @wiki.fetch("Template:#{extracted[:template]}")
extracted.merge!(parse_string(template))
end
info, skills = parse(extracted)
# ap info
# ap skills
persist(info[:info]) if save
true
end
# Fetches the wiki info from the wiki
# Returns the response body
# Raises an exception if something went wrong
def fetch_wiki_info
@wiki.fetch(@weapon.wiki_en)
rescue WikiError => e
ap e
# ap "There was an error fetching #{e.page}: #{e.message}" if @debug
{
error: {
name: @weapon.wiki_en,
granblue_id: @weapon.granblue_id
}
}
end
# Iterates over all weapons in the database and fetches their data
# If the save flag is set, data is saved to the database
# If the overwrite flag is set, data is fetched even if it already exists
# If the debug flag is set, additional information is printed to the console
def self.fetch_all(save: false, overwrite: false, debug: false, start: nil)
errors = []
weapons = Weapon.all.order(:granblue_id)
start_index = start.nil? ? 0 : weapons.index { |w| w.granblue_id == start }
count = weapons.drop(start_index).count
# ap "Start index: #{start_index}"
weapons.drop(start_index).each_with_index do |w, i|
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{w.wiki_en}... (#{i + 1}/#{count})" if debug
next if w.wiki_en.include?('Element Changed') || w.wiki_en.include?('Awakened')
next unless w.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: w.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
def self.fetch_list(list: [], save: false, overwrite: false, debug: false, start: nil)
errors = []
start_index = start.nil? ? 0 : list.index { |id| id == start }
count = list.drop(start_index).count
# ap "Start index: #{start_index}"
list.drop(start_index).each_with_index do |id, i|
weapon = Weapon.find_by(granblue_id: id)
percentage = ((i + 1) / count.to_f * 100).round(2)
ap "#{percentage}%: Fetching #{weapon.wiki_en}... (#{i + 1}/#{count})" if debug
next unless weapon.release_date.nil? || overwrite
begin
WeaponParser.new(granblue_id: weapon.granblue_id,
debug: debug).fetch(save: save)
rescue WikiError => e
errors.push(e.page)
end
end
ap 'The following pages were unable to be fetched:'
ap errors
end
# Parses the response string into a hash
def parse_string(string)
data = {}
lines = string.split("\n")
stop_loop = false
lines.each do |line|
next if stop_loop
if line.include?('Gameplay Notes')
stop_loop = true
next
end
if line.starts_with?('{{')
substr = line[2..].strip! || line[2..]
# All template tags start with {{ so we can skip the first two characters
disallowed = %w[#vardefine #lsth About]
next if substr.start_with?(*disallowed)
if substr.start_with?('Weapon')
ap "--> Found template: #{substr}" if @debug
substr = substr.split('|').first
data[:template] = substr if substr != 'Weapon'
next
end
end
next unless line[0] == '|' && line.size > 2
key, value = line[1..].split('=', 2).map(&:strip)
regex = /\A\{\{\{.*\|\}\}\}\z/
next if value =~ regex
data[key] = value if value
end
data
end
# Parses the hash into a format that can be saved to the database
def parse(hash)
info = {}
skills = {}
info[:name] = { en: hash['name'], ja: hash['jpname'] }
info[:flavor] = { en: hash['flavor'], ja: hash['jpflavor'] }
info[:id] = hash['id']
info[:flb] = hash['evo_max'].to_i >= 4
info[:ulb] = hash['evo_max'].to_i == 5
info[:rarity] = rarity_from_hash(hash['rarity'])
info[:proficiency] = proficiency_from_hash(hash['weapon'])
info[:series] = hash['series']
info[:obtain] = hash['obtain']
if hash.key?('bullets')
info[:bullets] = {
count: hash['bullets'].to_i,
loadout: [
bullet_from_hash(hash['bullet1']),
bullet_from_hash(hash['bullet2']),
bullet_from_hash(hash['bullet3']),
bullet_from_hash(hash['bullet4']),
bullet_from_hash(hash['bullet5']),
bullet_from_hash(hash['bullet6'])
]
}
end
info[:hp] = {
min_hp: hash['hp1'].to_i,
max_hp: hash['hp2'].to_i,
max_hp_flb: hash['hp3'].to_i,
max_hp_ulb: hash['hp4'].to_i.zero? ? nil : hash['hp4'].to_i
}
info[:atk] = {
min_atk: hash['atk1'].to_i,
max_atk: hash['atk2'].to_i,
max_atk_flb: hash['atk3'].to_i,
max_atk_ulb: hash['atk4'].to_i.zero? ? nil : hash['atk4'].to_i
}
info[:dates] = {
release_date: parse_date(hash['release_date']),
flb_date: parse_date(hash['4star_date']),
ulb_date: parse_date(hash['5star_date'])
}
info[:links] = {
wiki: { en: hash['name'], ja: hash['link_jpwiki'] },
gamewith: hash['link_gamewith'],
kamigame: hash['link_kamigame']
}
skills[:charge_attack] = {
name: { en: hash['ougi_name'], ja: hash['jpougi_name'] },
description: {
mlb: {
en: hash['enougi'],
ja: hash['jpougi']
},
flb: {
en: hash['enougi_4s'],
ja: hash['jpougi_4s']
}
}
}
skills[:skills] = [
{
name: { en: hash['s1_name'], ja: nil },
description: { en: hash['ens1_desc'] || hash['s1_desc'], ja: nil }
},
{
name: { en: hash['s2_name'], ja: nil },
description: { en: hash['ens2_desc'] || hash['s2_desc'], ja: nil }
},
{
name: { en: hash['s3_name'], ja: nil },
description: { en: hash['ens3_desc'] || hash['s3_desc'], ja: nil }
}
]
{
info: info.compact,
skills: skills.compact
}
end
# Saves select fields to the database
def persist(hash)
@weapon.release_date = hash[:dates][:release_date]
@weapon.flb_date = hash[:dates][:flb_date] if hash[:dates].key?(:flb_date)
@weapon.ulb_date = hash[:dates][:ulb_date] if hash[:dates].key?(:ulb_date)
@weapon.wiki_ja = hash[:links][:wiki][:ja] if hash[:links].key?(:wiki) && hash[:links][:wiki].key?(:ja)
@weapon.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith)
@weapon.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame)
if @weapon.save
ap "#{@weapon.granblue_id}: Successfully saved info for #{@weapon.wiki_en}" if @debug
puts
true
end
false
end
# Converts rarities from a string to a hash
def rarity_from_hash(string)
string ? GranblueWiki.rarities[string.upcase] : nil
end
# Converts proficiencies from a string to a hash
def proficiency_from_hash(string)
GranblueWiki.proficiencies[string]
end
# Converts a bullet type from a string to a hash
def bullet_from_hash(string)
string ? GranblueWiki.bullets[string] : nil
end
# Parses a date string into a Date object
def parse_date(date_str)
Date.parse(date_str) unless date_str.blank?
end
end
end
end

View file

@ -0,0 +1,122 @@
# frozen_string_literal: true
require 'httparty'
# GranblueWiki fetches and parses data from gbf.wiki
module Granblue
module Parsers
class Wiki
class_attribute :base_uri
class_attribute :proficiencies
class_attribute :elements
class_attribute :rarities
class_attribute :genders
class_attribute :races
class_attribute :bullets
class_attribute :boolean
self.base_uri = 'https://gbf.wiki/api.php'
self.proficiencies = {
'Sabre' => 1,
'Dagger' => 2,
'Axe' => 3,
'Spear' => 4,
'Bow' => 5,
'Staff' => 6,
'Melee' => 7,
'Harp' => 8,
'Gun' => 9,
'Katana' => 10
}.freeze
self.elements = {
'Wind' => 1,
'Fire' => 2,
'Water' => 3,
'Earth' => 4,
'Dark' => 5,
'Light' => 6
}.freeze
self.rarities = {
'R' => 1,
'SR' => 2,
'SSR' => 3
}.freeze
self.races = {
'Other' => 0,
'Human' => 1,
'Erune' => 2,
'Draph' => 3,
'Harvin' => 4,
'Primal' => 5
}.freeze
self.genders = {
'o' => 0,
'm' => 1,
'f' => 2,
'mf' => 3
}.freeze
self.bullets = {
'cartridge' => 1,
'rifle' => 2,
'parabellum' => 3,
'aetherial' => 4
}.freeze
self.boolean = {
'yes' => true,
'no' => false
}.freeze
def initialize(props: ['wikitext'], debug: false)
@debug = debug
@props = props.join('|')
end
def fetch(page)
query_params = params(page).map do |key, value|
"#{key}=#{value}"
end.join('&')
destination = "#{base_uri}?#{query_params}"
ap "--> Fetching #{destination}" if @debug
response = HTTParty.get(destination)
handle_response(response, page)
end
private
def handle_response(response, page)
case response.code
when 200
if response.key?('error')
raise WikiError.new(code: response['error']['code'],
message: response['error']['info'],
page: page)
end
response['parse']['wikitext']['*']
when 404 then puts "Page #{page} not found"
when 500...600 then puts "Server error: #{response.code}"
end
end
def params(page)
{
action: 'parse',
format: 'json',
page: page,
prop: @props
}
end
end
end
end