user-scanner 1.0.5.0__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 +113 -64
  3. user_scanner/cli/banner.py +2 -0
  4. user_scanner/cli/printer.py +117 -0
  5. user_scanner/community/__init__.py +1 -0
  6. user_scanner/community/coderlegion.py +15 -14
  7. user_scanner/community/stackoverflow.py +35 -0
  8. user_scanner/core/orchestrator.py +167 -95
  9. user_scanner/core/result.py +128 -0
  10. user_scanner/core/utils.py +9 -0
  11. user_scanner/creator/devto.py +13 -11
  12. user_scanner/creator/hashnode.py +25 -28
  13. user_scanner/creator/itch_io.py +12 -15
  14. user_scanner/creator/kaggle.py +12 -11
  15. user_scanner/creator/medium.py +18 -22
  16. user_scanner/creator/patreon.py +12 -16
  17. user_scanner/creator/producthunt.py +38 -31
  18. user_scanner/dev/codeberg.py +13 -11
  19. user_scanner/dev/cratesio.py +19 -17
  20. user_scanner/dev/dockerhub.py +17 -15
  21. user_scanner/dev/github.py +46 -27
  22. user_scanner/dev/gitlab.py +18 -15
  23. user_scanner/dev/huggingface.py +19 -0
  24. user_scanner/dev/launchpad.py +19 -17
  25. user_scanner/dev/npmjs.py +21 -34
  26. user_scanner/dev/replit.py +13 -11
  27. user_scanner/donation/buymeacoffee.py +10 -12
  28. user_scanner/donation/liberapay.py +36 -0
  29. user_scanner/gaming/chess_com.py +17 -20
  30. user_scanner/gaming/minecraft.py +19 -0
  31. user_scanner/gaming/monkeytype.py +7 -12
  32. user_scanner/gaming/osu.py +13 -16
  33. user_scanner/gaming/roblox.py +35 -26
  34. user_scanner/gaming/steam.py +18 -19
  35. user_scanner/social/bluesky.py +20 -24
  36. user_scanner/social/discord.py +17 -21
  37. user_scanner/social/instagram.py +22 -20
  38. user_scanner/social/mastodon.py +12 -16
  39. user_scanner/social/pinterest.py +15 -13
  40. user_scanner/social/reddit.py +16 -13
  41. user_scanner/social/snapchat.py +28 -26
  42. user_scanner/social/soundcloud.py +43 -0
  43. user_scanner/social/telegram.py +19 -17
  44. user_scanner/social/threads.py +23 -21
  45. user_scanner/social/x.py +20 -28
  46. user_scanner/social/youtube.py +41 -47
  47. user_scanner/utils/update.py +0 -0
  48. user_scanner/utils/version.py +2 -0
  49. user_scanner/version.json +1 -1
  50. {user_scanner-1.0.5.0.dist-info → user_scanner-1.0.9.0.dist-info}/METADATA +58 -23
  51. user_scanner-1.0.9.0.dist-info/RECORD +61 -0
  52. user_scanner-1.0.5.0.dist-info/RECORD +0 -52
  53. {user_scanner-1.0.5.0.dist-info → user_scanner-1.0.9.0.dist-info}/WHEEL +0 -0
  54. {user_scanner-1.0.5.0.dist-info → user_scanner-1.0.9.0.dist-info}/entry_points.txt +0 -0
  55. {user_scanner-1.0.5.0.dist-info → user_scanner-1.0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,93 +1,144 @@
1
1
  import importlib
2
- import pkgutil
2
+ import importlib.util
3
3
  from colorama import Fore, Style
4
- import threading
5
-
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from itertools import permutations
6
6
  import httpx
7
- from httpx import ConnectError, TimeoutException
8
-
9
- lock = threading.Condition()
10
- #Basically which thread is the one to print
11
- print_queue = 0
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
12
12
 
13
- def load_modules(package):
14
13
 
14
+ def load_modules(category_path: Path):
15
15
  modules = []
16
- for _, name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."):
17
- try:
18
- module = importlib.import_module(name)
19
- modules.append(module)
20
- except Exception as e:
21
- 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)
22
24
  return modules
23
25
 
24
- def worker_single(module, username, i):
25
- global print_queue
26
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:
27
68
  func = next((getattr(module, f) for f in dir(module)
28
69
  if f.startswith("validate_") and callable(getattr(module, f))), None)
29
- site_name = module.__name__.split('.')[-1].capitalize().replace("_",".")
30
- if site_name == "X":
31
- site_name = "X (Twitter)"
32
-
33
- output = ""
34
- if func:
35
- try:
36
- result = func(username)
37
- if result == 1:
38
- output = f" {Fore.GREEN}[✔] {site_name}: Available{Style.RESET_ALL}"
39
- elif result == 0:
40
- output = f" {Fore.RED}[✘] {site_name}: Taken{Style.RESET_ALL}"
41
- else:
42
- output = f" {Fore.YELLOW}[!] {site_name}: Error{Style.RESET_ALL}"
43
- except Exception as e:
44
- output = f" {Fore.YELLOW}[!] {site_name}: Exception - {e}{Style.RESET_ALL}"
45
- else:
46
- output = f" {Fore.YELLOW}[!] {site_name} has no validate_ function{Style.RESET_ALL}"
47
-
48
- with lock:
49
- #Waits for in-order printing
50
- while i != print_queue:
51
- lock.wait()
52
-
53
- print(output)
54
- print_queue += 1
55
- lock.notify_all()
56
-
57
- def run_module_single(module, username):
58
- #Just executes as if it was a thread
59
- worker_single(module, username, print_queue)
60
-
61
- def run_checks_category(package, username, verbose=False):
62
- global print_queue
63
-
64
- modules = load_modules(package)
65
- category_name = package.__name__.split('.')[-1].capitalize()
66
- print(f"{Fore.MAGENTA}== {category_name} SITES =={Style.RESET_ALL}")
67
-
68
- print_queue = 0
69
-
70
- threads = []
71
- for i, module in enumerate(modules):
72
- t = threading.Thread(target=worker_single, args=(module, username, i))
73
- threads.append(t)
74
- t.start()
75
-
76
- for t in threads:
77
- t.join()
78
-
79
- def run_checks(username):
80
- from user_scanner import dev, social, creator, community, gaming, donation
81
-
82
- packages = [dev, social, creator, community, gaming, donation]
83
-
84
- print(f"\n{Fore.CYAN} Checking username: {username}{Style.RESET_ALL}\n")
85
-
86
- for package in packages:
87
- run_checks_category(package, username)
88
- print()
89
-
90
- def make_get_request(url, **kwargs):
70
+
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:
91
142
  """Simple wrapper to **httpx.get** that predefines headers and timeout"""
92
143
  if not "headers" in kwargs:
93
144
  kwargs["headers"] = {
@@ -103,38 +154,59 @@ def make_get_request(url, **kwargs):
103
154
 
104
155
  return httpx.get(url, **kwargs)
105
156
 
106
- def generic_validate(url, func, **kwargs):
157
+
158
+ def generic_validate(url: str, func: Callable[[httpx.Response], AnyResult], **kwargs) -> AnyResult:
107
159
  """
108
160
  A generic validate function that makes a request and executes the provided function on the response.
109
161
  """
110
162
  try:
111
163
  response = make_get_request(url, **kwargs)
112
- return func(response)
113
- except (ConnectError, TimeoutException):
114
- return 2
115
- except Exception:
116
- return 2
117
-
118
- def status_validate(url, available, taken, **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:
119
172
  """
120
173
  Function that takes a **url** and **kwargs** for the request and
121
174
  checks if the request status matches the availabe or taken.
122
175
  **Available** and **Taken** must either be whole numbers or lists of whole numbers.
123
176
  """
124
- def inner(response):
125
- #Checks if a number is equal or is contained inside
126
- contains = lambda a,b: (isinstance(a,list) and b in a) or (a == b)
127
-
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)
128
180
  status = response.status_code
129
181
  available_value = contains(available, status)
130
182
  taken_value = contains(taken, status)
131
183
 
132
184
  if available_value and taken_value:
133
- return 2 # Can't be both available and taken
185
+ # Can't be both available and taken
186
+ return Result.error("Invalid status match. Report this on Github.")
134
187
  elif available_value:
135
- return 1
188
+ return Result.available()
136
189
  elif taken_value:
137
- return 0
138
- return 2
190
+ return Result.taken()
191
+ return Result.error("Status didn't match. Report this on Github.")
139
192
 
140
193
  return generic_validate(url, inner, **kwargs)
194
+
195
+
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,17 +1,19 @@
1
- from ..core.orchestrator import status_validate
1
+ from user_scanner.core.orchestrator import status_validate
2
+
2
3
 
3
4
  def validate_devto(user):
4
- url = f"https://dev.to/{user}"
5
+ url = f"https://dev.to/{user}"
6
+
7
+ return status_validate(url, 404, 200, follow_redirects=True)
5
8
 
6
- return status_validate(url, 404, 200, follow_redirects = True)
7
9
 
8
10
  if __name__ == "__main__":
9
- user = input ("Username?: ").strip()
10
- result = validate_devto(user)
11
+ user = input("Username?: ").strip()
12
+ result = validate_devto(user)
11
13
 
12
- if result == 1:
13
- print("Available!")
14
- elif result == 0:
15
- print("Unavailable!")
16
- else:
17
- 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!")
@@ -1,22 +1,19 @@
1
- from ..core.orchestrator import status_validate
1
+ from user_scanner.core.orchestrator import status_validate
2
2
 
3
- def validate_itch_io(user):
4
- """
5
- Checks if a itch.io username is available.
6
- Returns: 1 -> available, 0 -> taken, 2 -> error
7
- """
8
3
 
4
+ def validate_itch_io(user):
9
5
  url = f"https://{user}.itch.io"
10
6
 
11
- return status_validate(url, 404, 200, follow_redirects = True)
7
+ return status_validate(url, 404, 200, follow_redirects=True)
8
+
12
9
 
13
10
  if __name__ == "__main__":
14
- user = input ("Username?: ").strip()
15
- result = validate_itch_io(user)
11
+ user = input("Username?: ").strip()
12
+ result = validate_itch_io(user)
16
13
 
17
- if result == 1:
18
- print("Available!")
19
- elif result == 0:
20
- print("Unavailable!")
21
- else:
22
- print("Error occurred!")
14
+ if result == 1:
15
+ print("Available!")
16
+ elif result == 0:
17
+ print("Unavailable!")
18
+ else:
19
+ print("Error occurred!")
@@ -1,18 +1,19 @@
1
- from ..core.orchestrator import status_validate
1
+ from user_scanner.core.orchestrator import status_validate
2
+
2
3
 
3
4
  def validate_kaggle(user):
4
- url = f"https://www.kaggle.com/{user}"
5
+ url = f"https://www.kaggle.com/{user}"
5
6
 
6
- return status_validate(url, 404, 200, follow_redirects=True)
7
+ return status_validate(url, 404, 200, follow_redirects=True)
7
8
 
8
9
 
9
10
  if __name__ == "__main__":
10
- user = input ("Username?: ").strip()
11
- result = validate_kaggle(user)
11
+ user = input("Username?: ").strip()
12
+ result = validate_kaggle(user)
12
13
 
13
- if result == 1:
14
- print("Available!")
15
- elif result == 0:
16
- print("Unavailable!")
17
- else:
18
- 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!")