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