apksearch 1.0.0__tar.gz → 1.1.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apksearch
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Search for apks on varius websites
5
5
  Author-email: Abhi <allinoneallinone00@gmail.com>
6
6
  License: MIT License
@@ -129,6 +129,11 @@ if result:
129
129
  - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKMirror and returns the title and link if found.
130
130
  - **`find_version(self, apk_link: str, version: str) -> str`**: Finds and returns the download link for the given APK link and version.
131
131
 
132
+ #### `AppTeka`
133
+
134
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
135
+ - **`search_apk(self, version: str = None) -> None | tuple[str, str]`**: Searches for the APK on AppTeka and returns the title and link if found. If a version is provided, it checks if that version is available and returns the corresponding download link, None otherwise. If no version is provided, it returns the link for the latest version available.
136
+
132
137
  ### Testing
133
138
 
134
139
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -77,6 +77,11 @@ if result:
77
77
  - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKMirror and returns the title and link if found.
78
78
  - **`find_version(self, apk_link: str, version: str) -> str`**: Finds and returns the download link for the given APK link and version.
79
79
 
80
+ #### `AppTeka`
81
+
82
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
83
+ - **`search_apk(self, version: str = None) -> None | tuple[str, str]`**: Searches for the APK on AppTeka and returns the title and link if found. If a version is provided, it checks if that version is available and returns the corresponding download link, None otherwise. If no version is provided, it returns the link for the latest version available.
84
+
80
85
  ### Testing
81
86
 
82
87
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -0,0 +1,5 @@
1
+ from .sites.apkpure import APKPure
2
+ from .sites.apkmirror import APKMirror
3
+ from .sites.appteka import AppTeka
4
+
5
+ __all__ = ["APKPure", "APKMirror", "AppTeka"]
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
 
3
- from apksearch import APKPure, APKMirror
3
+ from apksearch import APKPure, APKMirror, AppTeka
4
4
  from requests.exceptions import ConnectionError, ConnectTimeout
5
5
 
6
6
  # Color codes
@@ -59,6 +59,29 @@ def search_apkmirror(pkg_name: str, version: str | None) -> None:
59
59
  print(f"{BOLD}APKMirror:{NC} No Results!")
60
60
 
61
61
 
62
+ def search_appteka(pkg_name: str, version: str | None) -> None:
63
+ appteka = AppTeka(pkg_name)
64
+ try:
65
+ result_apkpure: tuple[str, str] | None = appteka.search_apk(version)
66
+ except (ConnectionError, ConnectTimeout):
67
+ result_apkpure = None
68
+ print(f"{RED}Failed to resolve 'appteka.store'!{NC}")
69
+ if result_apkpure:
70
+ title, apk_link = result_apkpure
71
+ print(f"{BOLD}AppTeka:{NC} Found {GREEN}{title}{NC}") if title else None
72
+ if version:
73
+ if apk_link:
74
+ print(
75
+ f" ╰─> {BOLD}Version: {GREEN}{version}{NC} - {YELLOW}{apk_link}{NC}"
76
+ )
77
+ else:
78
+ print(f"{BOLD}AppTeka:{NC} Version {RED}{version}{NC} not found!")
79
+ else:
80
+ print(f" ╰─> {BOLD}Link: {YELLOW}{apk_link}{NC}")
81
+ else:
82
+ print(f"{BOLD}AppTeka:{NC} No Results!")
83
+
84
+
62
85
  def main():
63
86
  parser = argparse.ArgumentParser(
64
87
  prog="APKSearch", description="Search for APKs on various websites"
@@ -74,6 +97,9 @@ def main():
74
97
  search_apkpure(pkg_name, version)
75
98
  # Initiate search on apkmirror
76
99
  search_apkmirror(pkg_name, version)
100
+ # Initiate search on appteka
101
+ search_appteka(pkg_name, version)
102
+
77
103
 
78
104
  if __name__ == "__main__":
79
- main()
105
+ main()
@@ -12,7 +12,7 @@ class APKMirror:
12
12
  Attributes:
13
13
  pkg_name (str): The package name of the APK to search for.
14
14
  base_url (str): The base URL of the APKMirror website.
15
- search_url (str): The URL used to search for APKs on APKMirror.
15
+ api_url (str): The base URL for the APKMirror API.
16
16
  headers (dict): The headers used for making HTTP requests.
17
17
  session (requests.Session): The session object used for making HTTP requests.
18
18
 
@@ -0,0 +1,124 @@
1
+ import re
2
+ from bs4 import BeautifulSoup
3
+ import requests
4
+
5
+
6
+ class AppTeka:
7
+ """
8
+ This class provides methods to search for an APK on AppTeka based on package name,
9
+ and to find available versions and their download links for a given APK link.
10
+
11
+ Parameters:
12
+ pkg_name (str): The package name of the APK to search for.
13
+
14
+ Attributes:
15
+ pkg_name (str): The package name of the APK to search for.
16
+ base_url (str): The base URL of the AppTeka website.
17
+ search_url (str): The URL used to search for APKs on AppTeka.
18
+ headers (dict): The headers used for making HTTP requests.
19
+ session (requests.Session): The session object used for making HTTP requests.
20
+
21
+ Methods:
22
+ search_apk(version) -> None | tuple[str, str]:
23
+ Searches for an APK on AppTeka based on the package name and version.
24
+ Returns a tuple containing the APK name and download link if found, otherwise None.
25
+ """
26
+
27
+ def __init__(self, pkg_name: str):
28
+ self.pkg_name = pkg_name
29
+ self.base_url = "https://appteka.store"
30
+ self.search_url = self.base_url + "/list/?query="
31
+ self.headers = {
32
+ "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
33
+ "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
34
+ "cache-control": "no-cache",
35
+ "dnt": "1",
36
+ "connection": "keep-alive",
37
+ "pragma": "no-cache",
38
+ "referer": "https://appteka.store/list/",
39
+ "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
40
+ "sec-ch-ua-mobile": "?0",
41
+ "sec-ch-ua-platform": '"Windows"',
42
+ "sec-fetch-dest": "document",
43
+ "sec-fetch-mode": "navigate",
44
+ "sec-fetch-site": "same-origin",
45
+ "sec-fetch-user": "?1",
46
+ "upgrade-insecure-requests": "1",
47
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
48
+ }
49
+ self.session = requests.Session()
50
+
51
+ def search_apk(self, version: str = None) -> None | tuple[str, str]:
52
+ """
53
+ Searches for the APK on AppTeka and returns the title and link if found.
54
+
55
+ Parameters:
56
+ version (str, optional): The version of the APK to search for.
57
+
58
+ Returns:
59
+ None: If no matching APK is found.
60
+ tuple[str, str]: A tuple containing the title and link of the matching APK if found.
61
+ """
62
+ pkg_name = self.pkg_name
63
+ url = self.search_url + pkg_name
64
+ response: requests.Response = self.session.get(url, headers=self.headers)
65
+ soup = BeautifulSoup(response.text, "html.parser")
66
+ search_results = soup.find("div", {"class": "list-group"})
67
+ if search_results:
68
+ apk_items = search_results.find_all(
69
+ "a",
70
+ {"class": "list-group-item list-group-item-action d-flex gap-3 py-3"},
71
+ )
72
+ if apk_items:
73
+ for apk_item in apk_items:
74
+ apk_link = self.base_url + apk_item["href"]
75
+ apk_title = apk_item.find(
76
+ "strong", {"class": "text-gray-dark"}
77
+ ).text.strip()
78
+ # Unfortunately, AppTeka does not provide a package name in the search results.
79
+ # So, we can't compare the package names here.
80
+ # We can instead do a workaround by doing a request to the apk_link and check the package name there.
81
+ new_url = apk_link
82
+ new_response: requests.Response = self.session.get(
83
+ new_url, headers=self.headers
84
+ )
85
+ new_soup = BeautifulSoup(new_response.text, "html.parser")
86
+ rows = new_soup.find_all("dl", {"class": "row"})
87
+ for row in rows:
88
+ dt_tags = row.find_all("dt")
89
+ dd_tags = row.find_all("dd")
90
+ for dt, dd in zip(dt_tags, dd_tags):
91
+ if dt.text.strip() == "Package":
92
+ package_name = dd.text.strip()
93
+ if package_name == pkg_name:
94
+ # Appteka also stores the list of all the versions on same page
95
+ # So, if the version param is given then we can check if the version is available or not
96
+ if version:
97
+ version_modal = new_soup.find(
98
+ "div", {"id": "versionsModal"}
99
+ )
100
+ if version_modal:
101
+ version_links = version_modal.find_all(
102
+ "a",
103
+ {
104
+ "class": re.compile(
105
+ "^list-group-item list-group-item-action*"
106
+ )
107
+ },
108
+ )
109
+ for link in version_links:
110
+ version_text = (
111
+ link.find("p", {"class": "m-1"})
112
+ .text.strip()
113
+ .split("\xa0")[0]
114
+ )
115
+ if version_text == version:
116
+ apk_link = (
117
+ self.base_url + link["href"]
118
+ )
119
+ return apk_title, apk_link
120
+ return apk_title, None
121
+ else:
122
+ return apk_title, apk_link
123
+
124
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apksearch
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Search for apks on varius websites
5
5
  Author-email: Abhi <allinoneallinone00@gmail.com>
6
6
  License: MIT License
@@ -129,6 +129,11 @@ if result:
129
129
  - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKMirror and returns the title and link if found.
130
130
  - **`find_version(self, apk_link: str, version: str) -> str`**: Finds and returns the download link for the given APK link and version.
131
131
 
132
+ #### `AppTeka`
133
+
134
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
135
+ - **`search_apk(self, version: str = None) -> None | tuple[str, str]`**: Searches for the APK on AppTeka and returns the title and link if found. If a version is provided, it checks if that version is available and returns the corresponding download link, None otherwise. If no version is provided, it returns the link for the latest version available.
136
+
132
137
  ### Testing
133
138
 
134
139
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -13,5 +13,7 @@ apksearch.egg-info/top_level.txt
13
13
  apksearch/sites/__init__.py
14
14
  apksearch/sites/apkmirror.py
15
15
  apksearch/sites/apkpure.py
16
+ apksearch/sites/appteka.py
16
17
  tests/test_apkmirror.py
17
- tests/test_apkpure.py
18
+ tests/test_apkpure.py
19
+ tests/test_appteka.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "apksearch"
7
- version = "1.0.0"
7
+ version = "1.1.0"
8
8
  description = "Search for apks on varius websites"
9
9
  authors = [{ name = "Abhi", email = "allinoneallinone00@gmail.com" }]
10
10
  license = { file = "LICENSE" }
@@ -0,0 +1,39 @@
1
+ from apksearch.sites.appteka import AppTeka
2
+
3
+
4
+ def test_search_apk():
5
+ query = "com.roblox.client"
6
+ appteka = AppTeka(query)
7
+ result = appteka.search_apk()
8
+
9
+ assert result is not None, "No APK found for the query."
10
+ assert isinstance(result, tuple), "Result should be a tuple."
11
+ assert len(result) == 2, "Tuple should contain two elements."
12
+ assert isinstance(result[0], str), "First element of the tuple should be a string."
13
+ assert isinstance(result[1], str), "Second element of the tuple should be a string."
14
+
15
+
16
+ def test_search_apk_version():
17
+ query = "com.roblox.client"
18
+ version = "2.649.875"
19
+ appteka = AppTeka(query)
20
+ result = appteka.search_apk(version)
21
+
22
+ assert result is not None, "No APK found for the query."
23
+ assert isinstance(result, tuple), "Result should be a tuple."
24
+ assert len(result) == 2, "Tuple should contain two elements."
25
+ assert isinstance(result[0], str), "First element of the tuple should be a string."
26
+ assert isinstance(result[1], str), "Second element of the tuple should be a string."
27
+
28
+
29
+ def test_search_apk_not_version():
30
+ query = "com.roblox.client"
31
+ version = "nonexistent"
32
+ appteka = AppTeka(query)
33
+ result = appteka.search_apk(version)
34
+
35
+ assert result is not None, "No APK found for the query."
36
+ assert isinstance(result, tuple), "Result should be a tuple."
37
+ assert len(result) == 2, "Tuple should contain two elements."
38
+ assert isinstance(result[0], str), "First element of the tuple should be a string."
39
+ assert result[1] == None, "Second element of the tuple should be None."
@@ -1,4 +0,0 @@
1
- from .sites.apkpure import APKPure
2
- from .sites.apkmirror import APKMirror
3
-
4
- __all__ = ["APKPure", "APKMirror"]
File without changes
File without changes