apksearch 1.1.0__tar.gz → 1.2.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (23) hide show
  1. {apksearch-1.1.0 → apksearch-1.2.0}/PKG-INFO +7 -1
  2. {apksearch-1.1.0 → apksearch-1.2.0}/README.md +6 -0
  3. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/__init__.py +2 -1
  4. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/cli.py +36 -9
  5. apksearch-1.2.0/apksearch/sites/apkcombo.py +104 -0
  6. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/PKG-INFO +7 -1
  7. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/SOURCES.txt +2 -0
  8. {apksearch-1.1.0 → apksearch-1.2.0}/pyproject.toml +1 -1
  9. apksearch-1.2.0/tests/test_apkcombo.py +38 -0
  10. {apksearch-1.1.0 → apksearch-1.2.0}/LICENSE +0 -0
  11. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/__main__.py +0 -0
  12. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/sites/__init__.py +0 -0
  13. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/sites/apkmirror.py +0 -0
  14. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/sites/apkpure.py +0 -0
  15. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch/sites/appteka.py +0 -0
  16. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/dependency_links.txt +0 -0
  17. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/entry_points.txt +0 -0
  18. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/requires.txt +0 -0
  19. {apksearch-1.1.0 → apksearch-1.2.0}/apksearch.egg-info/top_level.txt +0 -0
  20. {apksearch-1.1.0 → apksearch-1.2.0}/setup.cfg +0 -0
  21. {apksearch-1.1.0 → apksearch-1.2.0}/tests/test_apkmirror.py +0 -0
  22. {apksearch-1.1.0 → apksearch-1.2.0}/tests/test_apkpure.py +0 -0
  23. {apksearch-1.1.0 → apksearch-1.2.0}/tests/test_appteka.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apksearch
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Search for apks on varius websites
5
5
  Author-email: Abhi <allinoneallinone00@gmail.com>
6
6
  License: MIT License
@@ -134,6 +134,12 @@ if result:
134
134
  - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
135
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
136
 
137
+ #### `APKCombo`
138
+
139
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
140
+ - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKCombo and returns the title and link if found.
141
+ - **`find_versions(self, apk_link: str) -> list[tuple[str, str]]`**: Finds and returns a list of versions and their download links for the given APK link.
142
+
137
143
  ### Testing
138
144
 
139
145
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -82,6 +82,12 @@ if result:
82
82
  - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
83
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
84
 
85
+ #### `APKCombo`
86
+
87
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
88
+ - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKCombo and returns the title and link if found.
89
+ - **`find_versions(self, apk_link: str) -> list[tuple[str, str]]`**: Finds and returns a list of versions and their download links for the given APK link.
90
+
85
91
  ### Testing
86
92
 
87
93
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -1,5 +1,6 @@
1
1
  from .sites.apkpure import APKPure
2
2
  from .sites.apkmirror import APKMirror
3
3
  from .sites.appteka import AppTeka
4
+ from .sites.apkcombo import APKCombo
4
5
 
5
- __all__ = ["APKPure", "APKMirror", "AppTeka"]
6
+ __all__ = ["APKPure", "APKMirror", "AppTeka", "APKCombo"]
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
 
3
- from apksearch import APKPure, APKMirror, AppTeka
3
+ from apksearch import APKPure, APKMirror, AppTeka, APKCombo
4
4
  from requests.exceptions import ConnectionError, ConnectTimeout
5
5
 
6
6
  # Color codes
@@ -36,15 +36,40 @@ def search_apkpure(pkg_name: str, version: str | None) -> None:
36
36
  print(f"{BOLD}APKPure:{NC} No Results!")
37
37
 
38
38
 
39
+ def search_apkcombo(pkg_name: str, version: str | None) -> None:
40
+ apkcombo = APKCombo(pkg_name)
41
+ try:
42
+ result_apkcombo: tuple[str, str] | None = apkcombo.search_apk()
43
+ except (ConnectionError, ConnectTimeout):
44
+ result_apkcombo = None
45
+ print(f"{RED}Failed to resolve 'apkcombo.app'!{NC}")
46
+ if result_apkcombo:
47
+ title, apk_link = result_apkcombo
48
+ print(f"{BOLD}APKCombo:{NC} Found {GREEN}{title}{NC}") if title else None
49
+ print(f" ╰─> {BOLD}Link: {YELLOW}{apk_link}{NC}") if not version else None
50
+ versions: list[tuple[str, str]] = apkcombo.find_versions(apk_link)
51
+ if version:
52
+ for version_tuple in versions:
53
+ if version_tuple[0] == version:
54
+ print(
55
+ f" ╰─> {BOLD}Version: {GREEN}{version}{NC} - {YELLOW}{version_tuple[1]}{NC}"
56
+ )
57
+ break
58
+ else:
59
+ print(f"{BOLD}APKCombo:{NC} Version {RED}{version}{NC} not found!")
60
+ else:
61
+ print(f"{BOLD}APKCombo:{NC} No Results!")
62
+
63
+
39
64
  def search_apkmirror(pkg_name: str, version: str | None) -> None:
40
65
  apkmirror = APKMirror(pkg_name)
41
66
  try:
42
- result_apkpure: tuple[str, str] | None = apkmirror.search_apk()
67
+ result_apkmirror: tuple[str, str] | None = apkmirror.search_apk()
43
68
  except (ConnectionError, ConnectTimeout):
44
- result_apkpure = None
69
+ result_apkmirror = None
45
70
  print(f"{RED}Failed to resolve 'apkmirror.com'!{NC}")
46
- if result_apkpure:
47
- title, apk_link = result_apkpure
71
+ if result_apkmirror:
72
+ title, apk_link = result_apkmirror
48
73
  print(f"{BOLD}APKMirror:{NC} Found {GREEN}{title}{NC}") if title else None
49
74
  print(f" ╰─> {BOLD}Link: {YELLOW}{apk_link}{NC}") if not version else None
50
75
  if version:
@@ -62,12 +87,12 @@ def search_apkmirror(pkg_name: str, version: str | None) -> None:
62
87
  def search_appteka(pkg_name: str, version: str | None) -> None:
63
88
  appteka = AppTeka(pkg_name)
64
89
  try:
65
- result_apkpure: tuple[str, str] | None = appteka.search_apk(version)
90
+ result_appteka: tuple[str, str] | None = appteka.search_apk(version)
66
91
  except (ConnectionError, ConnectTimeout):
67
- result_apkpure = None
92
+ result_appteka = None
68
93
  print(f"{RED}Failed to resolve 'appteka.store'!{NC}")
69
- if result_apkpure:
70
- title, apk_link = result_apkpure
94
+ if result_appteka:
95
+ title, apk_link = result_appteka
71
96
  print(f"{BOLD}AppTeka:{NC} Found {GREEN}{title}{NC}") if title else None
72
97
  if version:
73
98
  if apk_link:
@@ -99,6 +124,8 @@ def main():
99
124
  search_apkmirror(pkg_name, version)
100
125
  # Initiate search on appteka
101
126
  search_appteka(pkg_name, version)
127
+ # Initiate search on apkcombo
128
+ search_apkcombo(pkg_name, version)
102
129
 
103
130
 
104
131
  if __name__ == "__main__":
@@ -0,0 +1,104 @@
1
+ from bs4 import BeautifulSoup
2
+ import requests
3
+
4
+
5
+ class APKCombo:
6
+ """
7
+ This class provides methods to search for an APK on APKCombo based on package name,
8
+ and to find available versions and their download links for a given APK link.
9
+
10
+ Parameters:
11
+ pkg_name (str): The package name of the APK to search for.
12
+
13
+ Attributes:
14
+ pkg_name (str): The package name of the APK to search for.
15
+ base_url (str): The base URL of the APKCombo website.
16
+ search_url (str): The URL used to search for APKs on APKCombo.
17
+ headers (dict): The headers used for making HTTP requests.
18
+ session (requests.Session): The session object used for making HTTP requests.
19
+
20
+ Methods:
21
+ search_apk() -> None | tuple[str, str]:
22
+ Searches for the APK on APKCombo and returns the title and link if found.
23
+
24
+ find_versions(apk_link: str) -> list[tuple[str, str]]:
25
+ Finds and returns a list of versions and their download links for the given APK link.
26
+ """
27
+
28
+ def __init__(self, pkg_name: str):
29
+ self.pkg_name = pkg_name
30
+ self.base_url = "https://apkcombo.app"
31
+ self.search_url = self.base_url + "/search/"
32
+ self.headers = {
33
+ "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",
34
+ "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
35
+ "cache-control": "no-cache",
36
+ "cookie": "__apkcombo_lang=en",
37
+ "dnt": "1",
38
+ "pragma": "no-cache",
39
+ "priority": "u=0, i",
40
+ "referer": "https://apkcombo.app/",
41
+ "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
42
+ "sec-ch-ua-mobile": "?0",
43
+ "sec-ch-ua-platform": '"Windows"',
44
+ "sec-fetch-dest": "document",
45
+ "sec-fetch-mode": "navigate",
46
+ "sec-fetch-site": "same-origin",
47
+ "sec-fetch-user": "?1",
48
+ "upgrade-insecure-requests": "1",
49
+ "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",
50
+ }
51
+ self.session = requests.Session()
52
+
53
+ def search_apk(self) -> None | tuple[str, str]:
54
+ """
55
+ Searches for the APK on APKCombo and returns the title and link if found.
56
+
57
+ Returns:
58
+ None: If no matching APK is found.
59
+ tuple[str, str]: A tuple containing the title and link of the matching APK if found.
60
+ """
61
+ pkg_name = self.pkg_name
62
+ url = self.search_url + pkg_name
63
+ response: requests.Response = self.session.get(
64
+ url, headers=self.headers, allow_redirects=False
65
+ )
66
+ # Redirect to the APK page if there's only one result. i.e, apk found.
67
+ if response.status_code == 302:
68
+ url = self.search_url + response.headers["Location"]
69
+ response: requests.Response = self.session.get(url, headers=self.headers)
70
+ elif response.status_code == 200: # Package name not found or multiple results.
71
+ return None
72
+ else:
73
+ raise Exception(f"Error: {response.status_code}")
74
+ soup = BeautifulSoup(response.text, "html.parser")
75
+ title = soup.find("div", {"class": "app_name"}).text.strip()
76
+ apk_link = url
77
+ return title, apk_link
78
+
79
+ def find_versions(self, apk_link: str) -> list[tuple[str, str]]:
80
+ """
81
+ Finds and returns a list of versions and their download links for the given APK link.
82
+
83
+ Parameters:
84
+ apk_link (str): The link to the APK on the APKCombo website.
85
+
86
+ Returns:
87
+ list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
88
+ and its corresponding download link. If no versions are found, an empty list is returned.
89
+ """
90
+ url = apk_link + "/old-versions"
91
+ response: requests.Response = self.session.get(url, headers=self.headers)
92
+ soup = BeautifulSoup(response.text, "html.parser")
93
+ versions_list = soup.find("ul", {"class": "list-versions"})
94
+ versions_info = []
95
+
96
+ if versions_list:
97
+ versions = versions_list.find_all("a", {"class": "ver-item"})
98
+ for version in versions:
99
+ version_number = version.find("span", {"class": "vername"}).text
100
+ version_number = version_number.split(" ")[-1]
101
+ download_url = self.base_url + version["href"]
102
+ versions_info.append((version_number, download_url))
103
+
104
+ return versions_info
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apksearch
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Search for apks on varius websites
5
5
  Author-email: Abhi <allinoneallinone00@gmail.com>
6
6
  License: MIT License
@@ -134,6 +134,12 @@ if result:
134
134
  - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
135
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
136
 
137
+ #### `APKCombo`
138
+
139
+ - **`__init__(self, pkg_name: str)`**: Initializes with the package name.
140
+ - **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK on APKCombo and returns the title and link if found.
141
+ - **`find_versions(self, apk_link: str) -> list[tuple[str, str]]`**: Finds and returns a list of versions and their download links for the given APK link.
142
+
137
143
  ### Testing
138
144
 
139
145
  The project includes tests for the `sites` classes. To run the tests, use the following command:
@@ -11,9 +11,11 @@ apksearch.egg-info/entry_points.txt
11
11
  apksearch.egg-info/requires.txt
12
12
  apksearch.egg-info/top_level.txt
13
13
  apksearch/sites/__init__.py
14
+ apksearch/sites/apkcombo.py
14
15
  apksearch/sites/apkmirror.py
15
16
  apksearch/sites/apkpure.py
16
17
  apksearch/sites/appteka.py
18
+ tests/test_apkcombo.py
17
19
  tests/test_apkmirror.py
18
20
  tests/test_apkpure.py
19
21
  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.1.0"
7
+ version = "1.2.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,38 @@
1
+ from apksearch.sites.apkcombo import APKCombo
2
+
3
+
4
+ def test_search_apk():
5
+ query = "com.roblox.client"
6
+ apkcombo = APKCombo(query)
7
+ result = apkcombo.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_find_versions():
17
+ query = "com.roblox.client"
18
+ apkcombo = APKCombo(query)
19
+ result = apkcombo.search_apk()
20
+
21
+ if result:
22
+ apk_link = result[1]
23
+ versions = apkcombo.find_versions(apk_link)
24
+
25
+ assert isinstance(versions, list), "Versions should be a list."
26
+ assert len(versions) > 0, "No versions found."
27
+ assert all(
28
+ isinstance(version, tuple) for version in versions
29
+ ), "Each version should be a tuple."
30
+ assert all(
31
+ len(version) == 2 for version in versions
32
+ ), "Each version tuple should contain two elements."
33
+ assert all(
34
+ isinstance(version[0], str) for version in versions
35
+ ), "First element of each version tuple should be a string."
36
+ assert all(
37
+ isinstance(version[1], str) for version in versions
38
+ ), "Second element of each version tuple should be a string."
File without changes
File without changes