user-scanner 1.0.2.1__py3-none-any.whl → 1.0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. user_scanner/__init__.py +0 -1
  2. user_scanner/__main__.py +114 -61
  3. user_scanner/cli/banner.py +3 -8
  4. user_scanner/cli/printer.py +117 -0
  5. user_scanner/community/__init__.py +1 -0
  6. user_scanner/community/coderlegion.py +11 -31
  7. user_scanner/community/stackoverflow.py +35 -0
  8. user_scanner/core/orchestrator.py +199 -79
  9. user_scanner/core/result.py +128 -0
  10. user_scanner/core/utils.py +9 -0
  11. user_scanner/creator/devto.py +11 -29
  12. user_scanner/creator/hashnode.py +25 -28
  13. user_scanner/creator/itch_io.py +19 -0
  14. user_scanner/creator/kaggle.py +11 -29
  15. user_scanner/creator/medium.py +18 -22
  16. user_scanner/creator/patreon.py +12 -38
  17. user_scanner/creator/producthunt.py +47 -0
  18. user_scanner/dev/codeberg.py +11 -29
  19. user_scanner/dev/cratesio.py +11 -24
  20. user_scanner/dev/dockerhub.py +11 -27
  21. user_scanner/dev/github.py +43 -39
  22. user_scanner/dev/gitlab.py +21 -32
  23. user_scanner/dev/huggingface.py +19 -0
  24. user_scanner/dev/launchpad.py +11 -24
  25. user_scanner/dev/npmjs.py +21 -34
  26. user_scanner/dev/replit.py +11 -29
  27. user_scanner/donation/__init__.py +0 -0
  28. user_scanner/donation/buymeacoffee.py +19 -0
  29. user_scanner/donation/liberapay.py +36 -0
  30. user_scanner/gaming/chess_com.py +20 -36
  31. user_scanner/gaming/minecraft.py +19 -0
  32. user_scanner/gaming/monkeytype.py +8 -26
  33. user_scanner/gaming/osu.py +13 -38
  34. user_scanner/gaming/roblox.py +37 -42
  35. user_scanner/gaming/steam.py +29 -0
  36. user_scanner/social/bluesky.py +21 -38
  37. user_scanner/social/discord.py +17 -21
  38. user_scanner/social/instagram.py +11 -24
  39. user_scanner/social/mastodon.py +12 -38
  40. user_scanner/social/pinterest.py +18 -32
  41. user_scanner/social/reddit.py +19 -32
  42. user_scanner/social/snapchat.py +24 -37
  43. user_scanner/social/soundcloud.py +43 -0
  44. user_scanner/social/telegram.py +19 -24
  45. user_scanner/social/threads.py +11 -24
  46. user_scanner/social/x.py +20 -28
  47. user_scanner/social/youtube.py +41 -47
  48. user_scanner/utils/version.py +2 -0
  49. user_scanner/version.json +1 -1
  50. {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/METADATA +62 -67
  51. user_scanner-1.0.9.0.dist-info/RECORD +61 -0
  52. user_scanner-1.0.2.1.dist-info/RECORD +0 -48
  53. {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/WHEEL +0 -0
  54. {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/entry_points.txt +0 -0
  55. {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,92 +1,212 @@
1
1
  import importlib
2
- import pkgutil
2
+ import importlib.util
3
3
  from colorama import Fore, Style
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from itertools import permutations
6
+ import httpx
7
+ from pathlib import Path
8
+ from user_scanner.cli.printer import Printer
9
+ from user_scanner.core.result import Result, AnyResult
10
+ from typing import Callable, Dict, List
11
+ from user_scanner.core.utils import get_site_name, is_last_value
4
12
 
5
- def load_modules(package):
6
13
 
14
+ def load_modules(category_path: Path):
7
15
  modules = []
8
- for _, name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."):
9
- try:
10
- module = importlib.import_module(name)
11
- modules.append(module)
12
- except Exception as e:
13
- print(f"Failed to import {name}: {e}")
16
+ for file in category_path.glob("*.py"):
17
+ if file.name == "__init__.py":
18
+ continue
19
+ spec = importlib.util.spec_from_file_location(file.stem, str(file))
20
+ module = importlib.util.module_from_spec(spec)
21
+ spec.loader.exec_module(module)
22
+
23
+ modules.append(module)
14
24
  return modules
15
25
 
16
- def run_module_single(module, username):
17
26
 
27
+ def load_categories() -> Dict[str, Path]:
28
+ root = Path(__file__).resolve().parent.parent # Should be user_scanner
29
+ categories = {}
30
+
31
+ for subfolder in root.iterdir():
32
+ if subfolder.is_dir() and \
33
+ not subfolder.name.lower() in ["cli", "utils", "core"] and \
34
+ not "__" in subfolder.name: # Removes __pycache__
35
+ categories[subfolder.name] = subfolder.resolve()
36
+
37
+ return categories
38
+
39
+
40
+ def find_module(name: str):
41
+ name = name.lower()
42
+
43
+ matches = [
44
+ module
45
+ for category_path in load_categories().values()
46
+ for module in load_modules(category_path)
47
+ if module.__name__.split(".")[-1].lower() == name
48
+ ]
49
+
50
+ return matches
51
+
52
+ def find_category(module) -> str | None:
53
+
54
+ module_file = getattr(module, '__file__', None)
55
+ if not module_file:
56
+ return None
57
+
58
+ category = Path(module_file).parent.name.lower()
59
+ categories = load_categories()
60
+ if category in categories:
61
+ return category.capitalize()
62
+
63
+ return None
64
+
65
+
66
+
67
+ def worker_single(module, username: str) -> Result:
18
68
  func = next((getattr(module, f) for f in dir(module)
19
69
  if f.startswith("validate_") and callable(getattr(module, f))), None)
20
- site_name = module.__name__.split('.')[-1].capitalize()
21
- if site_name == "X":
22
- site_name = "X (Twitter)"
23
-
24
- if func:
25
- try:
26
- result = func(username)
27
- if result == 1:
28
- print(f" {Fore.GREEN}[✔] {site_name}: Available{Style.RESET_ALL}")
29
- elif result == 0:
30
- print(f" {Fore.RED}[✘] {site_name}: Taken{Style.RESET_ALL}")
31
- else:
32
- print(f" {Fore.YELLOW}[!] {site_name}: Error{Style.RESET_ALL}")
33
- except Exception as e:
34
- print(f" {Fore.YELLOW}[!] {site_name}: Exception - {e}{Style.RESET_ALL}")
35
- else:
36
- print(f" {Fore.YELLOW}[!] {site_name} has no validate_ function{Style.RESET_ALL}")
37
-
38
- def run_checks_category(package, username, verbose=False):
39
- modules = load_modules(package)
40
- category_name = package.__name__.split('.')[-1].capitalize()
41
- print(f"{Fore.MAGENTA}== {category_name} SITES =={Style.RESET_ALL}")
42
-
43
- for module in modules:
44
- run_module_single(module, username)
45
-
46
- def run_checks(username):
47
-
48
- from user_scanner import dev, social,creator, community, gaming
49
-
50
- categories = [
51
- ("DEV", dev),
52
- ("SOCIAL", social),
53
- ("CREATOR", creator),
54
- ("COMMUNITY", community),
55
- ("GAMING", gaming)
56
- ]
57
70
 
58
- print(f"\n{Fore.CYAN} Checking username: {username}{Style.RESET_ALL}\n")
71
+ site_name = get_site_name(module)
72
+
73
+ if not func:
74
+ return Result.error(f"{site_name} has no validate_ function", site_name=site_name, username=username)
75
+
76
+ try:
77
+ result: Result = func(username)
78
+ result.update(site_name=site_name, username=username)
79
+ return result
80
+ except Exception as e:
81
+ return Result.error(e, site_name=site_name, username=username)
82
+
83
+
84
+ def run_module_single(module, username: str, printer: Printer, last: bool = True) -> List[Result]:
85
+ result = worker_single(module, username)
86
+
87
+ category = find_category(module)
88
+ if category:
89
+ result.update(category=category)
90
+
91
+ site_name = get_site_name(module)
92
+ msg = printer.get_result_output(result)
93
+ if last == False and printer.is_json:
94
+ msg += ","
95
+ print(msg)
96
+
97
+ return [result]
98
+
99
+
100
+
101
+ def run_checks_category(category_path: Path, username: str, printer: Printer, last: bool = True) -> List[Result]:
102
+ modules = load_modules(category_path)
103
+
104
+ category_name = category_path.stem.capitalize()
105
+ if printer.is_console:
106
+ print(f"\n{Fore.MAGENTA}== {category_name} SITES =={Style.RESET_ALL}")
107
+
108
+ results = []
109
+
110
+ with ThreadPoolExecutor(max_workers=10) as executor:
111
+ exec_map = executor.map(lambda m: worker_single(m, username), modules)
112
+ for i, result in enumerate(exec_map):
113
+ result.update(category = category_name)
114
+ results.append(result)
115
+
116
+ is_last = last and is_last_value(modules, i)
117
+ site_name = get_site_name(modules[i])
118
+ msg = printer.get_result_output(result)
119
+ if is_last == False and printer.is_json:
120
+ msg += ","
121
+ print(msg)
122
+
123
+ return results
124
+
125
+
126
+ def run_checks(username: str, printer: Printer, last: bool = True) -> List[Result]:
127
+ if printer.is_console:
128
+ print(f"\n{Fore.CYAN} Checking username: {username}{Style.RESET_ALL}")
129
+
130
+ results = []
131
+
132
+ categories = list(load_categories().values())
133
+ for i, category_path in enumerate(categories):
134
+ last_cat: int = last and (i == len(categories) - 1)
135
+ temp = run_checks_category(category_path, username, printer, last_cat)
136
+ results.extend(temp)
137
+
138
+ return results
139
+
140
+
141
+ def make_get_request(url: str, **kwargs) -> httpx.Response:
142
+ """Simple wrapper to **httpx.get** that predefines headers and timeout"""
143
+ if not "headers" in kwargs:
144
+ kwargs["headers"] = {
145
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
146
+ 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
147
+ 'Accept-Encoding': "gzip, deflate, br",
148
+ 'Accept-Language': "en-US,en;q=0.9",
149
+ 'sec-fetch-dest': "document",
150
+ }
151
+
152
+ if not "timeout" in kwargs:
153
+ kwargs["timeout"] = 5.0
154
+
155
+ return httpx.get(url, **kwargs)
156
+
157
+
158
+ def generic_validate(url: str, func: Callable[[httpx.Response], AnyResult], **kwargs) -> AnyResult:
159
+ """
160
+ A generic validate function that makes a request and executes the provided function on the response.
161
+ """
162
+ try:
163
+ response = make_get_request(url, **kwargs)
164
+ result = func(response)
165
+ result.url = url
166
+ return result
167
+ except Exception as e:
168
+ return Result.error(e, url=url)
169
+
170
+
171
+ def status_validate(url: str, available: int | List[int], taken: int | List[int], **kwargs) -> Result:
172
+ """
173
+ Function that takes a **url** and **kwargs** for the request and
174
+ checks if the request status matches the availabe or taken.
175
+ **Available** and **Taken** must either be whole numbers or lists of whole numbers.
176
+ """
177
+ def inner(response: httpx.Response):
178
+ # Checks if a number is equal or is contained inside
179
+ def contains(a, b): return (isinstance(a, list) and b in a) or (a == b)
180
+ status = response.status_code
181
+ available_value = contains(available, status)
182
+ taken_value = contains(taken, status)
183
+
184
+ if available_value and taken_value:
185
+ # Can't be both available and taken
186
+ return Result.error("Invalid status match. Report this on Github.")
187
+ elif available_value:
188
+ return Result.available()
189
+ elif taken_value:
190
+ return Result.taken()
191
+ return Result.error("Status didn't match. Report this on Github.")
192
+
193
+ return generic_validate(url, inner, **kwargs)
59
194
 
60
- for cat_name, package in categories:
61
- try:
62
- modules = load_modules(package)
63
- except ModuleNotFoundError:
64
- continue
65
195
 
66
- print(f"{Fore.MAGENTA}== {cat_name} SITES =={Style.RESET_ALL}")
67
-
68
- for module in modules:
69
- # Find the first function starting with "validate_"
70
- func = None
71
- for f in dir(module):
72
- if f.startswith("validate_") and callable(getattr(module, f)):
73
- func = getattr(module, f)
74
- break
75
- if not func:
76
- continue
77
-
78
- site_name = module.__name__.split('.')[-1].capitalize()
79
- if site_name == "X":
80
- site_name = "X (Twitter)"
81
- try:
82
- result = func(username)
83
- if result == 1:
84
- print(f" {Fore.GREEN}[✔] {site_name}: Available{Style.RESET_ALL}")
85
- elif result == 0:
86
- print(f" {Fore.RED}[✘] {site_name}: Taken{Style.RESET_ALL}")
87
- else:
88
- print(f" {Fore.YELLOW}[!] {site_name}: Error{Style.RESET_ALL}")
89
- except Exception as e:
90
- print(f" {Fore.YELLOW}[!] {site_name}: Exception - {e}{Style.RESET_ALL}")
91
-
92
- print()
196
+ def generate_permutations(username, pattern, limit=None):
197
+ """
198
+ Generate all order-based permutations of characters in `pattern`
199
+ appended after `username`.
200
+ """
201
+ permutations_set = {username}
202
+
203
+ chars = list(pattern)
204
+
205
+ # generate permutations of length 1 → len(chars)
206
+ for r in range(1, len(chars) + 1):
207
+ for combo in permutations(chars, r):
208
+ permutations_set.add(username + ''.join(combo))
209
+ if limit and len(permutations_set) >= limit:
210
+ return list(permutations_set)[:limit]
211
+
212
+ return sorted(permutations_set)
@@ -0,0 +1,128 @@
1
+ from enum import Enum
2
+ from typing import Literal
3
+
4
+ DEBUG_MSG = """Result {{
5
+ status: {status},
6
+ reason: "{reason}",
7
+ username: "{username}",
8
+ site_name: "{site_name}",
9
+ category: "{category}",
10
+ }}"""
11
+
12
+ JSON_TEMPLATE = """{{
13
+ \t"username": "{username}",
14
+ \t"category": "{category}",
15
+ \t"site_name": "{site_name}",
16
+ \t"status": "{status}",
17
+ \t"reason": "{reason}"
18
+ }}"""
19
+
20
+ CSV_TEMPLATE = "{username},{category},{site_name},{status},{reason}"
21
+
22
+
23
+ def humanize_exception(e: Exception) -> str:
24
+ msg = str(e).lower()
25
+
26
+ if "10054" in msg:
27
+ return "Connection closed by remote server"
28
+ if "11001" in msg:
29
+ return "Could not resolve hostname"
30
+
31
+ return str(e)
32
+
33
+
34
+ class Status(Enum):
35
+ TAKEN = 0
36
+ AVAILABLE = 1
37
+ ERROR = 2
38
+
39
+ def __str__(self):
40
+ return super().__str__().split(".")[1].capitalize()
41
+
42
+
43
+ class Result:
44
+ def __init__(self, status: Status, reason: str | Exception | None = None, **kwargs):
45
+ self.status = status
46
+ self.reason = reason
47
+
48
+ self.username = None
49
+ self.site_name = None
50
+ self.category = None
51
+ self.update(**kwargs)
52
+
53
+ def update(self, **kwargs):
54
+ for field in ("username", "site_name", "category"):
55
+ if field in kwargs and kwargs[field] is not None:
56
+ setattr(self, field, kwargs[field])
57
+
58
+ @classmethod
59
+ def taken(cls, **kwargs):
60
+ return cls(Status.TAKEN, **kwargs)
61
+
62
+ @classmethod
63
+ def available(cls, **kwargs):
64
+ return cls(Status.AVAILABLE, **kwargs)
65
+
66
+ @classmethod
67
+ def error(cls, reason: str | Exception | None = None, **kwargs):
68
+ return cls(Status.ERROR, reason, **kwargs)
69
+
70
+ @classmethod
71
+ def from_number(cls, i: int, reason: str | Exception | None = None):
72
+ try:
73
+ status = Status(i)
74
+ except ValueError:
75
+ return cls(Status.ERROR, "Invalid status. Please contact maintainers.")
76
+
77
+ return cls(status, reason if status == Status.ERROR else None)
78
+
79
+ def to_number(self) -> int:
80
+ return self.status.value
81
+
82
+ def has_reason(self) -> bool:
83
+ return self.reason != None
84
+
85
+ def get_reason(self) -> str:
86
+ if self.reason == None:
87
+ return ""
88
+ if isinstance(self.reason, str):
89
+ return self.reason
90
+ # Format the exception
91
+ msg = humanize_exception(self.reason)
92
+ return f"{type(self.reason).__name__}: {msg.capitalize()}"
93
+
94
+ def as_dict(self) -> dict:
95
+ return {
96
+ "status": self.status,
97
+ "reason": self.get_reason(),
98
+ "username": self.username,
99
+ "site_name": self.site_name,
100
+ "category": self.category
101
+ }
102
+
103
+ def debug(self) -> str:
104
+ return DEBUG_MSG.format(**self.as_dict())
105
+
106
+ def to_json(self) -> str:
107
+ return JSON_TEMPLATE.format(**self.as_dict())
108
+
109
+ def to_csv(self) -> str:
110
+ return CSV_TEMPLATE.format(**self.as_dict())
111
+
112
+ def __str__(self):
113
+ return self.get_reason()
114
+
115
+ def __eq__(self, other):
116
+ if isinstance(other, Status):
117
+ return self.status == other
118
+
119
+ if isinstance(other, Result):
120
+ return self.status == other.status
121
+
122
+ if isinstance(other, int):
123
+ return self.to_number() == other
124
+
125
+ return NotImplemented
126
+
127
+
128
+ AnyResult = Literal[0, 1, 2] | Result
@@ -0,0 +1,9 @@
1
+ def get_site_name(module) -> str:
2
+ name = module.__name__.split('.')[-1].capitalize().replace("_", ".")
3
+ if name == "X":
4
+ return "X (Twitter)"
5
+ return name
6
+
7
+
8
+ def is_last_value(values, i: int) -> bool:
9
+ return i == len(values) - 1
@@ -1,37 +1,19 @@
1
- import httpx
2
- from httpx import ConnectError, TimeoutException
1
+ from user_scanner.core.orchestrator import status_validate
2
+
3
3
 
4
4
  def validate_devto(user):
5
5
  url = f"https://dev.to/{user}"
6
6
 
7
- headers = {
8
- 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
9
- '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",
10
- }
11
-
12
- try:
13
- response = httpx.head(url, headers=headers, timeout=3.0, follow_redirects=True)
14
- status = response.status_code
15
-
16
- if status == 200:
17
- return 0
18
- elif status == 404:
19
- return 1
20
- else:
21
- return 2
7
+ return status_validate(url, 404, 200, follow_redirects=True)
22
8
 
23
- except (ConnectError, TimeoutException):
24
- return 2
25
- except Exception:
26
- return 2
27
9
 
28
10
  if __name__ == "__main__":
29
- user = input ("Username?: ").strip()
30
- result = validate_devto(user)
11
+ user = input("Username?: ").strip()
12
+ result = validate_devto(user)
31
13
 
32
- if result == 1:
33
- print("Available!")
34
- elif result == 0:
35
- print("Unavailable!")
36
- else:
37
- print("Error occurred!")
14
+ if result == 1:
15
+ print("Available!")
16
+ elif result == 0:
17
+ print("Unavailable!")
18
+ else:
19
+ print("Error occurred!")
@@ -1,21 +1,21 @@
1
1
  import httpx
2
- import json
3
- from httpx import ConnectError, TimeoutException
2
+ from user_scanner.core.result import Result
3
+
4
4
 
5
5
  def validate_hashnode(user):
6
6
  url = "https://hashnode.com/utility/ajax/check-username"
7
7
 
8
8
  payload = {
9
- "username": user,
10
- "name": "Dummy Dummy"
9
+ "username": user,
10
+ "name": "Dummy Dummy"
11
11
  }
12
12
 
13
13
  headers = {
14
- 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36",
15
- 'Accept': "application/json",
16
- 'Content-Type': "application/json",
17
- 'Origin': "https://hashnode.com",
18
- 'Referer': "https://hashnode.com/signup",
14
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36",
15
+ 'Accept': "application/json",
16
+ 'Content-Type': "application/json",
17
+ 'Origin': "https://hashnode.com",
18
+ 'Referer': "https://hashnode.com/signup",
19
19
  }
20
20
 
21
21
  try:
@@ -26,29 +26,26 @@ def validate_hashnode(user):
26
26
 
27
27
  if 'status' in data:
28
28
  if data['status'] == 1:
29
- return 1
29
+ return Result.available()
30
30
  elif data['status'] == 0:
31
- return 0
31
+ return Result.taken()
32
32
 
33
- return 2
33
+ return Result.error("Status not found")
34
34
 
35
35
  else:
36
- return 2
36
+ return Result.error("Invalid status code")
37
+
38
+ except Exception as e:
39
+ return Result.error(e)
37
40
 
38
- except (ConnectError, TimeoutException):
39
- return 2
40
- except json.JSONDecodeError:
41
- return 2
42
- except Exception:
43
- return 2
44
41
 
45
42
  if __name__ == "__main__":
46
- user = input ("Username?: ").strip()
47
- result = validate_hashnode(user)
48
-
49
- if result == 1:
50
- print("Available!")
51
- elif result == 0:
52
- print("Unavailable!")
53
- else:
54
- print("Error occurred!")
43
+ user = input("Username?: ").strip()
44
+ result = validate_hashnode(user)
45
+
46
+ if result == 1:
47
+ print("Available!")
48
+ elif result == 0:
49
+ print("Unavailable!")
50
+ else:
51
+ print("Error occurred!")
@@ -0,0 +1,19 @@
1
+ from user_scanner.core.orchestrator import status_validate
2
+
3
+
4
+ def validate_itch_io(user):
5
+ url = f"https://{user}.itch.io"
6
+
7
+ return status_validate(url, 404, 200, follow_redirects=True)
8
+
9
+
10
+ if __name__ == "__main__":
11
+ user = input("Username?: ").strip()
12
+ result = validate_itch_io(user)
13
+
14
+ if result == 1:
15
+ print("Available!")
16
+ elif result == 0:
17
+ print("Unavailable!")
18
+ else:
19
+ print("Error occurred!")
@@ -1,37 +1,19 @@
1
- import httpx
2
- from httpx import ConnectError, TimeoutException
1
+ from user_scanner.core.orchestrator import status_validate
2
+
3
3
 
4
4
  def validate_kaggle(user):
5
5
  url = f"https://www.kaggle.com/{user}"
6
6
 
7
- headers = {
8
- 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36",
9
- 'Accept': "text/html",
10
- }
11
-
12
- try:
13
- response = httpx.get(url, headers=headers, timeout=3.0, follow_redirects=True)
14
- status = response.status_code
15
-
16
- if status == 200:
17
- return 0
18
- elif status == 404:
19
- return 1
20
- else:
21
- return 2
7
+ return status_validate(url, 404, 200, follow_redirects=True)
22
8
 
23
- except (ConnectError, TimeoutException):
24
- return 2
25
- except Exception:
26
- return 2
27
9
 
28
10
  if __name__ == "__main__":
29
- user = input ("Username?: ").strip()
30
- result = validate_kaggle(user)
11
+ user = input("Username?: ").strip()
12
+ result = validate_kaggle(user)
31
13
 
32
- if result == 1:
33
- print("Available!")
34
- elif result == 0:
35
- print("Unavailable!")
36
- else:
37
- print("Error occurred!")
14
+ if result == 1:
15
+ print("Available!")
16
+ elif result == 0:
17
+ print("Unavailable!")
18
+ else:
19
+ print("Error occurred!")
@@ -1,5 +1,6 @@
1
- import httpx
2
- from httpx import ConnectError, TimeoutException
1
+ from user_scanner.core.orchestrator import generic_validate
2
+ from user_scanner.core.result import Result
3
+
3
4
 
4
5
  def validate_medium(user):
5
6
  url = f"https://medium.com/@{user}"
@@ -9,33 +10,28 @@ def validate_medium(user):
9
10
  'Accept': "text/html",
10
11
  }
11
12
 
12
- try:
13
- response = httpx.get(url, headers=headers, timeout=3.0)
14
-
13
+ def process(response):
15
14
  if response.status_code == 200:
16
15
  html_text = response.text
17
16
 
18
-
19
17
  username_tag = f'property="profile:username" content="{user}"'
20
18
 
21
19
  if username_tag in html_text:
22
- return 0
20
+ return Result.taken()
23
21
  else:
24
- return 1
25
- return 2
22
+ return Result.available()
23
+ return Result.error()
24
+
25
+ return generic_validate(url, process, headers=headers)
26
26
 
27
- except (ConnectError, TimeoutException):
28
- return 2
29
- except Exception:
30
- return 2
31
27
 
32
28
  if __name__ == "__main__":
33
- user = input ("Username?: ").strip()
34
- result = validate_medium(user)
35
-
36
- if result == 1:
37
- print("Available!")
38
- elif result == 0:
39
- print("Unavailable!")
40
- else:
41
- print("Error occurred!")
29
+ user = input("Username?: ").strip()
30
+ result = validate_medium(user)
31
+
32
+ if result == 1:
33
+ print("Available!")
34
+ elif result == 0:
35
+ print("Unavailable!")
36
+ else:
37
+ print("Error occurred!")