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.
- user_scanner/__init__.py +0 -1
- user_scanner/__main__.py +114 -61
- user_scanner/cli/banner.py +3 -8
- user_scanner/cli/printer.py +117 -0
- user_scanner/community/__init__.py +1 -0
- user_scanner/community/coderlegion.py +11 -31
- user_scanner/community/stackoverflow.py +35 -0
- user_scanner/core/orchestrator.py +199 -79
- user_scanner/core/result.py +128 -0
- user_scanner/core/utils.py +9 -0
- user_scanner/creator/devto.py +11 -29
- user_scanner/creator/hashnode.py +25 -28
- user_scanner/creator/itch_io.py +19 -0
- user_scanner/creator/kaggle.py +11 -29
- user_scanner/creator/medium.py +18 -22
- user_scanner/creator/patreon.py +12 -38
- user_scanner/creator/producthunt.py +47 -0
- user_scanner/dev/codeberg.py +11 -29
- user_scanner/dev/cratesio.py +11 -24
- user_scanner/dev/dockerhub.py +11 -27
- user_scanner/dev/github.py +43 -39
- user_scanner/dev/gitlab.py +21 -32
- user_scanner/dev/huggingface.py +19 -0
- user_scanner/dev/launchpad.py +11 -24
- user_scanner/dev/npmjs.py +21 -34
- user_scanner/dev/replit.py +11 -29
- user_scanner/donation/__init__.py +0 -0
- user_scanner/donation/buymeacoffee.py +19 -0
- user_scanner/donation/liberapay.py +36 -0
- user_scanner/gaming/chess_com.py +20 -36
- user_scanner/gaming/minecraft.py +19 -0
- user_scanner/gaming/monkeytype.py +8 -26
- user_scanner/gaming/osu.py +13 -38
- user_scanner/gaming/roblox.py +37 -42
- user_scanner/gaming/steam.py +29 -0
- user_scanner/social/bluesky.py +21 -38
- user_scanner/social/discord.py +17 -21
- user_scanner/social/instagram.py +11 -24
- user_scanner/social/mastodon.py +12 -38
- user_scanner/social/pinterest.py +18 -32
- user_scanner/social/reddit.py +19 -32
- user_scanner/social/snapchat.py +24 -37
- user_scanner/social/soundcloud.py +43 -0
- user_scanner/social/telegram.py +19 -24
- user_scanner/social/threads.py +11 -24
- user_scanner/social/x.py +20 -28
- user_scanner/social/youtube.py +41 -47
- user_scanner/utils/version.py +2 -0
- user_scanner/version.json +1 -1
- {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/METADATA +62 -67
- user_scanner-1.0.9.0.dist-info/RECORD +61 -0
- user_scanner-1.0.2.1.dist-info/RECORD +0 -48
- {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/WHEEL +0 -0
- {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/entry_points.txt +0 -0
- {user_scanner-1.0.2.1.dist-info → user_scanner-1.0.9.0.dist-info}/licenses/LICENSE +0 -0
user_scanner/__init__.py
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
user_scanner/__main__.py
CHANGED
|
@@ -1,38 +1,15 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import time
|
|
2
3
|
import re
|
|
3
|
-
from user_scanner.
|
|
4
|
+
from user_scanner.cli import printer
|
|
5
|
+
from user_scanner.core.orchestrator import generate_permutations, load_categories
|
|
4
6
|
from colorama import Fore, Style
|
|
5
|
-
from .cli import
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"social": "social",
|
|
12
|
-
"creator": "creator",
|
|
13
|
-
"community": "community",
|
|
14
|
-
"gaming": "gaming"
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
def list_modules(category=None):
|
|
18
|
-
from user_scanner import dev, social, creator, community, gaming
|
|
19
|
-
packages = {
|
|
20
|
-
"dev": dev,
|
|
21
|
-
"social": social,
|
|
22
|
-
"creator": creator,
|
|
23
|
-
"community": community,
|
|
24
|
-
"gaming": gaming
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
categories_to_list = [category] if category else packages.keys()
|
|
28
|
-
|
|
29
|
-
for cat_name in categories_to_list:
|
|
30
|
-
package = packages[cat_name]
|
|
31
|
-
modules = load_modules(package)
|
|
32
|
-
print(Fore.MAGENTA + f"\n== {cat_name.upper()} SITES =={Style.RESET_ALL}")
|
|
33
|
-
for module in modules:
|
|
34
|
-
site_name = module.__name__.split(".")[-1]
|
|
35
|
-
print(f" - {site_name}")
|
|
7
|
+
from user_scanner.cli.banner import print_banner
|
|
8
|
+
from typing import List
|
|
9
|
+
from user_scanner.core.result import Result
|
|
10
|
+
from user_scanner.core.utils import is_last_value
|
|
11
|
+
|
|
12
|
+
MAX_PERMUTATIONS_LIMIT = 100 # To prevent excessive generation
|
|
36
13
|
|
|
37
14
|
def main():
|
|
38
15
|
parser = argparse.ArgumentParser(
|
|
@@ -43,7 +20,7 @@ def main():
|
|
|
43
20
|
"-u", "--username", help="Username to scan across platforms"
|
|
44
21
|
)
|
|
45
22
|
parser.add_argument(
|
|
46
|
-
"-c", "--category", choices=
|
|
23
|
+
"-c", "--category", choices=load_categories().keys(),
|
|
47
24
|
help="Scan all platforms in a category"
|
|
48
25
|
)
|
|
49
26
|
parser.add_argument(
|
|
@@ -56,51 +33,127 @@ def main():
|
|
|
56
33
|
"-v", "--verbose", action="store_true", help="Enable verbose output"
|
|
57
34
|
)
|
|
58
35
|
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"-p", "--permute",type=str,help="Generate username permutations using a string pattern (e.g -p 234)"
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"-s", "--stop",type=int,default=MAX_PERMUTATIONS_LIMIT,help="Limit the number of username permutations generated"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"-d", "--delay",type=float,default=0,help="Delay in seconds between requests (recommended: 1-2 seconds)"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"-f", "--format", choices=["console", "csv", "json"], default="console", help="Specify the output format (default: console)"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-o", "--output", type=str, help="Specify the output file"
|
|
53
|
+
)
|
|
54
|
+
|
|
59
55
|
args = parser.parse_args()
|
|
60
56
|
|
|
57
|
+
Printer = printer.Printer(args.format)
|
|
58
|
+
|
|
61
59
|
if args.list:
|
|
62
|
-
|
|
60
|
+
Printer.print_modules(args.category)
|
|
63
61
|
return
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
# Special username checks before run
|
|
67
|
-
if (args.module == "x" or args.category == "social"):
|
|
68
|
-
if re.search(r"[^a-zA-Z0-9._-]", args.username):
|
|
69
|
-
print(Fore.RED + f"[!] Username '{args.username}' contains unsupported special characters. X (Twitter) doesn't support these." + Style.RESET_ALL)
|
|
70
|
-
if (args.module == "bluesky" or args.category == "social"):
|
|
71
|
-
if re.search(r"[^a-zA-Z0-9\.-]", args.username):
|
|
72
|
-
print(Fore.RED + f"[!] Username '{args.username}' contains unsupported special characters. Bluesky will throw error. (Supported: only hyphens and digits)" + Style.RESET_ALL +"\n")
|
|
73
63
|
if not args.username:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
else:
|
|
77
|
-
print_banner()
|
|
64
|
+
parser.print_help()
|
|
65
|
+
return
|
|
78
66
|
|
|
79
67
|
|
|
80
|
-
|
|
68
|
+
if Printer.is_console:
|
|
69
|
+
print_banner()
|
|
70
|
+
|
|
71
|
+
if args.permute and args.delay == 0 and Printer.is_console:
|
|
72
|
+
print(
|
|
73
|
+
Fore.YELLOW
|
|
74
|
+
+ "[!] Warning: You're generating multiple usernames with NO delay between requests. "
|
|
75
|
+
"This may trigger rate limits or IP bans. Use --delay 1 or higher. (Use only if the sites throw errors otherwise ignore)\n"
|
|
76
|
+
+ Style.RESET_ALL)
|
|
77
|
+
|
|
78
|
+
usernames = [args.username] # Default single username list
|
|
79
|
+
|
|
80
|
+
#Added permutation support , generate all possible permutation of given sequence.
|
|
81
|
+
if args.permute:
|
|
82
|
+
usernames = generate_permutations(args.username, args.permute , args.stop)
|
|
83
|
+
if Printer.is_console:
|
|
84
|
+
print(
|
|
85
|
+
Fore.CYAN + f"[+] Generated {len(usernames)} username permutations" + Style.RESET_ALL)
|
|
86
|
+
|
|
87
|
+
if args.module and "." in args.module:
|
|
88
|
+
args.module = args.module.replace(".", "_")
|
|
89
|
+
|
|
90
|
+
def run_all_usernames(func, arg = None) -> List[Result]:
|
|
91
|
+
"""
|
|
92
|
+
Executes a function for all given usernames.
|
|
93
|
+
Made in order to simplify main()
|
|
94
|
+
"""
|
|
95
|
+
results = []
|
|
96
|
+
print(Printer.get_start())
|
|
97
|
+
for i, name in enumerate(usernames):
|
|
98
|
+
is_last = i == len(usernames) - 1
|
|
99
|
+
if arg == None:
|
|
100
|
+
results.extend(func(name, Printer, is_last))
|
|
101
|
+
else:
|
|
102
|
+
results.extend(func(arg, name, Printer, is_last))
|
|
103
|
+
if args.delay > 0 and not is_last:
|
|
104
|
+
time.sleep(args.delay)
|
|
105
|
+
if Printer.is_json:
|
|
106
|
+
print(Printer.get_end())
|
|
107
|
+
return results
|
|
108
|
+
|
|
109
|
+
results = []
|
|
81
110
|
|
|
82
111
|
if args.module:
|
|
83
112
|
# Single module search across all categories
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
113
|
+
from user_scanner.core.orchestrator import run_module_single, find_module
|
|
114
|
+
modules = find_module(args.module)
|
|
115
|
+
|
|
116
|
+
if len(modules) > 0:
|
|
88
117
|
for module in modules:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if not found:
|
|
95
|
-
print(Fore.RED + f"[!] Module '{args.module}' not found in any category." + Style.RESET_ALL)
|
|
118
|
+
results.extend(run_all_usernames(run_module_single, module))
|
|
119
|
+
else:
|
|
120
|
+
print(
|
|
121
|
+
Fore.RED + f"[!] Module '{args.module}' not found in any category." + Style.RESET_ALL)
|
|
122
|
+
|
|
96
123
|
elif args.category:
|
|
97
124
|
# Category-wise scan
|
|
98
|
-
category_package =
|
|
125
|
+
category_package = load_categories().get(args.category)
|
|
99
126
|
from user_scanner.core.orchestrator import run_checks_category
|
|
100
|
-
run_checks_category
|
|
127
|
+
results = run_all_usernames(run_checks_category, category_package)
|
|
128
|
+
|
|
101
129
|
else:
|
|
102
130
|
# Full scan
|
|
103
|
-
run_checks
|
|
131
|
+
from user_scanner.core.orchestrator import run_checks
|
|
132
|
+
results = run_all_usernames(run_checks)
|
|
133
|
+
|
|
134
|
+
if not args.output:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if args.output and Printer.is_console:
|
|
138
|
+
msg = (
|
|
139
|
+
"\n[!] The console format cannot be "
|
|
140
|
+
f"written to file: '{args.output}'."
|
|
141
|
+
)
|
|
142
|
+
print(Fore.RED + msg + Style.RESET_ALL)
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
content = Printer.get_start()
|
|
146
|
+
|
|
147
|
+
for i,result in enumerate(results):
|
|
148
|
+
char = "" if Printer.is_csv or is_last_value(results, i) else ","
|
|
149
|
+
content += "\n" + Printer.get_result_output(result) + char
|
|
150
|
+
|
|
151
|
+
if Printer.is_json:
|
|
152
|
+
content += "\n" + Printer.get_end()
|
|
153
|
+
|
|
154
|
+
with open(args.output, "a", encoding="utf-8") as f:
|
|
155
|
+
f.write(content)
|
|
156
|
+
|
|
104
157
|
|
|
105
158
|
if __name__ == "__main__":
|
|
106
159
|
main()
|
user_scanner/cli/banner.py
CHANGED
|
@@ -23,17 +23,12 @@ INFO_BOX = f"""{C_MAGENTA} ╔═══════════════
|
|
|
23
23
|
║ {C_RED}♚ {C_GREEN}Email{C_WHITE} : kaifcodec@gmail.com {C_MAGENTA}║
|
|
24
24
|
══════════════════════════════════════════{Style.RESET_ALL}""".strip()
|
|
25
25
|
|
|
26
|
+
|
|
26
27
|
def print_banner():
|
|
27
28
|
print(BANNER_ASCII)
|
|
28
29
|
print(INFO_BOX)
|
|
29
30
|
print(" ")
|
|
30
|
-
if __name__ == "__main__":
|
|
31
|
-
print_banner()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
31
|
|
|
39
32
|
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
print_banner()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from colorama import Fore, Style
|
|
2
|
+
from typing import Literal
|
|
3
|
+
from user_scanner.core.result import Result, Status
|
|
4
|
+
|
|
5
|
+
INDENT = " "
|
|
6
|
+
CSV_HEADER = "username,category,site_name,status,url,reason"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def indentate(msg: str, indent: int):
|
|
10
|
+
if indent <= 0:
|
|
11
|
+
return msg
|
|
12
|
+
tabs = INDENT * indent
|
|
13
|
+
return "\n".join([f"{tabs}{line}" for line in msg.split("\n")])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Printer:
|
|
17
|
+
def __init__(self, format: Literal["console", "csv", "json"]) -> None:
|
|
18
|
+
if not format in ["console", "csv", "json"]:
|
|
19
|
+
raise ValueError(f"Invalid output-format: {format}")
|
|
20
|
+
self.mode: str = format
|
|
21
|
+
self.indent: int = 0
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def is_console(self) -> bool:
|
|
25
|
+
return self.mode == "console"
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def is_csv(self) -> bool:
|
|
29
|
+
return self.mode == "csv"
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def is_json(self) -> bool:
|
|
33
|
+
return self.mode == "json"
|
|
34
|
+
|
|
35
|
+
def get_start(self, json_char: str = "[") -> str:
|
|
36
|
+
if self.is_json:
|
|
37
|
+
self.indent += 1
|
|
38
|
+
return indentate(json_char, self.indent - 1)
|
|
39
|
+
elif self.is_csv:
|
|
40
|
+
return CSV_HEADER
|
|
41
|
+
return ""
|
|
42
|
+
|
|
43
|
+
def get_end(self, json_char: str = "]") -> str:
|
|
44
|
+
if not self.is_json:
|
|
45
|
+
return
|
|
46
|
+
self.indent = max(self.indent - 1, 0)
|
|
47
|
+
return indentate(json_char, self.indent)
|
|
48
|
+
|
|
49
|
+
def get_result_output(self, result: Result) -> str:
|
|
50
|
+
#In principle result should always have this
|
|
51
|
+
site_name = result.site_name
|
|
52
|
+
username = result.username
|
|
53
|
+
|
|
54
|
+
match (result.status, self.mode):
|
|
55
|
+
case (Status.AVAILABLE, "console"):
|
|
56
|
+
return f"{INDENT}{Fore.GREEN}[✔] {site_name} ({username}): Available{Style.RESET_ALL}"
|
|
57
|
+
|
|
58
|
+
case (Status.TAKEN, "console"):
|
|
59
|
+
return f"{INDENT}{Fore.RED}[✘] {site_name} ({username}): Taken{Style.RESET_ALL}"
|
|
60
|
+
|
|
61
|
+
case (Status.ERROR, "console"):
|
|
62
|
+
reason = ""
|
|
63
|
+
if isinstance(result, Result) and result.has_reason():
|
|
64
|
+
reason = f" ({result.get_reason()})"
|
|
65
|
+
return f"{INDENT}{Fore.YELLOW}[!] {site_name} ({username}): Error{reason}{Style.RESET_ALL}"
|
|
66
|
+
|
|
67
|
+
case (_, "json"):
|
|
68
|
+
return indentate(result.to_json().replace("\t", INDENT), self.indent)
|
|
69
|
+
|
|
70
|
+
case (_, "csv"):
|
|
71
|
+
return result.to_csv()
|
|
72
|
+
|
|
73
|
+
return ""
|
|
74
|
+
|
|
75
|
+
def print_modules(self, category: str | None = None):
|
|
76
|
+
from user_scanner.core.orchestrator import load_categories, load_modules
|
|
77
|
+
categories = load_categories()
|
|
78
|
+
categories_to_list = [category] if category else categories.keys()
|
|
79
|
+
|
|
80
|
+
# Print the start
|
|
81
|
+
if self.is_json:
|
|
82
|
+
print(self.get_start("{"))
|
|
83
|
+
elif self.is_csv:
|
|
84
|
+
print("category,site_name")
|
|
85
|
+
|
|
86
|
+
for i, cat_name in enumerate(categories_to_list):
|
|
87
|
+
path = categories[cat_name]
|
|
88
|
+
modules = load_modules(path)
|
|
89
|
+
|
|
90
|
+
# Print for each category
|
|
91
|
+
match self.mode:
|
|
92
|
+
case "console":
|
|
93
|
+
print(Fore.MAGENTA +
|
|
94
|
+
f"\n== {cat_name.upper()} SITES =={Style.RESET_ALL}")
|
|
95
|
+
case "json":
|
|
96
|
+
print(self.get_start(f"\"{cat_name}\": ["))
|
|
97
|
+
|
|
98
|
+
for j, module in enumerate(modules):
|
|
99
|
+
is_last = j == len(modules) - 1
|
|
100
|
+
site_name = module.__name__.split(".")[-1].capitalize()
|
|
101
|
+
|
|
102
|
+
# Print for each site name
|
|
103
|
+
match self.mode:
|
|
104
|
+
case "console":
|
|
105
|
+
print(f"{INDENT}- {site_name}")
|
|
106
|
+
case "json":
|
|
107
|
+
msg = f"\"{site_name}\"" + ("" if is_last else ",")
|
|
108
|
+
print(indentate(msg, self.indent))
|
|
109
|
+
case "csv":
|
|
110
|
+
print(f"{cat_name},{site_name}")
|
|
111
|
+
|
|
112
|
+
if self.is_json:
|
|
113
|
+
is_last = i == len(categories_to_list) - 1
|
|
114
|
+
print(self.get_end("]" if is_last else "],"))
|
|
115
|
+
|
|
116
|
+
if self.is_json:
|
|
117
|
+
print(self.get_end("}"))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# community
|
|
@@ -1,39 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
from user_scanner.core.orchestrator import status_validate
|
|
2
|
+
|
|
3
3
|
|
|
4
4
|
def validate_coderlegion(user):
|
|
5
5
|
url = f"https://coderlegion.com/user/{user}"
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.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
|
-
'Accept-Encoding': "gzip, deflate, br",
|
|
11
|
-
'Accept-Language': "en-US,en;q=0.9",
|
|
12
|
-
}
|
|
13
|
-
try:
|
|
14
|
-
response = httpx.get(url, headers=headers, timeout = 15.0)
|
|
15
|
-
status = response.status_code
|
|
16
|
-
|
|
17
|
-
if status == 200:
|
|
18
|
-
return 0
|
|
19
|
-
elif status == 404:
|
|
20
|
-
return 1
|
|
21
|
-
else:
|
|
22
|
-
return 2
|
|
7
|
+
return status_validate(url, 404, 200, timeout=15.0)
|
|
23
8
|
|
|
24
|
-
except (ConnectError, TimeoutException):
|
|
25
|
-
return 2
|
|
26
|
-
except Exception:
|
|
27
|
-
return 2
|
|
28
9
|
|
|
29
10
|
if __name__ == "__main__":
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if result == 1:
|
|
34
|
-
print("Available!")
|
|
35
|
-
elif result == 0:
|
|
36
|
-
print("Unavailable!")
|
|
37
|
-
else:
|
|
38
|
-
print("Error occured!")
|
|
11
|
+
user = input("Username?: ").strip()
|
|
12
|
+
result = validate_coderlegion(user)
|
|
39
13
|
|
|
14
|
+
if result == 1:
|
|
15
|
+
print("Available!")
|
|
16
|
+
elif result == 0:
|
|
17
|
+
print("Unavailable!")
|
|
18
|
+
else:
|
|
19
|
+
print("Error occured!")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from user_scanner.core.orchestrator import generic_validate
|
|
2
|
+
from user_scanner.core.result import Result
|
|
3
|
+
|
|
4
|
+
def validate_stackoverflow(user: str) -> Result:
|
|
5
|
+
url = f"https://stackoverflow.com/users/filter?search={user}"
|
|
6
|
+
|
|
7
|
+
def process(response):
|
|
8
|
+
if response.status_code == 200:
|
|
9
|
+
text = response.text
|
|
10
|
+
|
|
11
|
+
if "No users matched your search." in text:
|
|
12
|
+
return Result.available()
|
|
13
|
+
|
|
14
|
+
pattern = f'>{user}<'
|
|
15
|
+
if pattern in text:
|
|
16
|
+
return Result.taken()
|
|
17
|
+
|
|
18
|
+
return Result.available()
|
|
19
|
+
|
|
20
|
+
return Result.error("Unexpected status code from Stack Overflow")
|
|
21
|
+
|
|
22
|
+
return generic_validate(url, process)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
user = input("Username?: ").strip()
|
|
27
|
+
result = validate_stackoverflow(user)
|
|
28
|
+
|
|
29
|
+
if result == Result.available():
|
|
30
|
+
print("Available!")
|
|
31
|
+
elif result == Result.taken():
|
|
32
|
+
print("Unavailable!")
|
|
33
|
+
else:
|
|
34
|
+
msg = result.get_reason()
|
|
35
|
+
print("Error occurred!" + msg)
|