|
|
|
@ -1,10 +1,13 @@ |
|
|
|
from typing import Optional |
|
|
|
from PyQt6.QtCore import QObject, pyqtSignal, QRunnable |
|
|
|
from bs4 import BeautifulSoup, Tag |
|
|
|
from fuzzywuzzy import fuzz |
|
|
|
from cache import cache |
|
|
|
from db import db |
|
|
|
|
|
|
|
from utility.functions import get_form_name, get_display_name |
|
|
|
import re |
|
|
|
|
|
|
|
from utility.functions import get_form_name, get_display_name, parse_pfic |
|
|
|
|
|
|
|
class GatherEvolutionsWorkerSignals(QObject): |
|
|
|
finished = pyqtSignal(list) |
|
|
|
@ -22,23 +25,50 @@ class GatherEvolutions(QRunnable): |
|
|
|
except Exception as e: |
|
|
|
print(f"Error gathering Pokémon home storage status: {e}") |
|
|
|
|
|
|
|
def gather_evolution_data(self): |
|
|
|
def gather_evolution_data(self, force_refresh = False): |
|
|
|
all_pokemon_forms = db.get_list_of_pokemon_forms() |
|
|
|
evolutions = [] |
|
|
|
|
|
|
|
for pokemon_form in all_pokemon_forms: |
|
|
|
print(f"Processing {get_display_name(pokemon_form)}'s evolutions") |
|
|
|
url = f"https://bulbapedia.bulbagarden.net/wiki/{pokemon_form["name"]}_(Pokémon)" |
|
|
|
pokemon_name = pokemon_form["name"] |
|
|
|
form = get_form_name(pokemon_form) |
|
|
|
|
|
|
|
cache_record_name = f"chain_{pokemon_name}_{form}" |
|
|
|
if force_refresh: |
|
|
|
cache.purge(cache_record_name) |
|
|
|
|
|
|
|
cached_entry = cache.get(cache_record_name) |
|
|
|
if cached_entry != None: |
|
|
|
evolutions.extend(cached_entry) |
|
|
|
continue |
|
|
|
|
|
|
|
#form = get_form_name(pokemon_form, not pokemon_form["gender_relevant"]) |
|
|
|
search_form = form |
|
|
|
if search_form and pokemon_name in search_form: |
|
|
|
search_form = search_form.replace(pokemon_name, "").strip() |
|
|
|
|
|
|
|
gender = None |
|
|
|
if search_form and "male" in search_form.lower(): |
|
|
|
gender = search_form |
|
|
|
search_form = None |
|
|
|
|
|
|
|
if pokemon_name == "Flabébé": |
|
|
|
# Bulbapedia doesn't detail out Flabébé's evolution chain fully. as its exactly the same for each form, but the coloured form remains constant |
|
|
|
# through the evolution line, Red->Red->Red, Yellow->Yellow->Yellow etc. |
|
|
|
search_form = None |
|
|
|
|
|
|
|
url = f"https://bulbapedia.bulbagarden.net/wiki/{pokemon_name}_(Pokémon)" |
|
|
|
page_data = cache.fetch_url(url) |
|
|
|
if not page_data: |
|
|
|
continue |
|
|
|
|
|
|
|
soup = BeautifulSoup(page_data, 'html.parser') |
|
|
|
evolution_section = soup.find('span', id='Evolution_data') |
|
|
|
if not evolution_section: |
|
|
|
continue |
|
|
|
|
|
|
|
evolution_table = None |
|
|
|
form = get_form_name(pokemon_form, not pokemon_form["gender_relevant"]) |
|
|
|
pokemon_name = pokemon_form["name"] |
|
|
|
evolution_table = evolution_section.parent.find_next('table') |
|
|
|
if form: |
|
|
|
form_without_form = form.replace('Form', '').replace('form', '').strip() |
|
|
|
@ -51,12 +81,54 @@ class GatherEvolutions(QRunnable): |
|
|
|
if not evolution_table: |
|
|
|
continue |
|
|
|
|
|
|
|
evolution_chain = [] |
|
|
|
if pokemon_name == "Eevee": |
|
|
|
evolution_chain = self.parse_eevee_evolution_chain(evolution_table, pokemon_form) |
|
|
|
evolutions.append(evolution_chain) |
|
|
|
#evolutions.append(evolution_chain) |
|
|
|
else: |
|
|
|
evolution_chain = self.parse_evolution_chain(evolution_table, pokemon_form) |
|
|
|
evolutions.append(evolution_chain) |
|
|
|
#evolutions.append(evolution_chain) |
|
|
|
|
|
|
|
chain = [] |
|
|
|
for pokemon in evolution_chain: |
|
|
|
from_pfic = self.get_pokemon_form_by_name(pokemon["pokemon"], pokemon["form"], gender=gender) |
|
|
|
if not from_pfic: |
|
|
|
#logger.warning(f"Could not find PFIC for {stage.pokemon} {stage.form}") |
|
|
|
continue |
|
|
|
|
|
|
|
stage = pokemon["next_stage"] |
|
|
|
if stage: |
|
|
|
to_pfic = self.get_pokemon_form_by_name(stage["pokemon"], stage["form"], gender=gender) |
|
|
|
if to_pfic: |
|
|
|
evolution_info = { |
|
|
|
"from_pfic": from_pfic, |
|
|
|
"to_pfic": to_pfic, |
|
|
|
"method": stage["method"] |
|
|
|
} |
|
|
|
evolutions.append(evolution_info) |
|
|
|
chain.append(evolution_info) |
|
|
|
|
|
|
|
#insert_evolution_info(evolution_info) |
|
|
|
|
|
|
|
#if "breed" in stage["next_stage"]["method"].lower(): |
|
|
|
# update_pokemon_baby_status(from_pfic, True) |
|
|
|
|
|
|
|
for branch in pokemon["branches"]: |
|
|
|
to_pfic = self.get_pokemon_form_by_name(branch["pokemon"], branch["form"], gender=gender) |
|
|
|
if to_pfic: |
|
|
|
evolution_info = { |
|
|
|
"from_pfic": from_pfic, |
|
|
|
"to_pfic": to_pfic, |
|
|
|
"method": branch["method"] |
|
|
|
} |
|
|
|
evolutions.append(evolution_info) |
|
|
|
chain.append(evolution_info) |
|
|
|
#EvolutionInfo(from_pfic, to_pfic, branch.method) |
|
|
|
#insert_evolution_info(evolution_info) |
|
|
|
|
|
|
|
#if "breed" in branch.method.lower(): |
|
|
|
# update_pokemon_baby_status(from_pfic, True) |
|
|
|
cache.set(cache_record_name, chain) |
|
|
|
|
|
|
|
return evolutions |
|
|
|
|
|
|
|
@ -234,3 +306,57 @@ class GatherEvolutions(QRunnable): |
|
|
|
stage = self.extract_stage_form(td) |
|
|
|
return pokemon_name, stage |
|
|
|
return None, None |
|
|
|
|
|
|
|
def get_pokemon_form_by_name(self, name: str, form: Optional[str] = None, threshold: int = 80, gender: Optional[str] = None): |
|
|
|
fields = [ |
|
|
|
"pfic", |
|
|
|
"name", |
|
|
|
"form_name" |
|
|
|
] |
|
|
|
results = db.get_pokemon_details_by_name(name, fields) |
|
|
|
#results = db_controller.execute_query('SELECT PFIC, name, form_name FROM pokemon_forms WHERE name = ?', (name,)) |
|
|
|
|
|
|
|
if not results: |
|
|
|
return None |
|
|
|
|
|
|
|
results.sort(key=lambda x: parse_pfic(x["pfic"])) |
|
|
|
|
|
|
|
if form is None and gender is None: |
|
|
|
if len(results) > 1: |
|
|
|
if results[0]["form_name"] == None: |
|
|
|
return results[0]["pfic"] |
|
|
|
else: |
|
|
|
return self.get_pokemon_form_by_name(name, "Male", threshold=100, gender=gender) |
|
|
|
else: |
|
|
|
return results[0]["pfic"] # Return the PFIC of the first result if no form is specified |
|
|
|
|
|
|
|
if gender: |
|
|
|
gendered_form = self.get_pokemon_form_by_name(name, gender, threshold=100) |
|
|
|
if gendered_form: |
|
|
|
return gendered_form |
|
|
|
|
|
|
|
stripped_form = self.strip_pokemon_name(name, form) |
|
|
|
|
|
|
|
for entry in results: |
|
|
|
stripped_db_form = self.strip_pokemon_name(entry["name"], entry["form_name"]) |
|
|
|
if self.fuzzy_match_form(stripped_form, stripped_db_form, threshold): |
|
|
|
return entry["pfic"] |
|
|
|
|
|
|
|
# Some times we get a form for a pokemon that doesn't really have one. |
|
|
|
if len(results) > 1 and form != None: |
|
|
|
return results[0]["pfic"] |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
def strip_pokemon_name(self, pokemon_name: str, form_name: str) -> str: |
|
|
|
if form_name: |
|
|
|
form_name = form_name.replace("Form", "").strip() |
|
|
|
form_name = re.sub(f'{re.escape(pokemon_name)}\\s*', '', form_name, flags=re.IGNORECASE).strip() |
|
|
|
form_name = form_name.replace(" ", " ") |
|
|
|
return form_name |
|
|
|
return form_name |
|
|
|
|
|
|
|
def fuzzy_match_form(self, form1: str, form2: str, threshold: int = 80) -> bool: |
|
|
|
if form1 is None or form2 is None: |
|
|
|
return form1 == form2 |
|
|
|
return fuzz.ratio(form1.lower(), form2.lower()) >= threshold |