add batch_preview endpoint for entity import
This commit is contained in:
parent
707c0436c5
commit
f5760b1833
6 changed files with 607 additions and 6 deletions
|
|
@ -4,9 +4,10 @@ module Api
|
|||
module V1
|
||||
class CharactersController < Api::V1::ApiController
|
||||
include IdResolvable
|
||||
include BatchPreviewable
|
||||
|
||||
before_action :set, only: %i[show related download_images download_status update]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_images]
|
||||
before_action :set, only: %i[show related download_image download_images download_status update raw fetch_wiki]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_image download_images fetch_wiki batch_preview]
|
||||
|
||||
# GET /characters/:id
|
||||
def show
|
||||
|
|
@ -68,6 +69,53 @@ module Api
|
|||
end
|
||||
end
|
||||
|
||||
# POST /characters/:id/download_image
|
||||
# Synchronously downloads a single image for a character
|
||||
def download_image
|
||||
size = params[:size]
|
||||
transformation = params[:transformation]
|
||||
force = params[:force] == true
|
||||
|
||||
# Validate size
|
||||
valid_sizes = Granblue::Downloaders::CharacterDownloader::SIZES
|
||||
unless valid_sizes.include?(size)
|
||||
return render json: { error: "Invalid size. Must be one of: #{valid_sizes.join(', ')}" }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Validate transformation for characters (01, 02, 03, 04)
|
||||
valid_transformations = %w[01 02 03 04]
|
||||
if transformation.present? && !valid_transformations.include?(transformation)
|
||||
return render json: { error: "Invalid transformation. Must be one of: #{valid_transformations.join(', ')}" }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Build variant ID
|
||||
variant_id = transformation.present? ? "#{@character.granblue_id}_#{transformation}" : "#{@character.granblue_id}_01"
|
||||
|
||||
begin
|
||||
downloader = Granblue::Downloaders::CharacterDownloader.new(
|
||||
@character.granblue_id,
|
||||
storage: :s3,
|
||||
force: force,
|
||||
verbose: true
|
||||
)
|
||||
|
||||
# Call the download_variant method directly for a single variant/size
|
||||
downloader.send(:download_variant, variant_id, size)
|
||||
|
||||
render json: {
|
||||
success: true,
|
||||
character_id: @character.id,
|
||||
granblue_id: @character.granblue_id,
|
||||
size: size,
|
||||
transformation: transformation,
|
||||
message: 'Image downloaded successfully'
|
||||
}
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[CHARACTERS] Image download error for #{@character.id}: #{e.message}"
|
||||
render json: { success: false, error: e.message }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
# POST /characters/:id/download_images
|
||||
# Triggers async image download for a character
|
||||
def download_images
|
||||
|
|
@ -105,6 +153,59 @@ module Api
|
|||
)
|
||||
end
|
||||
|
||||
# GET /characters/:id/raw
|
||||
# Returns raw wiki and game data for database viewing
|
||||
def raw
|
||||
render json: CharacterBlueprint.render(@character, view: :raw)
|
||||
end
|
||||
|
||||
# POST /characters/batch_preview
|
||||
# Fetches wiki data and suggestions for multiple wiki page names
|
||||
def batch_preview
|
||||
wiki_pages = params[:wiki_pages]
|
||||
|
||||
unless wiki_pages.is_a?(Array) && wiki_pages.any?
|
||||
return render json: { error: 'wiki_pages must be a non-empty array' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Limit to 10 pages
|
||||
wiki_pages = wiki_pages.first(10)
|
||||
|
||||
results = wiki_pages.map do |wiki_page|
|
||||
process_wiki_preview(wiki_page, :character)
|
||||
end
|
||||
|
||||
render json: { results: results }
|
||||
end
|
||||
|
||||
# POST /characters/:id/fetch_wiki
|
||||
# Fetches and stores wiki data for this character
|
||||
def fetch_wiki
|
||||
unless @character.wiki_en.present?
|
||||
return render json: { error: 'No wiki page configured for this character' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
begin
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(@character.wiki_en)
|
||||
|
||||
# Handle redirects
|
||||
redirect_match = wiki_text.match(/#REDIRECT \[\[(.*?)\]\]/)
|
||||
if redirect_match
|
||||
redirect_target = redirect_match[1]
|
||||
@character.update!(wiki_en: redirect_target)
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(redirect_target)
|
||||
end
|
||||
|
||||
@character.update!(wiki_raw: wiki_text)
|
||||
render json: CharacterBlueprint.render(@character, view: :raw)
|
||||
rescue Granblue::WikiError => e
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[CHARACTERS] Wiki fetch error for #{@character.id}: #{e.message}"
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ module Api
|
|||
module V1
|
||||
class SummonsController < Api::V1::ApiController
|
||||
include IdResolvable
|
||||
include BatchPreviewable
|
||||
|
||||
before_action :set, only: %i[show download_images download_status update]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_images]
|
||||
before_action :set, only: %i[show download_image download_images download_status update raw fetch_wiki]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_image download_images fetch_wiki batch_preview]
|
||||
|
||||
# GET /summons/:id
|
||||
def show
|
||||
|
|
@ -59,6 +60,53 @@ module Api
|
|||
end
|
||||
end
|
||||
|
||||
# POST /summons/:id/download_image
|
||||
# Synchronously downloads a single image for a summon
|
||||
def download_image
|
||||
size = params[:size]
|
||||
transformation = params[:transformation]
|
||||
force = params[:force] == true
|
||||
|
||||
# Validate size
|
||||
valid_sizes = Granblue::Downloaders::SummonDownloader::SIZES
|
||||
unless valid_sizes.include?(size)
|
||||
return render json: { error: "Invalid size. Must be one of: #{valid_sizes.join(', ')}" }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Validate transformation for summons (none, 02, 03, 04)
|
||||
valid_transformations = [nil, '', '02', '03', '04']
|
||||
if transformation.present? && !valid_transformations.include?(transformation)
|
||||
return render json: { error: 'Invalid transformation. Must be one of: 02, 03, 04 (or empty for base)' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Build variant ID - summons don't have suffix for base
|
||||
variant_id = transformation.present? ? "#{@summon.granblue_id}_#{transformation}" : @summon.granblue_id
|
||||
|
||||
begin
|
||||
downloader = Granblue::Downloaders::SummonDownloader.new(
|
||||
@summon.granblue_id,
|
||||
storage: :s3,
|
||||
force: force,
|
||||
verbose: true
|
||||
)
|
||||
|
||||
# Call the download_variant method directly for a single variant/size
|
||||
downloader.send(:download_variant, variant_id, size)
|
||||
|
||||
render json: {
|
||||
success: true,
|
||||
summon_id: @summon.id,
|
||||
granblue_id: @summon.granblue_id,
|
||||
size: size,
|
||||
transformation: transformation,
|
||||
message: 'Image downloaded successfully'
|
||||
}
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[SUMMONS] Image download error for #{@summon.id}: #{e.message}"
|
||||
render json: { success: false, error: e.message }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
# POST /summons/:id/download_images
|
||||
# Triggers async image download for a summon
|
||||
def download_images
|
||||
|
|
@ -96,6 +144,59 @@ module Api
|
|||
)
|
||||
end
|
||||
|
||||
# GET /summons/:id/raw
|
||||
# Returns raw wiki and game data for database viewing
|
||||
def raw
|
||||
render json: SummonBlueprint.render(@summon, view: :raw)
|
||||
end
|
||||
|
||||
# POST /summons/batch_preview
|
||||
# Fetches wiki data and suggestions for multiple wiki page names
|
||||
def batch_preview
|
||||
wiki_pages = params[:wiki_pages]
|
||||
|
||||
unless wiki_pages.is_a?(Array) && wiki_pages.any?
|
||||
return render json: { error: 'wiki_pages must be a non-empty array' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Limit to 10 pages
|
||||
wiki_pages = wiki_pages.first(10)
|
||||
|
||||
results = wiki_pages.map do |wiki_page|
|
||||
process_wiki_preview(wiki_page, :summon)
|
||||
end
|
||||
|
||||
render json: { results: results }
|
||||
end
|
||||
|
||||
# POST /summons/:id/fetch_wiki
|
||||
# Fetches and stores wiki data for this summon
|
||||
def fetch_wiki
|
||||
unless @summon.wiki_en.present?
|
||||
return render json: { error: 'No wiki page configured for this summon' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
begin
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(@summon.wiki_en)
|
||||
|
||||
# Handle redirects
|
||||
redirect_match = wiki_text.match(/#REDIRECT \[\[(.*?)\]\]/)
|
||||
if redirect_match
|
||||
redirect_target = redirect_match[1]
|
||||
@summon.update!(wiki_en: redirect_target)
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(redirect_target)
|
||||
end
|
||||
|
||||
@summon.update!(wiki_raw: wiki_text)
|
||||
render json: SummonBlueprint.render(@summon, view: :raw)
|
||||
rescue Granblue::WikiError => e
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[SUMMONS] Wiki fetch error for #{@summon.id}: #{e.message}"
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ module Api
|
|||
module V1
|
||||
class WeaponsController < Api::V1::ApiController
|
||||
include IdResolvable
|
||||
include BatchPreviewable
|
||||
|
||||
before_action :set, only: %i[show download_images download_status update]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_images]
|
||||
before_action :set, only: %i[show download_image download_images download_status update raw fetch_wiki]
|
||||
before_action :ensure_editor_role, only: %i[create update validate download_image download_images fetch_wiki batch_preview]
|
||||
|
||||
# GET /weapons/:id
|
||||
def show
|
||||
|
|
@ -59,6 +60,53 @@ module Api
|
|||
end
|
||||
end
|
||||
|
||||
# POST /weapons/:id/download_image
|
||||
# Synchronously downloads a single image for a weapon
|
||||
def download_image
|
||||
size = params[:size]
|
||||
transformation = params[:transformation]
|
||||
force = params[:force] == true
|
||||
|
||||
# Validate size
|
||||
valid_sizes = Granblue::Downloaders::WeaponDownloader::SIZES
|
||||
unless valid_sizes.include?(size)
|
||||
return render json: { error: "Invalid size. Must be one of: #{valid_sizes.join(', ')}" }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Validate transformation for weapons (none, 02, 03)
|
||||
valid_transformations = [nil, '', '02', '03']
|
||||
if transformation.present? && !valid_transformations.include?(transformation)
|
||||
return render json: { error: 'Invalid transformation. Must be one of: 02, 03 (or empty for base)' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Build variant ID - weapons don't have suffix for base
|
||||
variant_id = transformation.present? ? "#{@weapon.granblue_id}_#{transformation}" : @weapon.granblue_id
|
||||
|
||||
begin
|
||||
downloader = Granblue::Downloaders::WeaponDownloader.new(
|
||||
@weapon.granblue_id,
|
||||
storage: :s3,
|
||||
force: force,
|
||||
verbose: true
|
||||
)
|
||||
|
||||
# Call the download_variant method directly for a single variant/size
|
||||
downloader.send(:download_variant, variant_id, size)
|
||||
|
||||
render json: {
|
||||
success: true,
|
||||
weapon_id: @weapon.id,
|
||||
granblue_id: @weapon.granblue_id,
|
||||
size: size,
|
||||
transformation: transformation,
|
||||
message: 'Image downloaded successfully'
|
||||
}
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[WEAPONS] Image download error for #{@weapon.id}: #{e.message}"
|
||||
render json: { success: false, error: e.message }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
# POST /weapons/:id/download_images
|
||||
# Triggers async image download for a weapon
|
||||
def download_images
|
||||
|
|
@ -96,6 +144,59 @@ module Api
|
|||
)
|
||||
end
|
||||
|
||||
# GET /weapons/:id/raw
|
||||
# Returns raw wiki and game data for database viewing
|
||||
def raw
|
||||
render json: WeaponBlueprint.render(@weapon, view: :raw)
|
||||
end
|
||||
|
||||
# POST /weapons/batch_preview
|
||||
# Fetches wiki data and suggestions for multiple wiki page names
|
||||
def batch_preview
|
||||
wiki_pages = params[:wiki_pages]
|
||||
|
||||
unless wiki_pages.is_a?(Array) && wiki_pages.any?
|
||||
return render json: { error: 'wiki_pages must be a non-empty array' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
# Limit to 10 pages
|
||||
wiki_pages = wiki_pages.first(10)
|
||||
|
||||
results = wiki_pages.map do |wiki_page|
|
||||
process_wiki_preview(wiki_page, :weapon)
|
||||
end
|
||||
|
||||
render json: { results: results }
|
||||
end
|
||||
|
||||
# POST /weapons/:id/fetch_wiki
|
||||
# Fetches and stores wiki data for this weapon
|
||||
def fetch_wiki
|
||||
unless @weapon.wiki_en.present?
|
||||
return render json: { error: 'No wiki page configured for this weapon' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
begin
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(@weapon.wiki_en)
|
||||
|
||||
# Handle redirects
|
||||
redirect_match = wiki_text.match(/#REDIRECT \[\[(.*?)\]\]/)
|
||||
if redirect_match
|
||||
redirect_target = redirect_match[1]
|
||||
@weapon.update!(wiki_en: redirect_target)
|
||||
wiki_text = Granblue::Parsers::Wiki.new.fetch(redirect_target)
|
||||
end
|
||||
|
||||
@weapon.update!(wiki_raw: wiki_text)
|
||||
render json: WeaponBlueprint.render(@weapon, view: :raw)
|
||||
rescue Granblue::WikiError => e
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[WEAPONS] Wiki fetch error for #{@weapon.id}: #{e.message}"
|
||||
render json: { error: "Failed to fetch wiki data: #{e.message}" }, status: :bad_gateway
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set
|
||||
|
|
|
|||
91
app/controllers/concerns/batch_previewable.rb
Normal file
91
app/controllers/concerns/batch_previewable.rb
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Provides batch wiki preview functionality for entity controllers
|
||||
module BatchPreviewable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
# Process a single wiki page and return preview data
|
||||
# @param wiki_page [String] The wiki page name to fetch
|
||||
# @param entity_type [Symbol] The type of entity (:character, :weapon, :summon)
|
||||
# @return [Hash] Preview data including status, suggestions, and errors
|
||||
def process_wiki_preview(wiki_page, entity_type)
|
||||
result = {
|
||||
wiki_page: wiki_page,
|
||||
status: 'success'
|
||||
}
|
||||
|
||||
begin
|
||||
# Fetch wiki content
|
||||
wiki = Granblue::Parsers::Wiki.new
|
||||
wiki_text = wiki.fetch(wiki_page)
|
||||
|
||||
# Handle redirects
|
||||
redirect_match = wiki_text.match(/#REDIRECT \[\[(.*?)\]\]/)
|
||||
if redirect_match
|
||||
redirect_target = redirect_match[1]
|
||||
result[:redirected_from] = wiki_page
|
||||
result[:wiki_page] = redirect_target
|
||||
wiki_text = wiki.fetch(redirect_target)
|
||||
end
|
||||
|
||||
result[:wiki_raw] = wiki_text
|
||||
|
||||
# Parse suggestions based on entity type
|
||||
suggestions = case entity_type
|
||||
when :character
|
||||
Granblue::Parsers::SuggestionParser.parse_character(wiki_text)
|
||||
when :weapon
|
||||
Granblue::Parsers::SuggestionParser.parse_weapon(wiki_text)
|
||||
when :summon
|
||||
Granblue::Parsers::SuggestionParser.parse_summon(wiki_text)
|
||||
end
|
||||
|
||||
result[:granblue_id] = suggestions[:granblue_id] if suggestions[:granblue_id].present?
|
||||
result[:suggestions] = suggestions
|
||||
|
||||
# Queue image download if we have a granblue_id
|
||||
if suggestions[:granblue_id].present?
|
||||
result[:image_status] = queue_image_download(suggestions[:granblue_id], entity_type)
|
||||
else
|
||||
result[:image_status] = 'no_id'
|
||||
end
|
||||
rescue Granblue::WikiError => e
|
||||
result[:status] = 'error'
|
||||
result[:error] = "Wiki page not found: #{e.message}"
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[BATCH_PREVIEW] Error processing #{wiki_page}: #{e.message}"
|
||||
result[:status] = 'error'
|
||||
result[:error] = "Failed to process wiki page: #{e.message}"
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# Queue an image download job for the entity
|
||||
# @param granblue_id [String] The granblue ID to download images for
|
||||
# @param entity_type [Symbol] The type of entity
|
||||
# @return [String] Status of the image download ('queued', 'skipped', 'error')
|
||||
def queue_image_download(granblue_id, entity_type)
|
||||
# Check if entity already exists in database
|
||||
model_class = case entity_type
|
||||
when :character then Character
|
||||
when :weapon then Weapon
|
||||
when :summon then Summon
|
||||
end
|
||||
|
||||
existing = model_class.find_by(granblue_id: granblue_id)
|
||||
if existing
|
||||
# Entity exists, skip download (images likely already exist)
|
||||
return 'exists'
|
||||
end
|
||||
|
||||
# For now, we don't queue the download since the entity doesn't exist yet
|
||||
# The image download will happen after the entity is created
|
||||
'pending'
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[BATCH_PREVIEW] Error queueing image download: #{e.message}"
|
||||
'error'
|
||||
end
|
||||
end
|
||||
|
|
@ -15,28 +15,40 @@ Rails.application.routes.draw do
|
|||
resources :weapons, only: %i[show create update] do
|
||||
collection do
|
||||
get 'validate/:granblue_id', action: :validate, as: :validate
|
||||
post 'batch_preview'
|
||||
end
|
||||
member do
|
||||
post 'download_image'
|
||||
post 'download_images'
|
||||
get 'download_status'
|
||||
get 'raw'
|
||||
post 'fetch_wiki'
|
||||
end
|
||||
end
|
||||
resources :characters, only: %i[show create update] do
|
||||
collection do
|
||||
get 'validate/:granblue_id', action: :validate, as: :validate
|
||||
post 'batch_preview'
|
||||
end
|
||||
member do
|
||||
post 'download_image'
|
||||
post 'download_images'
|
||||
get 'download_status'
|
||||
get 'raw'
|
||||
post 'fetch_wiki'
|
||||
end
|
||||
end
|
||||
resources :summons, only: %i[show create update] do
|
||||
collection do
|
||||
get 'validate/:granblue_id', action: :validate, as: :validate
|
||||
post 'batch_preview'
|
||||
end
|
||||
member do
|
||||
post 'download_image'
|
||||
post 'download_images'
|
||||
get 'download_status'
|
||||
get 'raw'
|
||||
post 'fetch_wiki'
|
||||
end
|
||||
end
|
||||
resources :favorites, only: [:create]
|
||||
|
|
|
|||
195
lib/granblue/parsers/suggestion_parser.rb
Normal file
195
lib/granblue/parsers/suggestion_parser.rb
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Granblue
|
||||
module Parsers
|
||||
# SuggestionParser extracts structured suggestions from wiki text
|
||||
# for use in batch entity import flows
|
||||
class SuggestionParser
|
||||
# Parse character wiki text into suggestion fields
|
||||
def self.parse_character(wiki_text)
|
||||
return {} if wiki_text.blank?
|
||||
|
||||
data = parse_wiki_text(wiki_text)
|
||||
|
||||
suggestions = {}
|
||||
suggestions[:name_en] = data['name'] if data['name'].present?
|
||||
suggestions[:name_jp] = data['jpname'] if data['jpname'].present?
|
||||
suggestions[:granblue_id] = data['id'] if data['id'].present?
|
||||
|
||||
# Character ID (for linking related characters)
|
||||
if data['charid'].present?
|
||||
char_ids = data['charid'].scan(/\b\d{4}\b/)
|
||||
suggestions[:character_id] = char_ids if char_ids.any?
|
||||
end
|
||||
|
||||
# Rarity
|
||||
suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present?
|
||||
|
||||
# Element
|
||||
suggestions[:element] = Wiki.elements[data['element']] if data['element'].present?
|
||||
|
||||
# Gender
|
||||
suggestions[:gender] = Wiki.genders[data['gender']] if data['gender'].present?
|
||||
|
||||
# Proficiencies
|
||||
if data['weapon'].present?
|
||||
profs = data['weapon'].split(',').map(&:strip)
|
||||
suggestions[:proficiency1] = Wiki.proficiencies[profs[0]] if profs[0]
|
||||
suggestions[:proficiency2] = Wiki.proficiencies[profs[1]] if profs[1]
|
||||
end
|
||||
|
||||
# Races
|
||||
if data['race'].present?
|
||||
races = data['race'].split(',').map(&:strip)
|
||||
suggestions[:race1] = Wiki.races[races[0]] if races[0]
|
||||
suggestions[:race2] = Wiki.races[races[1]] if races[1]
|
||||
end
|
||||
|
||||
# Stats
|
||||
suggestions[:min_hp] = data['min_hp'].to_i if data['min_hp'].present?
|
||||
suggestions[:max_hp] = data['max_hp'].to_i if data['max_hp'].present?
|
||||
suggestions[:max_hp_flb] = data['flb_hp'].to_i if data['flb_hp'].present?
|
||||
suggestions[:min_atk] = data['min_atk'].to_i if data['min_atk'].present?
|
||||
suggestions[:max_atk] = data['max_atk'].to_i if data['max_atk'].present?
|
||||
suggestions[:max_atk_flb] = data['flb_atk'].to_i if data['flb_atk'].present?
|
||||
|
||||
# Uncap status
|
||||
suggestions[:flb] = Wiki.boolean.fetch(data['5star'], false) if data['5star'].present?
|
||||
suggestions[:ulb] = data['max_evo'].to_i == 6 if data['max_evo'].present?
|
||||
|
||||
# Dates
|
||||
suggestions[:release_date] = parse_date(data['release_date']) if data['release_date'].present?
|
||||
suggestions[:flb_date] = parse_date(data['5star_date']) if data['5star_date'].present?
|
||||
suggestions[:ulb_date] = parse_date(data['6star_date']) if data['6star_date'].present?
|
||||
|
||||
# External links
|
||||
suggestions[:gamewith] = data['link_gamewith'] if data['link_gamewith'].present?
|
||||
suggestions[:kamigame] = data['link_kamigame'] if data['link_kamigame'].present?
|
||||
|
||||
suggestions.compact
|
||||
end
|
||||
|
||||
# Parse weapon wiki text into suggestion fields
|
||||
def self.parse_weapon(wiki_text)
|
||||
return {} if wiki_text.blank?
|
||||
|
||||
data = parse_wiki_text(wiki_text)
|
||||
|
||||
suggestions = {}
|
||||
suggestions[:name_en] = data['name'] if data['name'].present?
|
||||
suggestions[:name_jp] = data['jpname'] if data['jpname'].present?
|
||||
suggestions[:granblue_id] = data['id'] if data['id'].present?
|
||||
|
||||
# Rarity
|
||||
suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present?
|
||||
|
||||
# Element
|
||||
suggestions[:element] = Wiki.elements[data['element']] if data['element'].present?
|
||||
|
||||
# Proficiency (weapon type)
|
||||
suggestions[:proficiency] = Wiki.proficiencies[data['type']] if data['type'].present?
|
||||
|
||||
# Stats
|
||||
suggestions[:min_hp] = data['min_hp'].to_i if data['min_hp'].present?
|
||||
suggestions[:max_hp] = data['max_hp'].to_i if data['max_hp'].present?
|
||||
suggestions[:max_hp_flb] = data['flb_hp'].to_i if data['flb_hp'].present?
|
||||
suggestions[:min_atk] = data['min_atk'].to_i if data['min_atk'].present?
|
||||
suggestions[:max_atk] = data['max_atk'].to_i if data['max_atk'].present?
|
||||
suggestions[:max_atk_flb] = data['flb_atk'].to_i if data['flb_atk'].present?
|
||||
|
||||
# Uncap status
|
||||
suggestions[:flb] = Wiki.boolean.fetch(data['4star'], false) if data['4star'].present?
|
||||
suggestions[:ulb] = Wiki.boolean.fetch(data['5star'], false) if data['5star'].present?
|
||||
|
||||
# Dates
|
||||
suggestions[:release_date] = parse_date(data['release_date']) if data['release_date'].present?
|
||||
suggestions[:flb_date] = parse_date(data['4star_date']) if data['4star_date'].present?
|
||||
suggestions[:ulb_date] = parse_date(data['5star_date']) if data['5star_date'].present?
|
||||
|
||||
# External links
|
||||
suggestions[:gamewith] = data['link_gamewith'] if data['link_gamewith'].present?
|
||||
suggestions[:kamigame] = data['link_kamigame'] if data['link_kamigame'].present?
|
||||
|
||||
# Recruits (character recruited by this weapon)
|
||||
suggestions[:recruits] = data['recruit'] if data['recruit'].present?
|
||||
|
||||
suggestions.compact
|
||||
end
|
||||
|
||||
# Parse summon wiki text into suggestion fields
|
||||
def self.parse_summon(wiki_text)
|
||||
return {} if wiki_text.blank?
|
||||
|
||||
data = parse_wiki_text(wiki_text)
|
||||
|
||||
suggestions = {}
|
||||
suggestions[:name_en] = data['name'] if data['name'].present?
|
||||
suggestions[:name_jp] = data['jpname'] if data['jpname'].present?
|
||||
suggestions[:granblue_id] = data['id'] if data['id'].present?
|
||||
|
||||
# Rarity
|
||||
suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present?
|
||||
|
||||
# Element
|
||||
suggestions[:element] = Wiki.elements[data['element']] if data['element'].present?
|
||||
|
||||
# Stats
|
||||
suggestions[:min_hp] = data['min_hp'].to_i if data['min_hp'].present?
|
||||
suggestions[:max_hp] = data['max_hp'].to_i if data['max_hp'].present?
|
||||
suggestions[:max_hp_flb] = data['flb_hp'].to_i if data['flb_hp'].present?
|
||||
suggestions[:min_atk] = data['min_atk'].to_i if data['min_atk'].present?
|
||||
suggestions[:max_atk] = data['max_atk'].to_i if data['max_atk'].present?
|
||||
suggestions[:max_atk_flb] = data['flb_atk'].to_i if data['flb_atk'].present?
|
||||
|
||||
# Uncap status
|
||||
suggestions[:flb] = Wiki.boolean.fetch(data['4star'], false) if data['4star'].present?
|
||||
suggestions[:ulb] = Wiki.boolean.fetch(data['5star'], false) if data['5star'].present?
|
||||
|
||||
# Sub-aura
|
||||
suggestions[:subaura] = Wiki.boolean.fetch(data['subaura'], false) if data['subaura'].present?
|
||||
|
||||
# Dates
|
||||
suggestions[:release_date] = parse_date(data['release_date']) if data['release_date'].present?
|
||||
suggestions[:flb_date] = parse_date(data['4star_date']) if data['4star_date'].present?
|
||||
suggestions[:ulb_date] = parse_date(data['5star_date']) if data['5star_date'].present?
|
||||
|
||||
# External links
|
||||
suggestions[:gamewith] = data['link_gamewith'] if data['link_gamewith'].present?
|
||||
suggestions[:kamigame] = data['link_kamigame'] if data['link_kamigame'].present?
|
||||
|
||||
suggestions.compact
|
||||
end
|
||||
|
||||
# Parse wiki text into a key-value hash
|
||||
def self.parse_wiki_text(wiki_text)
|
||||
lines = wiki_text.split("\n")
|
||||
data = {}
|
||||
stop_loop = false
|
||||
|
||||
lines.each do |line|
|
||||
next if stop_loop
|
||||
|
||||
# Stop parsing at gameplay notes section
|
||||
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.present?
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
# Parse a date string into a Date object
|
||||
def self.parse_date(date_str)
|
||||
Date.parse(date_str)
|
||||
rescue ArgumentError, TypeError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue