diff --git a/lib/granblue/parsers/suggestion_parser.rb b/lib/granblue/parsers/suggestion_parser.rb index 74d5fc4..bf26d28 100644 --- a/lib/granblue/parsers/suggestion_parser.rb +++ b/lib/granblue/parsers/suggestion_parser.rb @@ -25,8 +25,11 @@ module Granblue # Rarity suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present? - # Element - suggestions[:element] = Wiki.elements[data['element']] if data['element'].present? + # Element - capitalize first letter for case-insensitive lookup + if data['element'].present? + element_key = data['element'].strip.capitalize + suggestions[:element] = Wiki.elements[element_key] + end # Gender suggestions[:gender] = Wiki.genders[data['gender']] if data['gender'].present? @@ -57,14 +60,21 @@ module Granblue 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? + # Series - character series like "grand", "zodiac", etc. + if data['series'].present? + wiki_series = data['series'].to_s.downcase.strip + series_value = Wiki.character_series[wiki_series] + suggestions[:series] = [series_value] if series_value + end + # 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? + # External links - parse URLs to extract values + suggestions[:gamewith] = parse_gamewith_url(data['link_gamewith']) if data['link_gamewith'].present? + suggestions[:kamigame] = parse_kamigame_url(data['link_kamigame'], :character) if data['link_kamigame'].present? suggestions.compact end @@ -83,32 +93,43 @@ module Granblue # Rarity suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present? - # Element - suggestions[:element] = Wiki.elements[data['element']] if data['element'].present? + # Element - capitalize first letter for case-insensitive lookup + if data['element'].present? + element_key = data['element'].strip.capitalize + suggestions[:element] = Wiki.elements[element_key] + end # 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? + # Stats - weapons use hp1/hp2/hp3/hp4 and atk1/atk2/atk3/atk4 + suggestions[:min_hp] = data['hp1'].to_i if data['hp1'].present? + suggestions[:max_hp] = data['hp2'].to_i if data['hp2'].present? + suggestions[:max_hp_flb] = data['hp3'].to_i if data['hp3'].present? + suggestions[:max_hp_ulb] = data['hp4'].to_i if data['hp4'].present? + suggestions[:min_atk] = data['atk1'].to_i if data['atk1'].present? + suggestions[:max_atk] = data['atk2'].to_i if data['atk2'].present? + suggestions[:max_atk_flb] = data['atk3'].to_i if data['atk3'].present? + suggestions[:max_atk_ulb] = data['atk4'].to_i if data['atk4'].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? + # Uncap status - weapons use evo_max (4=FLB, 5=ULB) + if data['evo_max'].present? + evo = data['evo_max'].to_i + suggestions[:flb] = evo >= 4 + suggestions[:ulb] = evo >= 5 + end + + # Series (e.g., "Revenant", "Optimus", etc.) + suggestions[:series] = data['series'] if data['series'].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? + # External links - parse URLs to extract values + suggestions[:gamewith] = parse_gamewith_url(data['link_gamewith']) if data['link_gamewith'].present? + suggestions[:kamigame] = parse_kamigame_url(data['link_kamigame'], :weapon) if data['link_kamigame'].present? # Recruits (character recruited by this weapon) suggestions[:recruits] = data['recruit'] if data['recruit'].present? @@ -131,20 +152,32 @@ module Granblue # Rarity suggestions[:rarity] = Wiki.rarities[data['rarity']] if data['rarity'].present? - # Element - suggestions[:element] = Wiki.elements[data['element']] if data['element'].present? + # Element - capitalize first letter for case-insensitive lookup + if data['element'].present? + element_key = data['element'].strip.capitalize + suggestions[:element] = Wiki.elements[element_key] + 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? + # Stats - summons use hp1/hp2/hp3/hp4/hp5 and atk1/atk2/atk3/atk4/atk5 + suggestions[:min_hp] = data['hp1'].to_i if data['hp1'].present? + suggestions[:max_hp] = data['hp2'].to_i if data['hp2'].present? + suggestions[:max_hp_flb] = data['hp3'].to_i if data['hp3'].present? + suggestions[:max_hp_ulb] = data['hp4'].to_i if data['hp4'].present? + suggestions[:min_atk] = data['atk1'].to_i if data['atk1'].present? + suggestions[:max_atk] = data['atk2'].to_i if data['atk2'].present? + suggestions[:max_atk_flb] = data['atk3'].to_i if data['atk3'].present? + suggestions[:max_atk_ulb] = data['atk4'].to_i if data['atk4'].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? + # Uncap status - summons use evo_max (4=FLB, 5=ULB, 6=transcendence) + if data['evo_max'].present? + evo = data['evo_max'].to_i + suggestions[:flb] = evo >= 4 + suggestions[:ulb] = evo >= 5 + suggestions[:transcendence] = evo >= 6 + end + + # Series (e.g., "Optimus", "Arcarum", etc.) + suggestions[:series] = data['series'] if data['series'].present? # Sub-aura suggestions[:subaura] = Wiki.boolean.fetch(data['subaura'], false) if data['subaura'].present? @@ -154,9 +187,9 @@ module Granblue 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? + # External links - parse URLs to extract values + suggestions[:gamewith] = parse_gamewith_url(data['link_gamewith']) if data['link_gamewith'].present? + suggestions[:kamigame] = parse_kamigame_url(data['link_kamigame'], :summon) if data['link_kamigame'].present? suggestions.compact end @@ -191,6 +224,84 @@ module Granblue rescue ArgumentError, TypeError nil end + + # Parse Gamewith value to extract article ID + # Handles multiple formats: + # - Full URL: https://xn--bck3aza1a2if6kra4ee0hf.gamewith.jp/article/show/519325 + # - Direct numeric ID: 519325 + # - Template syntax: {{{link_gamewith|519325}}} + # Output: "519325" + def self.parse_gamewith_url(value) + return nil if value.blank? + + value = value.to_s.strip + + # Handle MediaWiki template syntax {{{link_gamewith|VALUE}}} + if value =~ /\{\{\{link_gamewith\|(\d+)\}\}\}/ + return $1 + end + + # If it's a full URL, extract the ID + if value =~ /gamewith\.jp\/article\/show\/(\d+)/ + $1 + # If it's already just a numeric ID, return it + elsif value =~ /^\d+$/ + value + end + end + + # Parse Kamigame value to extract Japanese slug + # Handles multiple formats: + # - Full URL: https://kamigame.jp/グラブル/キャラクター/SSR水着リッチ.html + # - Direct Japanese slug: SSR水着リッチ or SSR/アグニス + # - Template syntax: {{{link_kamigame|VALUE}}} + # entity_type: :character, :weapon, :summon + def self.parse_kamigame_url(value, entity_type) + return nil if value.blank? + + value = value.to_s.strip + + # Handle MediaWiki template syntax {{{link_kamigame|VALUE}}} + # This may contain nested templates like {{{jpname|}}} + if value =~ /\{\{\{link_kamigame\|([^}]*)\}\}\}/ + extracted = $1 + # If the extracted value contains nested templates, skip it + return nil if extracted.include?('{{{') + return nil if extracted.blank? + value = extracted + end + + # URL decode to handle percent-encoded Japanese characters + decoded = URI.decode_www_form_component(value) + + # Check if it's a full URL + if decoded.include?('kamigame.jp') + case entity_type + when :character + # https://kamigame.jp/グラブル/キャラクター/SSR水着リッチ.html -> SSR水着リッチ + if decoded =~ /キャラクター\/([^\/]+)\.html$/ + $1 + end + when :weapon + # https://kamigame.jp/グラブル/武器/SSR/ブラインド.html -> ブラインド + if decoded =~ /武器\/(?:SSR|SR|R)\/([^\/]+)\.html$/ + $1 + end + when :summon + # https://kamigame.jp/グラブル/召喚石/SSR/アグニス.html -> SSR/アグニス + if decoded =~ /召喚石\/((?:SSR|SR|R)\/[^\/]+)\.html$/ + $1 + end + end + else + # Assume it's already just the slug value + # Remove .html extension if present + decoded.sub(/\.html$/, '') + end + rescue ArgumentError + # Handle invalid URL encoding + nil + end end end end