def download_pogo(self, architecture: APKArch) -> NoReturn: """ Download the package com.nianticlabs.pokemongo Determine if theres a newer version of com.nianticlabs.pokemongo. If a new version exists, validate it is supported by MAD. If the release is supported download and save to the storage interface Args: architecture (APKArch): Architecture of the package to download """ latest_version = self.find_latest_pogo(architecture) if latest_version is None: logger.warning( 'Unable to find latest data for PoGo. Try again later') elif supported_pogo_version(architecture, latest_version): current_version = self.storage.get_current_version( APKType.pogo, architecture) if type(current_version) is not str: current_version = None if current_version is None or is_newer_version( latest_version, current_version): where = { 'usage': APKType.pogo.value, 'arch': architecture.value } try: update_data = {'download_status': 1} self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) retries: int = 0 successful: bool = False while retries < MAX_RETRIES and not successful: self.gpconn = GPlayConnector(architecture) latest_data = self.get_latest(APKType.pogo, architecture) downloaded_file = self.gpconn.download( APKPackage.pogo.value, version_code=latest_data['url']) if downloaded_file and downloaded_file.getbuffer( ).nbytes > 0: PackageImporter(APKType.pogo, architecture, self.storage, downloaded_file, 'application/zip', version=latest_version) successful = True else: logger.info("Issue downloading apk") retries += 1 if retries < MAX_RETRIES: logger.warning( 'Unable to successfully download the APK') except: # noqa: E722 raise finally: update_data['download_status'] = 0 self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where)
def find_latest_pogo(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.nianticlabs.pokemongo has an update Args: architecture (APKArch): Architecture of the package to check """ latest = None logger.info('Searching for a new version of PoGo [{}]', architecture.name) self.gpconn = GPlayConnector(architecture) try: download_url = None latest = self.gpconn.get_latest_version(APKPackage.pogo.value) current_version = self.storage.get_current_version(APKType.pogo, architecture) if type(current_version) is not str: current_version = None if current_version is None or is_newer_version(latest, current_version): if supported_pogo_version(architecture, latest): logger.info('Newer version found on the Play Store: {}', latest) download_url = True else: logger.info('No newer version found') self.set_last_searched(APKType.pogo, architecture, version=latest, url=download_url) except Exception as err: logger.opt(exception=True).critical(err) return latest
def find_latest_pogo(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.nianticlabs.pokemongo has an update Args: architecture (APKArch): Architecture of the package to check """ latest = None version_code: int = None version_str: str = None logger.info('Searching for a new version of PoGo [{}]', architecture.name) try: latest_pogo_version = self.get_latest_version() if latest_pogo_version[architecture] is None: return latest latest_supported = latest_pogo_version[architecture] current_version_string = self.storage.get_current_version(APKType.pogo, architecture) current_version_code = None if type(current_version_string) is not str: current_version_string = None if current_version_string: latest_supported_dict: dict = {architecture: current_version_string} current_version_code = self.get_version_code(latest_supported=latest_supported_dict, arch=architecture) version_str = current_version_string version_code = current_version_code # do some sanity checking until this is fixed properly tmp_latest = self.get_latest(APKType.pogo, architecture) if (current_version_string is None or is_newer_version(latest_supported["version"], current_version_string) or (tmp_latest and tmp_latest['url'] is not None)): # Validate its available via google gpconn = GPlayConnector(architecture) (store_version_code, store_version_string) = gpconn.get_latest_version(APKPackage.pogo.value) if not supported_pogo_version(architecture, store_version_string): logger.info(f"Store version {store_version_string} is not supported by MAD. Unable to get a newer " "supported version.") if current_version_code: version_code = current_version_code version_str = current_version_string else: version_code = latest_supported["versionCode"] version_str = latest_supported["version"] elif current_version_code and store_version_code <= current_version_code: logger.info(f"Latest store version is {store_version_string} while {current_version_string} is " "already installed. Unable to find a newer version") version_code = current_version_code version_str = current_version_string else: logger.info('Newer version found: {}', store_version_string) version_code = store_version_code version_str = store_version_string else: logger.info('No newer version found') self.set_last_searched(APKType.pogo, architecture, version=version_str, url=version_code) except Exception as err: logger.opt(exception=True).critical(err) return { "version_code": version_code, "version": version_str }
def find_latest_pogo(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.nianticlabs.pokemongo has an update Args: architecture (APKArch): Architecture of the package to check """ latest = None version_code: int = None version_str: str = None logger.info('Searching for a new version of PoGo [{}]', architecture.name) try: latest_pogo_version = self.get_latest_version() if latest_pogo_version[architecture] is None: return latest latest_supported = latest_pogo_version[architecture] current_version = self.storage.get_current_version( APKType.pogo, architecture) if type(current_version) is not str: current_version = None # do some sanity checking until this is fixed properly tmp_latest = self.get_latest(APKType.pogo, architecture) if current_version is None or is_newer_version( latest_supported["version"], current_version) or (tmp_latest and tmp_latest['url'] is not None): # Validate its available via google gpconn = GPlayConnector(architecture) (store_vc, store_vs) = gpconn.get_latest_version(APKPackage.pogo.value) if store_vc < latest_supported["versionCode"]: logger.info( f"Latest supported is {store_vc} while installed is {latest_supported['versionCode']}. " "Unable to find a newer version") return None elif store_vc > latest_supported["versionCode"]: logger.info( "Version in store is newer than supported version. Using an older version" ) version_code = latest_supported["versionCode"] version_str = latest_supported["version"] elif current_version and store_vs == current_version: logger.info("Latest version [{}] is already installed", store_vc) version_code = store_vc version_str = store_vs else: logger.info('Newer version found: {}', store_vs) version_code = store_vc version_str = store_vs else: logger.info('No newer version found') self.set_last_searched(APKType.pogo, architecture, version=version_str, url=version_code) except Exception as err: logger.opt(exception=True).critical(err) return {"version_code": version_code, "version": version_str}
class APKWizard(object): """ The wizard will allow for simplified APK management for the required packages Args: dbc: Database wrapper storage: Abstract storage element for interacting with storage medium Attributes: dbc: Database wrapper gpconn: Object for interacting with google play storage: Abstract storage element for interacting with storage medium """ gpconn: GPlayConnector storage: AbstractAPKStorage def __init__(self, dbc, storage: AbstractAPKStorage): self.storage: AbstractAPKStorage = storage self.dbc = dbc self.gpconn = None def apk_all_actions(self) -> NoReturn: "Search and download all required packages" self.apk_all_download() def apk_all_download(self) -> NoReturn: "Download all packages in a non-blocking fashion" Thread(target=self.apk_nonblocking_download).start() def apk_all_search(self) -> NoReturn: "Search for updates for any required package" self.find_latest_pogo(APKArch.armeabi_v7a) self.find_latest_pogo(APKArch.arm64_v8a) self.find_latest_rgc(APKArch.noarch) self.find_latest_pd(APKArch.noarch) def apk_download(self, package: APKType, architecture: APKArch) -> NoReturn: """Download a specific package Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download """ if package == APKType.pogo: self.download_pogo(architecture) elif package == APKType.rgc: self.download_rgc(architecture) elif package == APKType.pd: self.download_pd(architecture) def apk_nonblocking_download(self) -> NoReturn: "Download all packages" self.download_pogo(APKArch.armeabi_v7a) self.download_pogo(APKArch.arm64_v8a) self.download_rgc(APKArch.noarch) self.download_pd(APKArch.noarch) def apk_search(self, package: APKType, architecture: APKArch) -> NoReturn: """ Search for a specific package Args: package (APKType): Package to search architecture (APKArch): Architecture of the package to search """ if package == APKType.pogo: self.find_latest_pogo(architecture) elif package == APKType.rgc: self.find_latest_rgc(architecture) elif package == APKType.pd: self.find_latest_pd(architecture) def download_pogo(self, architecture: APKArch) -> NoReturn: """ Download the package com.nianticlabs.pokemongo Determine if theres a newer version of com.nianticlabs.pokemongo. If a new version exists, validate it is supported by MAD. If the release is supported download and save to the storage interface Args: architecture (APKArch): Architecture of the package to download """ latest_version = self.find_latest_pogo(architecture) if latest_version is None: logger.warning( 'Unable to find latest data for PoGo. Try again later') elif supported_pogo_version(architecture, latest_version): current_version = self.storage.get_current_version( APKType.pogo, architecture) if type(current_version) is not str: current_version = None if current_version is None or is_newer_version( latest_version, current_version): where = { 'usage': APKType.pogo.value, 'arch': architecture.value } try: update_data = {'download_status': 1} self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) retries: int = 0 successful: bool = False while retries < MAX_RETRIES and not successful: self.gpconn = GPlayConnector(architecture) latest_data = self.get_latest(APKType.pogo, architecture) downloaded_file = self.gpconn.download( APKPackage.pogo.value, version_code=latest_data['url']) if downloaded_file and downloaded_file.getbuffer( ).nbytes > 0: PackageImporter(APKType.pogo, architecture, self.storage, downloaded_file, 'application/zip', version=latest_version) successful = True else: logger.info("Issue downloading apk") retries += 1 if retries < MAX_RETRIES: logger.warning( 'Unable to successfully download the APK') except: # noqa: E722 raise finally: update_data['download_status'] = 0 self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) def download_pd(self, architecture: APKArch) -> NoReturn: """ Download the package com.mad.pogodroid Args: architecture (APKArch): Architecture of the package to download """ logger.info("Downloading latest PogoDroid") self.__download_simple(APKType.pd, architecture) def __download_simple(self, package: APKType, architecture: APKArch) -> NoReturn: """ Downloads the package via requests Determine if there is a newer version of the package. If there is a newer version, download and save to the storage interface Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download """ latest_data = self.get_latest(package, architecture) current_version = self.storage.get_current_version( package, architecture) if type(current_version) is not str: current_version = None if not latest_data or latest_data['url'] is None: self.apk_search(package, architecture) latest_data = self.get_latest(package, architecture) if not latest_data: logger.warning('Unable to find latest data') elif current_version and 'size' in current_version and current_version.size == int( latest_data['version']): logger.info('Latest version already installed') else: update_data = {'download_status': 1} where = {'usage': package.value, 'arch': architecture.value} self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) try: retries: int = 0 successful: bool = False while retries < MAX_RETRIES and not successful: response = requests.get(latest_data['url'], verify=False, headers=APK_HEADERS) downloaded_file = io.BytesIO(response.content) if downloaded_file and downloaded_file.getbuffer( ).nbytes > 0: PackageImporter( package, architecture, self.storage, downloaded_file, 'application/vnd.android.package-archive') successful = True else: logger.info("Issue downloading apk") retries += 1 if retries < MAX_RETRIES: logger.warning( 'Unable to successfully download the APK') except: # noqa: E722 logger.warning('Unable to download the file @ {}', latest_data['url']) finally: update_data['download_status'] = 0 self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) def download_rgc(self, architecture: APKArch) -> NoReturn: """ Download the package de.grennith.rgc.remotegpscontroller Args: architecture (APKArch): Architecture of the package to download """ logger.info("Downloading latest RGC") self.__download_simple(APKType.rgc, architecture) def __find_latest_head(self, package, architecture, url) -> NoReturn: """ Determine if there is a newer version by checking the size of the package from the HEAD response Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download url (str): URL to perform the HEAD against """ (curr_info, status) = lookup_package_info(self.storage, package) installed_size = None if curr_info: installed_size = curr_info.get('size', None) head = requests.head(url, verify=False, headers=APK_HEADERS, allow_redirects=True) mirror_size = int(head.headers['Content-Length']) if not curr_info or (installed_size and installed_size != mirror_size): logger.info('Newer version found on the mirror of size {}', mirror_size) else: logger.info('No newer version found') self.set_last_searched(package, architecture, version=mirror_size, url=url) def find_latest_pd(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.mad.pogodroid has an update Args: architecture (APKArch): Architecture of the package to check """ logger.info('Searching for a new version of PD [{}]', architecture.name) self.__find_latest_head(APKType.pd, architecture, global_variables.URL_PD_APK) def find_latest_pogo(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.nianticlabs.pokemongo has an update Args: architecture (APKArch): Architecture of the package to check """ latest = None logger.info('Searching for a new version of PoGo [{}]', architecture.name) try: version_code = None latest_pogo_version = self.get_latest_version() if latest_pogo_version[architecture] is None: return latest latest = latest_pogo_version[architecture] current_version = self.storage.get_current_version( APKType.pogo, architecture) if type(current_version) is not str: current_version = None # do some sanity checking until this is fixed properly tmp_latest = self.get_latest(APKType.pogo, architecture) if current_version is None or is_newer_version( latest, current_version) or (tmp_latest and tmp_latest['url'] is not None and int(tmp_latest['url']) == 1): logger.info('Newer version found: {}', latest) version_code: int = self.get_version_code( latest_pogo_version, architecture) else: logger.info('No newer version found') self.set_last_searched(APKType.pogo, architecture, version=latest, url=version_code) except Exception as err: logger.opt(exception=True).critical(err) return latest def find_latest_rgc(self, architecture: APKArch) -> Optional[str]: """ Determine if the package de.grennith.rgc.remotegpscontroller has an update Args: architecture (APKArch): Architecture of the package to check """ logger.info('Searching for a new version of RGC [{}]', architecture.name) self.__find_latest_head(APKType.rgc, architecture, global_variables.URL_RGC_APK) def get_latest(self, package: APKType, architecture: APKArch) -> dict: """ Determine the latest found version for a given package / architecture Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download Returns (dict): Returns the latest version found for the package """ sql = "SELECT `version`, `url` FROM `mad_apk_autosearch` WHERE `usage` = %s AND `arch` = %s" return self.dbc.autofetch_row(sql, args=(package.value, architecture.value)) def get_latest_version(self) -> Dict[APKArch, str]: versions: Dict[APKArch, str] = { APKArch.armeabi_v7a: None, APKArch.arm64_v8a: None } gh_resp = requests.get(global_variables.ADDRESSES_GITHUB) for ver_identifier in gh_resp.json().keys(): version, arch = ver_identifier.split('_') named_arch = APKArch.armeabi_v7a if arch == '32' else APKArch.arm64_v8a if versions[named_arch] is None: versions[named_arch] = version elif is_newer_version(version, versions[named_arch]): versions[named_arch] = version return versions def get_version_code(self, latest_supported: Dict[APKArch, str], arch: APKArch) -> Optional[int]: pogo_vc_sess = requests.session() pogo_vc_sess.headers.update( {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}) # attempt to pull the information locally try: with open('configs/version_codes.json', 'r') as fh: data = json.load(fh) except (FileNotFoundError, json.decoder.JSONDecodeError): pass else: version_code = self.parse_version_code(latest_supported, arch, data) if version_code is not None: return version_code # match not found locally. Try GitHub try: data = pogo_vc_sess.get( global_variables.VERSIONCODES_GITHUB).json() except Exception: pass else: version_code = self.parse_version_code(latest_supported, arch, data) if version_code is not None: return version_code return None def parse_version_code(self, latest_supported: Dict[APKArch, str], arch: APKArch, data: Dict) -> Optional[int]: named_arch = '32' if arch == APKArch.armeabi_v7a else '64' latest_version = f"{latest_supported[arch]}_{named_arch}" if data: try: return data[latest_version] except KeyError: pass return None def set_last_searched(self, package: APKType, architecture: APKArch, version: str = None, url: str = None) -> NoReturn: """ Updates the last search information for the package / architecture Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download version (str): latest version found url (str): URL for the download """ data = { 'usage': package.value, 'arch': architecture.value, 'last_checked': 'NOW()' } if version: data['version'] = version if url: data['url'] = url self.dbc.autoexec_insert('mad_apk_autosearch', data, literals=['last_checked'], optype='ON DUPLICATE')
class APKWizard(object): """ The wizard will allow for simplified APK management for the required packages Args: dbc: Database wrapper storage: Abstract storage element for interacting with storage medium Attributes: dbc: Database wrapper gpconn: Object for interacting with google play storage: Abstract storage element for interacting with storage medium """ gpconn: GPlayConnector storage: AbstractAPKStorage def __init__(self, dbc, storage: AbstractAPKStorage): self.storage: AbstractAPKStorage = storage self.dbc = dbc self.gpconn = None def apk_all_actions(self) -> NoReturn: "Search and download all required packages" self.apk_all_search() self.apk_all_download() def apk_all_download(self) -> NoReturn: "Download all packages in a non-blocking fashion" Thread(target=self.apk_nonblocking_download).start() def apk_all_search(self) -> NoReturn: "Search for updates for any required package" self.find_latest_pogo(APKArch.armeabi_v7a) self.find_latest_pogo(APKArch.arm64_v8a) self.find_latest_rgc(APKArch.noarch) self.find_latest_pd(APKArch.noarch) def apk_download(self, package: APKType, architecture: APKArch) -> NoReturn: """Download a specific package Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download """ if package == APKType.pogo: self.download_pogo(architecture) elif package == APKType.rgc: self.download_rgc(architecture) elif package == APKType.pd: self.download_pd(architecture) def apk_nonblocking_download(self) -> NoReturn: "Download all packages" self.download_pogo(APKArch.armeabi_v7a) self.download_pogo(APKArch.arm64_v8a) self.download_rgc(APKArch.noarch) self.download_pd(APKArch.noarch) def apk_search(self, package: APKType, architecture: APKArch) -> NoReturn: """ Search for a specific package Args: package (APKType): Package to search architecture (APKArch): Architecture of the package to search """ if package == APKType.pogo: self.find_latest_pogo(architecture) elif package == APKType.rgc: self.find_latest_rgc(architecture) elif package == APKType.pd: self.find_latest_pd(architecture) def download_pogo(self, architecture: APKArch) -> NoReturn: """ Download the package com.nianticlabs.pokemongo Determine if theres a newer version of com.nianticlabs.pokemongo. If a new version exists, validate it is supported by MAD. If the release is supported download and save to the storage interface Args: architecture (APKArch): Architecture of the package to download """ latest_version = self.find_latest_pogo(architecture) if latest_version is None: logger.warning('Unable to find latest data for PoGo. Try again later') elif supported_pogo_version(architecture, latest_version): current_version = self.storage.get_current_version(APKType.pogo, architecture) if type(current_version) is not str: current_version = None if current_version is None or is_newer_version(latest_version, current_version): where = { 'usage': APKType.pogo.value, 'arch': architecture.value } try: update_data = { 'download_status': 1 } self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) retries: int = 0 successful: bool = False while retries < MAX_RETRIES and not successful: self.gpconn = GPlayConnector(architecture) downloaded_file = self.gpconn.download(APKPackage.pogo.value) if downloaded_file and downloaded_file.getbuffer().nbytes > 0: PackageImporter(APKType.pogo, architecture, self.storage, downloaded_file, 'application/zip', version=latest_version) successful = True else: logger.info("Issue downloading apk") retries += 1 if retries < MAX_RETRIES: logger.warning('Unable to successfully download the APK') except: # noqa: E722 raise finally: update_data['download_status'] = 0 self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) def download_pd(self, architecture: APKArch) -> NoReturn: """ Download the package com.mad.pogodroid Args: architecture (APKArch): Architecture of the package to download """ logger.info("Downloading latest PogoDroid") self.__download_simple(APKType.pd, architecture) def __download_simple(self, package: APKType, architecture: APKArch) -> NoReturn: """ Downloads the package via requests Determine if there is a newer version of the package. If there is a newer version, download and save to the storage interface Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download """ latest_data = self.get_latest(package, architecture) current_version = self.storage.get_current_version(package, architecture) if type(current_version) is not str: current_version = None if not latest_data or latest_data['url'] is None: self.apk_search(package, architecture) latest_data = self.get_latest(package, architecture) if not latest_data: logger.warning('Unable to find latest data') elif current_version and 'size' in current_version and current_version.size == int(latest_data['version']): logger.info('Latest version already installed') else: update_data = { 'download_status': 1 } where = { 'usage': package.value, 'arch': architecture.value } self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) try: retries: int = 0 successful: bool = False while retries < MAX_RETRIES and not successful: response = requests.get(latest_data['url'], verify=False, headers=APK_HEADERS) downloaded_file = io.BytesIO(response.content) if downloaded_file and downloaded_file.getbuffer().nbytes > 0: PackageImporter(package, architecture, self.storage, downloaded_file, 'application/vnd.android.package-archive') successful = True else: logger.info("Issue downloading apk") retries += 1 if retries < MAX_RETRIES: logger.warning('Unable to successfully download the APK') except: # noqa: E722 logger.warning('Unable to download the file @ {}', latest_data['url']) finally: update_data['download_status'] = 0 self.dbc.autoexec_update('mad_apk_autosearch', update_data, where_keyvals=where) def download_rgc(self, architecture: APKArch) -> NoReturn: """ Download the package de.grennith.rgc.remotegpscontroller Args: architecture (APKArch): Architecture of the package to download """ logger.info("Downloading latest RGC") self.__download_simple(APKType.rgc, architecture) def __find_latest_head(self, package, architecture, url) -> NoReturn: """ Determine if there is a newer version by checking the size of the package from the HEAD response Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download url (str): URL to perform the HEAD against """ (curr_info, status) = lookup_package_info(self.storage, package) installed_size = None if curr_info: installed_size = curr_info.get('size', None) head = requests.head(url, verify=False, headers=APK_HEADERS, allow_redirects=True) mirror_size = int(head.headers['Content-Length']) if not curr_info or (installed_size and installed_size != mirror_size): logger.info('Newer version found on the mirror of size {}', mirror_size) else: logger.info('No newer version found') self.set_last_searched(package, architecture, version=mirror_size, url=url) def find_latest_pd(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.mad.pogodroid has an update Args: architecture (APKArch): Architecture of the package to check """ logger.info('Searching for a new version of PD [{}]', architecture.name) self.__find_latest_head(APKType.pd, architecture, global_variables.URL_PD_APK) def find_latest_pogo(self, architecture: APKArch) -> Optional[str]: """ Determine if the package com.nianticlabs.pokemongo has an update Args: architecture (APKArch): Architecture of the package to check """ latest = None logger.info('Searching for a new version of PoGo [{}]', architecture.name) self.gpconn = GPlayConnector(architecture) try: download_url = None latest = self.gpconn.get_latest_version(APKPackage.pogo.value) current_version = self.storage.get_current_version(APKType.pogo, architecture) if type(current_version) is not str: current_version = None if current_version is None or is_newer_version(latest, current_version): if supported_pogo_version(architecture, latest): logger.info('Newer version found on the Play Store: {}', latest) download_url = True else: logger.info('No newer version found') self.set_last_searched(APKType.pogo, architecture, version=latest, url=download_url) except Exception as err: logger.opt(exception=True).critical(err) return latest def find_latest_rgc(self, architecture: APKArch) -> Optional[str]: """ Determine if the package de.grennith.rgc.remotegpscontroller has an update Args: architecture (APKArch): Architecture of the package to check """ logger.info('Searching for a new version of RGC [{}]', architecture.name) self.__find_latest_head(APKType.rgc, architecture, global_variables.URL_RGC_APK) def get_latest(self, package: APKType, architecture: APKArch) -> dict: """ Determine the latest found version for a given package / architecture Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download Returns (dict): Returns the latest version found for the package """ sql = "SELECT `version`, `url` FROM `mad_apk_autosearch` WHERE `usage` = %s AND `arch` = %s" return self.dbc.autofetch_row(sql, args=(package.value, architecture.value)) def set_last_searched(self, package: APKType, architecture: APKArch, version: str = None, url: str = None) -> NoReturn: """ Updates the last search information for the package / architecture Args: package (APKType): Package to download architecture (APKArch): Architecture of the package to download version (str): latest version found url (str): URL for the download """ data = { 'usage': package.value, 'arch': architecture.value, 'last_checked': 'NOW()' } if version: data['version'] = version if url: data['url'] = url self.dbc.autoexec_insert('mad_apk_autosearch', data, literals=['last_checked'], optype='ON DUPLICATE')