From 7a0ad476eb062db0745579e4bce41c07d8b079d3 Mon Sep 17 00:00:00 2001 From: Khiem Ton Date: Thu, 23 Mar 2023 09:27:57 +0700 Subject: [PATCH] feat: SQLite Database for Pokemon --- .gitignore | 4 +++- ispoof/core/location.py | 28 +++++++++++++++++++++----- ispoof/lists/pokemonlist.py | 28 ++++++++++++++++++++++---- ispoof/objects/__init__.py | 3 +++ ispoof/objects/player.py | 4 ++-- ispoof/objects/pokemon.py | 36 +++++++++++++++++++++++++++------- ispoof/objects/raid.py | 30 ++++++++++++++++++---------- ispoof/spoofer/scraper.py | 6 ++++-- main.py | 39 ++++++++++++++++++++++++------------- requirements.txt | 3 ++- 10 files changed, 135 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index b800286..4003a78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ __pycache__ Pipfile Pipfile.lock -DeveloperDiskImage* \ No newline at end of file +DeveloperDiskImage* +logs +data.db \ No newline at end of file diff --git a/ispoof/core/location.py b/ispoof/core/location.py index 8c3a625..088793c 100644 --- a/ispoof/core/location.py +++ b/ispoof/core/location.py @@ -1,10 +1,26 @@ from math import radians, sin, cos, asin, sqrt +from sqlalchemy.types import TypeDecorator, String -class Location(): - def __init__(self, latitude, longitude): +class Location(TypeDecorator): + impl = String + cache_ok = True + + def __init__(self, latitude=None, longitude=None): self.latitude = latitude self.longitude = longitude - + + def process_bind_param(self, value, dialect): + if value: + return str(value) + + def process_result_value(self, value, dialect): + if value: + return Location(* map(float, value.split(","))) + + def load_dialect_impl(self, dialect): + # Provide the implementation for the specified dialect + return dialect.type_descriptor(String) + def distance(self, other): R = 6371 @@ -74,8 +90,10 @@ class Location(): return 117 else: return 120 - - + + def __str__(self): + return str(self.latitude) + "," + str(self.longitude) + def __repr__(self): return str(self.latitude) + "," + str(self.longitude) diff --git a/ispoof/lists/pokemonlist.py b/ispoof/lists/pokemonlist.py index 230be60..ed837ae 100644 --- a/ispoof/lists/pokemonlist.py +++ b/ispoof/lists/pokemonlist.py @@ -1,20 +1,35 @@ from ..objects.pokemon import Pokemon from ..core.location import Location from thefuzz.fuzz import partial_ratio +from sqlalchemy.orm import Session +from sqlalchemy.engine import Engine +from typing import List +from sqlalchemy import desc +from datetime import datetime, timedelta class PokemonList(): - def __init__(self, *args: Pokemon): - self.pokemons = [*args] + def __init__(self, engine: Engine): + self.pokemons = None + self.engine = engine + self.timedelta = timedelta(minutes=2) def sort_by_name(self, reverse=False): - self.pokemons.sort(key=lambda pokemon: pokemon.name, reverse=reverse) + with Session(self.engine) as session: + if reverse: + result = session.query(Pokemon).where(Pokemon.end_time > datetime.now() + self.timedelta)\ + .order_by(desc(Pokemon.name)) + else: + result = session.query(Pokemon).where(Pokemon.end_time > datetime.now() + self.timedelta)\ + .order_by(Pokemon.name) + session.commit() + return result.all() def sort_by_cp(self, reverse=False): self.pokemons.sort(key=lambda pokemon: pokemon.cp, reverse=reverse) def sort_by_level(self, reverse=False): self.pokemons.sort(key=lambda pokemon: pokemon.level, reverse=reverse) - + def sort_by_distance(self, location: Location, reverse=False): self.pokemons.sort(key=lambda pokemon: location.distance(pokemon.location), reverse=False) @@ -24,3 +39,8 @@ class PokemonList(): def search_by_name(self, query:str): return PokemonList(*filter(lambda pokemon: partial_ratio(query.lower(), pokemon.name) >= 80, self.pokemons)) + def insert_to_database(self, pokemons: List[Pokemon]): + with Session(self.engine) as session: + session.add_all(pokemons) + session.commit() + diff --git a/ispoof/objects/__init__.py b/ispoof/objects/__init__.py index e69de29..f617d5a 100644 --- a/ispoof/objects/__init__.py +++ b/ispoof/objects/__init__.py @@ -0,0 +1,3 @@ +from .player import Player +from .pokemon import Pokemon +from .raid import Raid \ No newline at end of file diff --git a/ispoof/objects/player.py b/ispoof/objects/player.py index 7bc6b94..3644b04 100644 --- a/ispoof/objects/player.py +++ b/ispoof/objects/player.py @@ -9,9 +9,9 @@ class Player(Object): def set_location_with_query(self, query): loc = Nominatim(user_agent="GetLoc") - getLoc = loc.geocode(query) + get_loc = loc.geocode(query) - self.location = Location(getLoc.latitude, getLoc.longitude) + self.location = Location(get_loc.latitude, get_loc.longitude) def set_location(self, location, did_activity): next_cd = self.cooldown_to(location) diff --git a/ispoof/objects/pokemon.py b/ispoof/objects/pokemon.py index 76c40d2..f99903c 100644 --- a/ispoof/objects/pokemon.py +++ b/ispoof/objects/pokemon.py @@ -1,11 +1,31 @@ from datetime import datetime -from .object import Object +from sqlalchemy import Column, String, Integer, Boolean, DateTime, PrimaryKeyConstraint +from ..core.location import Location +from sqlalchemy.orm import declarative_base + +Base = declarative_base() + +class Pokemon(Base): + __tablename__ = "pokemon" + name = Column(String(30)) + number = Column(Integer) + location = Column(Location) + cp = Column(Integer) + level = Column(Integer) + attack = Column(Integer) + defense = Column(Integer) + hp = Column(Integer) + iv = Column(Integer) + shiny = Column(Boolean) + start_time = Column(DateTime) + end_time = Column(DateTime) + country = Column(String(2)) + PrimaryKeyConstraint(name, location, start_time, end_time, name="pokemon_pk", sqlite_on_conflict='IGNORE') -class Pokemon(Object): def __init__(self, name, number, location, - cp, level, attack, defense, hp, - iv, shiny, start_time, end_time, - country): + cp, level, attack, defense, hp, + iv, shiny, start_time, end_time, + country): self.name = name self.number = number self.location = location @@ -19,9 +39,11 @@ class Pokemon(Object): self.start_time = start_time self.end_time = end_time self.country = country - + + super(Pokemon, self).__init__() + def is_dispawned(self): - if datetime().now() > end_time: + if datetime().now() > self.end_time: return True return False diff --git a/ispoof/objects/raid.py b/ispoof/objects/raid.py index 723a29b..05639b0 100644 --- a/ispoof/objects/raid.py +++ b/ispoof/objects/raid.py @@ -1,15 +1,25 @@ from .object import Object +from datetime import datetime +from sqlalchemy import Column, String, Integer, Boolean, Time, PrimaryKeyConstraint +from sqlalchemy.orm import declarative_base -class Raid(Object): - def __init__(self, name, number, level, location, start_time, end_time, country): - super().__init__() - self.name = name - self.number = number - self.level = level - self.location = location - self.start_time = start_time - self.end_time = end_time - self.country = country +Base = declarative_base() +class Raid(Object, Base): + __tablename__ = "raid" + + name = Column(String(30)) + number = Column(Integer) + location = Column(String(50)) + level = Column(Integer) + start_time = Column(Time) + end_time = Column(Time) + country = Column(String(2)) + PrimaryKeyConstraint(name, location, start_time, end_time, name="raid_pk") + + def is_dispawned(self): + if datetime().now() > self.end_time: + return True + return False def __repr__(self): return f"(Raid: {self.name} - {self.level}-star - {self.location} - Start: {self.start_time} - End: {self.end_time})" diff --git a/ispoof/spoofer/scraper.py b/ispoof/spoofer/scraper.py index 19265d6..b7b1dba 100644 --- a/ispoof/spoofer/scraper.py +++ b/ispoof/spoofer/scraper.py @@ -19,7 +19,7 @@ class Scraper(): for row in soup.find_all("tr")[1:]: data = row.find_all("td")[1:] - name = data[0].text.strip() + name = data[0].text.strip().strip("*") number = int(data[1].text) coordinates = map(float, data[2].text.split(",")) @@ -36,7 +36,9 @@ class Scraper(): end_time = datetime.fromisoformat(data[11].text) country = data[12].text - pokemon = Pokemon(name, number, location, cp, level, attack, defense, hp, iv, shiny, start_time, end_time, country) + pokemon = Pokemon(name=name, number=number, location=location, cp=cp, level=level, attack=attack, + defense=defense, hp=hp, iv=iv, shiny=shiny, start_time=start_time, end_time=end_time, + country=country) pokemon_lst.append(pokemon) return pokemon_lst diff --git a/main.py b/main.py index 7766ac7..797d7e8 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,11 @@ -from ispoof.core.objects.player import Player -from ispoof.core.spoofer.scraper import Scraper -from ispoof.core.spoofer.device import Device +from ispoof.objects.player import Player +from ispoof.spoofer.scraper import Scraper +from ispoof.spoofer.device import Device from pymobiledevice3.exceptions import AlreadyMountedError +from sqlalchemy import create_engine +from ispoof.lists.pokemonlist import PokemonList +from ispoof.data import initialize_database +from sqlalchemy.orm import Session import traceback if __name__ == "__main__": @@ -11,21 +15,32 @@ if __name__ == "__main__": try: device.mount_image(image_path, signature_path) except Exception as e: - traceback.print_exc() + # traceback.print_exc() print("Already mounted. Continuing.") player = Player() query = input("Enter your location: ") player.set_location_with_query(query) + print(str(player.location)) scraper = Scraper() - + engine = create_engine("sqlite:///data.db") + initialize_database(engine=engine) + pokemon_lst = PokemonList(engine=engine) while True: + pokemons = scraper.get_hundos() - pokemons.sort(key=lambda x: x.end_time, reverse=True) + pokemon_lst.insert_to_database(pokemons) print("Spoof to") - print(pokemons[10]) - location = pokemons[10].location + print("Pokemon List:") + pokemons = pokemon_lst.sort_by_name() + for i, pokemon in enumerate(pokemons): + print(i, pokemon) + i = int(input("Choose pokemon: ")) + pokemon = pokemons[i] + location = pokemon.location + print(pokemon) device.spoof_gps(location) did_activity = None + print(pokemon) while True: activity = input("Did you do any cooldown activities? [Y/N] ").lower() if activity in ("y", "n"): @@ -40,9 +55,5 @@ if __name__ == "__main__": if continue_prompt == "n": device.stop_spoofing() exit(0) - else: break - - - - -# print(scraper.get_raids()) \ No newline at end of file + else: + break diff --git a/requirements.txt b/requirements.txt index 5ca2514..5a4157c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ beautifulsoup4 lxml requests geopy -thefuzz[speedup] \ No newline at end of file +thefuzz[speedup] +sqlalchemy \ No newline at end of file