apksearch 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- apksearch/__init__.py +2 -1
- apksearch/cli.py +36 -9
- apksearch/sites/apkcombo.py +104 -0
- {apksearch-1.1.0.dist-info → apksearch-1.2.0.dist-info}/METADATA +7 -1
- apksearch-1.2.0.dist-info/RECORD +14 -0
- apksearch-1.1.0.dist-info/RECORD +0 -13
- {apksearch-1.1.0.dist-info → apksearch-1.2.0.dist-info}/LICENSE +0 -0
- {apksearch-1.1.0.dist-info → apksearch-1.2.0.dist-info}/WHEEL +0 -0
- {apksearch-1.1.0.dist-info → apksearch-1.2.0.dist-info}/entry_points.txt +0 -0
- {apksearch-1.1.0.dist-info → apksearch-1.2.0.dist-info}/top_level.txt +0 -0
apksearch/__init__.py
CHANGED
apksearch/cli.py
CHANGED
@@ -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
|
-
|
67
|
+
result_apkmirror: tuple[str, str] | None = apkmirror.search_apk()
|
43
68
|
except (ConnectionError, ConnectTimeout):
|
44
|
-
|
69
|
+
result_apkmirror = None
|
45
70
|
print(f"{RED}Failed to resolve 'apkmirror.com'!{NC}")
|
46
|
-
if
|
47
|
-
title, apk_link =
|
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
|
-
|
90
|
+
result_appteka: tuple[str, str] | None = appteka.search_apk(version)
|
66
91
|
except (ConnectionError, ConnectTimeout):
|
67
|
-
|
92
|
+
result_appteka = None
|
68
93
|
print(f"{RED}Failed to resolve 'appteka.store'!{NC}")
|
69
|
-
if
|
70
|
-
title, apk_link =
|
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.
|
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:
|
@@ -0,0 +1,14 @@
|
|
1
|
+
apksearch/__init__.py,sha256=7gSvDwU4DieNIkOHP3m8rnpFt_54XitPiWBzuZ-kkf4,205
|
2
|
+
apksearch/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
+
apksearch/cli.py,sha256=iQe1riJhBUjByyb1WBgbiSxN_WHvOLATwUZkxU4X0Gs,5079
|
4
|
+
apksearch/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
apksearch/sites/apkcombo.py,sha256=zhlbsD6I97QTWFRTR1aOzM7gGW9_--qwJ1kUHSp8_Ik,4641
|
6
|
+
apksearch/sites/apkmirror.py,sha256=IpS6r7ovM3g2dZrkR_a9zQpHy-jqrU2nJ3ykVkWxers,3127
|
7
|
+
apksearch/sites/apkpure.py,sha256=oUH-D1Xh04Bdb9eWQlX74B8OR3wm9lOEWqvvCC0-dUo,4785
|
8
|
+
apksearch/sites/appteka.py,sha256=in04JYF043n0fUvBW1QQeXnNbYekGUIh4qeame951nA,6372
|
9
|
+
apksearch-1.2.0.dist-info/LICENSE,sha256=Icu9iAY9cAaraq-HaAk8aWpXS1nE-3U_wfaOhN-HQUw,1061
|
10
|
+
apksearch-1.2.0.dist-info/METADATA,sha256=99vlfqVCjL8L2jB23uaaKCrMG7lhE8bgSyi64N9ynJs,6309
|
11
|
+
apksearch-1.2.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
12
|
+
apksearch-1.2.0.dist-info/entry_points.txt,sha256=FeAPgNPSU1tCwQNaKAmk6eQYbMHtsltcgeWSGUTxu0k,49
|
13
|
+
apksearch-1.2.0.dist-info/top_level.txt,sha256=VguZMODhlXWwDyJJNJms5syJ4EHmWSQOS45J9I5Cv5o,10
|
14
|
+
apksearch-1.2.0.dist-info/RECORD,,
|
apksearch-1.1.0.dist-info/RECORD
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
apksearch/__init__.py,sha256=rv05nSqsXDSGgmlXomRpOK1qRxX-KYLVRWThg_IRJRk,156
|
2
|
-
apksearch/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
-
apksearch/cli.py,sha256=FshatyXLp7iMQOSPuKidDHn9tmZns1WJPYLVz1R8kjs,3895
|
4
|
-
apksearch/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
apksearch/sites/apkmirror.py,sha256=IpS6r7ovM3g2dZrkR_a9zQpHy-jqrU2nJ3ykVkWxers,3127
|
6
|
-
apksearch/sites/apkpure.py,sha256=oUH-D1Xh04Bdb9eWQlX74B8OR3wm9lOEWqvvCC0-dUo,4785
|
7
|
-
apksearch/sites/appteka.py,sha256=in04JYF043n0fUvBW1QQeXnNbYekGUIh4qeame951nA,6372
|
8
|
-
apksearch-1.1.0.dist-info/LICENSE,sha256=Icu9iAY9cAaraq-HaAk8aWpXS1nE-3U_wfaOhN-HQUw,1061
|
9
|
-
apksearch-1.1.0.dist-info/METADATA,sha256=Oa0idOEPo3_bS1hQKR4Zf5HybgOxd7LkqEJwurCZp8E,5936
|
10
|
-
apksearch-1.1.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
11
|
-
apksearch-1.1.0.dist-info/entry_points.txt,sha256=FeAPgNPSU1tCwQNaKAmk6eQYbMHtsltcgeWSGUTxu0k,49
|
12
|
-
apksearch-1.1.0.dist-info/top_level.txt,sha256=VguZMODhlXWwDyJJNJms5syJ4EHmWSQOS45J9I5Cv5o,10
|
13
|
-
apksearch-1.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|