6 changed files with 265 additions and 3 deletions
@ -0,0 +1,148 @@ |
|||||
|
from PyQt6.QtCore import QObject, pyqtSignal, QRunnable |
||||
|
from bs4 import BeautifulSoup |
||||
|
from cache import cache |
||||
|
|
||||
|
from utility.data import regions, default_forms |
||||
|
from utility.functions import get_objects_by_number, compare_pokemon_forms |
||||
|
from db import db |
||||
|
|
||||
|
class GatherHomeStorageStatusWorkerSignals(QObject): |
||||
|
finished = pyqtSignal(list) |
||||
|
|
||||
|
class GatherHomeStorageStatus(QRunnable): |
||||
|
def __init__(self): |
||||
|
super().__init__() |
||||
|
self.signals = GatherHomeStorageStatusWorkerSignals() |
||||
|
self.base_url = "https://www.serebii.net/pokemonhome/" |
||||
|
|
||||
|
def run(self): |
||||
|
try: |
||||
|
gathered_data = self.gather_home_storage_data() |
||||
|
self.signals.finished.emit(gathered_data) |
||||
|
except Exception as e: |
||||
|
print(f"Error gathering Pokémon home storage status: {e}") |
||||
|
|
||||
|
def gather_home_storage_data(self): |
||||
|
all_pokemon_forms = db.get_list_of_pokemon_forms() |
||||
|
pokemon_storable_in_home = [] |
||||
|
pfics_that_can_go_to_home = [] |
||||
|
for region in regions: |
||||
|
pokemon_storable_in_home.extend(self.scrape_region_for_pokemon(region)) |
||||
|
|
||||
|
for pokemon_form in all_pokemon_forms: |
||||
|
storable_in_home = False |
||||
|
name = pokemon_form["name"] |
||||
|
national_dex = pokemon_form["national_dex"] |
||||
|
working_form = pokemon_form["form_name"] |
||||
|
|
||||
|
if working_form and name in working_form: |
||||
|
working_form = working_form.replace(name, "").strip() |
||||
|
|
||||
|
# serebii doesn't list gender in the table so we have to assume based on form name. |
||||
|
if working_form and ("male" in working_form.lower() or "working_form" in working_form.lower()): |
||||
|
working_form = None |
||||
|
|
||||
|
if name == "Unown" and (working_form != "!" and working_form != "?"): |
||||
|
working_form = None |
||||
|
|
||||
|
if name == "Tauros" and working_form == "Combat Breed": |
||||
|
working_form = "Paldean Form" |
||||
|
|
||||
|
# serebii just gave up on Alcremie. It has 36 uniquie forms all storable in home. |
||||
|
if name == "Alcremie": |
||||
|
working_form = None |
||||
|
|
||||
|
pokemon_by_national_dex = get_objects_by_number(pokemon_storable_in_home, f"{national_dex:04d}") |
||||
|
for pokemon in pokemon_by_national_dex: |
||||
|
if working_form: |
||||
|
parts = pokemon['name'].split(" ") |
||||
|
if len(parts) > 1 and parts[0] == working_form: |
||||
|
storable_in_home = True |
||||
|
|
||||
|
brackets = self.extract_bracketed_text(pokemon['name']) |
||||
|
if brackets: |
||||
|
for bracket in brackets: |
||||
|
if name in bracket: |
||||
|
bracket = bracket.replace(name, "").strip() |
||||
|
if compare_pokemon_forms(working_form, bracket): |
||||
|
storable_in_home = True |
||||
|
break |
||||
|
if storable_in_home == False and working_form and working_form in default_forms: |
||||
|
working_form = None |
||||
|
|
||||
|
if working_form == None and name.lower() in pokemon['name'].lower(): |
||||
|
storable_in_home = True |
||||
|
break |
||||
|
if storable_in_home: |
||||
|
pfics_that_can_go_to_home.append(pokemon_form["pfic"]) |
||||
|
return pfics_that_can_go_to_home |
||||
|
|
||||
|
|
||||
|
def scrape_region_for_pokemon(self, region): |
||||
|
cached_entry = cache.get(f"home_{region}") |
||||
|
if cached_entry != None: |
||||
|
return cached_entry |
||||
|
|
||||
|
url = f"{self.base_url}{region}pokemon.shtml" |
||||
|
response = cache.fetch_url(url) |
||||
|
if not response: |
||||
|
return [] |
||||
|
|
||||
|
soup = BeautifulSoup(response, 'html.parser') |
||||
|
table = soup.find('table', class_='dextable') |
||||
|
if table == None: |
||||
|
return [] |
||||
|
|
||||
|
pokemon_list = [] |
||||
|
|
||||
|
rows = table.find_all('tr')[2:] # Skip the header row and the game intro row |
||||
|
for row in rows: |
||||
|
cells = row.find_all('td') |
||||
|
if len(cells) <= 5: # Ensure we have enough cells to check depositability. if only 5 then its not depositable in any game. |
||||
|
continue |
||||
|
|
||||
|
number = cells[0].text.strip().lstrip('#') |
||||
|
name = cells[2].text.strip() |
||||
|
|
||||
|
# Get the image URL |
||||
|
img_url = cells[1].find('img')['src'] |
||||
|
full_img_url = f"https://www.serebii.net{img_url}" |
||||
|
|
||||
|
pokemon_list.append({ |
||||
|
'number': number, |
||||
|
'name': name, |
||||
|
'image_url': full_img_url |
||||
|
}) |
||||
|
|
||||
|
cache.set(f"home_{region}", pokemon_list) |
||||
|
|
||||
|
return pokemon_list |
||||
|
|
||||
|
def extract_bracketed_text(self, string): |
||||
|
results = [] |
||||
|
stack = [] |
||||
|
start_index = -1 |
||||
|
|
||||
|
for i, char in enumerate(string): |
||||
|
if char == '(': |
||||
|
if not stack: |
||||
|
start_index = i |
||||
|
stack.append(i) |
||||
|
elif char == ')': |
||||
|
if stack: |
||||
|
stack.pop() |
||||
|
if not stack: |
||||
|
results.append(string[start_index + 1:i]) |
||||
|
start_index = -1 |
||||
|
else: |
||||
|
#logger.warning(f"Warning: Unmatched closing parenthesis at position {i}") |
||||
|
pass |
||||
|
|
||||
|
# Handle any remaining unclosed brackets |
||||
|
if stack: |
||||
|
#logger.warning(f"Warning: {len(stack)} unmatched opening parentheses") |
||||
|
for unmatched_start in stack: |
||||
|
results.append(string[unmatched_start + 1:]) |
||||
|
|
||||
|
return results |
||||
|
|
||||
Loading…
Reference in new issue