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,42 +1,29 @@
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_reddit(user):
5
6
  url = f"https://www.reddit.com/user/{user}/"
6
7
 
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,*/*;q=0.8",
10
- 'Accept-Encoding': "gzip, deflate, br",
11
- 'Accept-Language': "en-US,en;q=0.9",
12
- 'sec-fetch-dest': "document",
13
- }
14
-
15
- NOT_FOUND_STRING = "Sorry, nobody on Reddit goes by that name."
16
-
17
- try:
18
- response = httpx.get(url, headers=headers, follow_redirects=True, timeout = 3.0)
19
-
8
+ def process(response):
20
9
  if response.status_code == 200:
21
- if NOT_FOUND_STRING in response.text:
22
- return 1
10
+ if "Sorry, nobody on Reddit goes by that name." in response.text:
11
+ return Result.available()
23
12
  else:
24
- return 0
13
+ return Result.taken()
25
14
  else:
26
- return 2
15
+ return Result.error()
27
16
 
28
- except (ConnectError, TimeoutException):
29
- return 2
30
- except Exception:
31
- return 2
17
+ return generic_validate(url, process, follow_redirects=True)
32
18
 
33
- if __name__ == "__main__":
34
- user = input ("Username?: ").strip()
35
- result = validate_reddit(user)
36
19
 
37
- if result == 1:
38
- print("Available!")
39
- elif result == 0:
40
- print("Unavailable!")
41
- else:
42
- print("Error occured!")
20
+ if __name__ == "__main__":
21
+ user = input("Username?: ").strip()
22
+ result = validate_reddit(user)
23
+
24
+ if result == 1:
25
+ print("Available!")
26
+ elif result == 0:
27
+ print("Unavailable!")
28
+ else:
29
+ print("Error occured!")
@@ -1,48 +1,35 @@
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_snapchat(user):
5
5
  url = f"https://www.snapchat.com/@{user}"
6
6
 
7
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,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, zstd",
11
- 'sec-ch-ua': "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
12
- 'sec-ch-ua-mobile': "?1",
13
- 'sec-ch-ua-platform': "\"Android\"",
14
- 'upgrade-insecure-requests': "1",
15
- 'sec-fetch-site': "none",
16
- 'sec-fetch-mode': "navigate",
17
- 'sec-fetch-user': "?1",
18
- 'sec-fetch-dest': "document",
19
- 'accept-language': "en-US,en;q=0.9",
20
- 'priority': "u=0, i"
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,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, zstd",
11
+ 'sec-ch-ua': "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
12
+ 'sec-ch-ua-mobile': "?1",
13
+ 'sec-ch-ua-platform': "\"Android\"",
14
+ 'upgrade-insecure-requests': "1",
15
+ 'sec-fetch-site': "none",
16
+ 'sec-fetch-mode': "navigate",
17
+ 'sec-fetch-user': "?1",
18
+ 'sec-fetch-dest': "document",
19
+ 'accept-language': "en-US,en;q=0.9",
20
+ 'priority': "u=0, i"
21
21
  }
22
22
 
23
- try:
24
- response = httpx.get(url, headers=headers, follow_redirects=True, timeout = 3.0)
25
- status = response.status_code
26
-
27
- if status == 200:
28
- return 0
29
- elif status == 404:
30
- return 1
31
- else:
32
- return 2
23
+ return status_validate(url, 404, 200, headers=headers, follow_redirects=True)
33
24
 
34
- except (ConnectError, TimeoutException):
35
- return 2
36
- except Exception:
37
- return 2
38
25
 
39
26
  if __name__ == "__main__":
40
- user = input ("Username?: ").strip()
41
- result = validate_snapchat(user)
27
+ user = input("Username?: ").strip()
28
+ result = validate_snapchat(user)
42
29
 
43
- if result == 1:
44
- print("Available!")
45
- elif result == 0:
46
- print("Unavailable!")
47
- else:
48
- print("Error occured!")
30
+ if result == 1:
31
+ print("Available!")
32
+ elif result == 0:
33
+ print("Unavailable!")
34
+ else:
35
+ print("Error occured!")
@@ -0,0 +1,43 @@
1
+ from user_scanner.core.orchestrator import generic_validate
2
+ from user_scanner.core.result import Result
3
+
4
+
5
+ def validate_soundcloud(user):
6
+ url = f"https://soundcloud.com/{user}"
7
+
8
+ headers = {
9
+ 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
10
+ 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
11
+ }
12
+
13
+ def process(response):
14
+ if response.status_code == 404:
15
+ return Result.available()
16
+
17
+ if response.status_code == 200:
18
+ text = response.text
19
+
20
+ if f'soundcloud://users:{user}' in text:
21
+ return Result.taken()
22
+ if f'"username":"{user}"' in text:
23
+ return Result.taken()
24
+ if 'soundcloud://users:' in text and '"username":"' in text:
25
+ return Result.taken()
26
+
27
+ return Result.available()
28
+
29
+ return Result.error()
30
+
31
+ return generic_validate(url, process, headers=headers, follow_redirects=True)
32
+
33
+
34
+ if __name__ == "__main__":
35
+ user = input("Username?: ").strip()
36
+ result = validate_soundcloud(user)
37
+
38
+ if result == 1:
39
+ print("Available!")
40
+ elif result == 0:
41
+ print("Unavailable!")
42
+ else:
43
+ print("Error occured!")
@@ -1,34 +1,29 @@
1
- import httpx
2
1
  import re
2
+ from user_scanner.core.orchestrator import generic_validate
3
+ from user_scanner.core.result import Result
4
+
3
5
 
4
6
  def validate_telegram(user: str) -> int:
5
- """
6
- Checks if a Telegram username is available.
7
- Returns: 1 -> available, 0 -> taken, 2 -> error
8
- """
9
7
  url = f"https://t.me/{user}"
10
- headers = {
11
- "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
12
- }
13
8
 
14
- try:
15
- r = httpx.get(url, headers=headers, follow_redirects=True, timeout=3.0)
9
+ def process(r):
16
10
  if r.status_code == 200:
17
- return 0 if re.search(r'<div[^>]*class="tgme_page_extra"[^>]*>', r.text) else 1
18
- return 2
19
- except (httpx.ConnectError, httpx.TimeoutException):
20
- return 2
21
- except Exception:
22
- return 2
11
+ if re.search(r'<div[^>]*class="tgme_page_extra"[^>]*>', r.text):
12
+ return Result.taken()
13
+ else:
14
+ return Result.available()
15
+ return Result.error()
16
+
17
+ return generic_validate(url, process, follow_redirects=True)
23
18
 
24
19
 
25
20
  if __name__ == "__main__":
26
- user = input ("Username?: ").strip()
27
- result = validate_telegram(user)
21
+ user = input("Username?: ").strip()
22
+ result = validate_telegram(user)
28
23
 
29
- if result == 1:
30
- print("Available!")
31
- elif result == 0:
32
- print("Unavailable!")
33
- else:
34
- print("Error occured!")
24
+ if result == 1:
25
+ print("Available!")
26
+ elif result == 0:
27
+ print("Unavailable!")
28
+ else:
29
+ print("Error occured!")
@@ -1,5 +1,5 @@
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_instagram(user):
5
5
  url = f"https://www.threads.com/api/v1/users/web_profile_info/?username={user}"
@@ -13,30 +13,17 @@ def validate_instagram(user):
13
13
  'X-Requested-With': "XMLHttpRequest",
14
14
  'Referer': f"https://www.instagram.com/{user}/",
15
15
  }
16
-
17
- try:
18
- response = httpx.get(url, headers=headers, timeout = 3.0)
19
- status = response.status_code
20
16
 
21
- if status == 200:
22
- return 0
23
- elif status == 404:
24
- return 1
25
- else:
26
- return 2
17
+ return status_validate(url, 404, 200, headers=headers)
27
18
 
28
- except (ConnectError, TimeoutException):
29
- return 2
30
- except Exception:
31
- return 2
32
19
 
33
20
  if __name__ == "__main__":
34
- user = input ("Username?: ").strip()
35
- result = validate_instagram(user)
21
+ user = input("Username?: ").strip()
22
+ result = validate_instagram(user)
36
23
 
37
- if result == 1:
38
- print("Available!")
39
- elif result == 0:
40
- print("Unavailable!")
41
- else:
42
- print("Error occured!")
24
+ if result == 1:
25
+ print("Available!")
26
+ elif result == 0:
27
+ print("Unavailable!")
28
+ else:
29
+ print("Error occured!")
user_scanner/social/x.py CHANGED
@@ -1,7 +1,5 @@
1
- import httpx
2
- import json
3
- from colorama import Fore, Style
4
- from httpx import ConnectError, TimeoutException
1
+ from user_scanner.core.result import Result
2
+ from user_scanner.core.orchestrator import generic_validate
5
3
 
6
4
  def validate_x(user):
7
5
  url = "https://api.twitter.com/i/users/username_available.json"
@@ -17,38 +15,32 @@ def validate_x(user):
17
15
  "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",
18
16
  }
19
17
 
20
- try:
21
- response = httpx.get(url, params=params, headers=headers, timeout = 3.0)
18
+ def process(response):
22
19
  status = response.status_code
23
- # print(response.text)
24
- if status in [401, 403, 429]:
25
- return 2
26
20
 
21
+ if status in [401, 403, 429]:
22
+ return Result.error()
27
23
 
28
24
  elif status == 200:
29
25
  data = response.json()
30
26
  if data.get('valid') is True:
31
- return 1
27
+ return Result.available()
32
28
  elif data.get('reason') == 'taken':
33
- return 0
29
+ return Result.taken()
34
30
  elif (data.get('reason') == "improper_format" or data.get('reason') == "invalid_username"):
35
- print("\n" +" "+f"{Fore.CYAN}X says: {data.get('desc')}{Style.RESET_ALL}")
36
- return 2
37
- else:
38
- return 2
31
+ return Result.error(f"X says: {data.get('desc')}")
32
+
33
+ return Result.error()
39
34
 
40
- except (ConnectError, TimeoutException, json.JSONDecodeError):
41
- return 2
42
- except Exception:
43
- return 2
35
+ return generic_validate(url, process, params=params, headers=headers)
44
36
 
45
37
  if __name__ == "__main__":
46
- user = input ("Username?: ").strip()
47
- result = validate_x(user)
48
-
49
- if result == 1:
50
- print("Available!")
51
- elif result == 0:
52
- print("Unavailable!")
53
- else:
54
- print("Error occured!")
38
+ user = input("Username?: ").strip()
39
+ result = validate_x(user)
40
+
41
+ if result == 1:
42
+ print("Available!")
43
+ elif result == 0:
44
+ print("Unavailable!")
45
+ else:
46
+ print("Error occured!")
@@ -1,56 +1,50 @@
1
- import httpx
2
- from httpx import ConnectError, TimeoutException
1
+ from user_scanner.core.orchestrator import status_validate, Result
3
2
 
4
- def validate_youtube(user):
5
- url = f"https://m.youtube.com/@{user}"
6
3
 
4
+ def validate_youtube(user) -> Result:
5
+ url = f"https://m.youtube.com/@{user}"
7
6
  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,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, zstd",
11
- 'device-memory': "4",
12
- 'sec-ch-ua': "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
13
- 'sec-ch-ua-mobile': "?1",
14
- 'sec-ch-ua-full-version': "\"141.0.7390.111\"",
15
- 'sec-ch-ua-arch': "\"\"",
16
- 'sec-ch-ua-platform': "\"Android\"",
17
- 'sec-ch-ua-platform-version': "\"15.0.0\"",
18
- 'sec-ch-ua-bitness': "\"\"",
19
- 'sec-ch-ua-wow64': "?0",
20
- 'sec-ch-ua-full-version-list': "\"Google Chrome\";v=\"141.0.7390.111\", \"Not?A_Brand\";v=\"8.0.0.0\", \"Chromium\";v=\"141.0.7390.111\"",
21
- 'sec-ch-ua-form-factors': "\"Mobile\"",
22
- 'upgrade-insecure-requests': "1",
23
- 'sec-fetch-site': "none",
24
- 'sec-fetch-mode': "navigate",
25
- 'sec-fetch-user': "?1",
26
- 'sec-fetch-dest': "document",
27
- 'accept-language': "en-US,en;q=0.9",
28
- 'priority': "u=0, i"
7
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
8
+ '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",
9
+ 'Accept-Encoding': "identity",
10
+ 'sec-ch-dpr': "2.75",
11
+ 'sec-ch-viewport-width': "980",
12
+ 'sec-ch-ua': "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"",
13
+ 'sec-ch-ua-mobile': "?1",
14
+ 'sec-ch-ua-full-version': "\"143.0.7499.52\"",
15
+ 'sec-ch-ua-arch': "\"\"",
16
+ 'sec-ch-ua-platform': "\"Android\"",
17
+ 'sec-ch-ua-platform-version': "\"15.0.0\"",
18
+ 'sec-ch-ua-model': "\"I2404\"",
19
+ 'sec-ch-ua-bitness': "\"\"",
20
+ 'sec-ch-ua-wow64': "?0",
21
+ 'sec-ch-ua-full-version-list': "\"Google Chrome\";v=\"143.0.7499.52\", \"Chromium\";v=\"143.0.7499.52\", \"Not A(Brand\";v=\"24.0.0.0\"",
22
+ 'sec-ch-ua-form-factors': "\"Mobile\"",
23
+ 'upgrade-insecure-requests': "1",
24
+ 'x-browser-channel': "stable",
25
+ 'x-browser-year': "2025",
26
+ 'x-browser-copyright': "Copyright 2025 Google LLC. All Rights reserved.",
27
+ 'sec-fetch-site': "none",
28
+ 'sec-fetch-mode': "navigate",
29
+ 'sec-fetch-user': "?1",
30
+ 'sec-fetch-dest': "document",
31
+ 'accept-language': "en-US,en;q=0.9",
32
+ 'priority': "u=0, i"
29
33
  }
30
34
 
31
- try:
32
- response = httpx.get(url, headers=headers, follow_redirects=True, timeout = 3.0)
33
- status = response.status_code
34
35
 
35
- if status == 200:
36
- return 0
37
- elif status == 404:
38
- return 1
39
- else:
40
- return 2
36
+ return status_validate(url, 404, 200, headers=headers)
41
37
 
42
- except (ConnectError, TimeoutException):
43
- return 2
44
- except Exception:
45
- return 2
46
38
 
47
39
  if __name__ == "__main__":
48
- user = input ("Username?: ").strip()
49
- result = validate_youtube(user)
50
-
51
- if result == 1:
52
- print("Available!")
53
- elif result == 0:
54
- print("Unavailable!")
55
- else:
56
- print("Error occured!")
40
+ user = input("Username?: ").strip()
41
+ result = validate_youtube(user)
42
+
43
+ if result == 1:
44
+ print("Available!")
45
+ elif result == 0:
46
+ print("Unavailable!")
47
+ else:
48
+ reason = result.get_reason()
49
+ print(f"Error occurred! Reason: {reason}")
50
+
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
  _SCRIPT_DIR = Path(__file__).resolve().parent
5
5
  VERSION_FILE = _SCRIPT_DIR.parent / "version.json"
6
6
 
7
+
7
8
  def load_local_version():
8
9
  try:
9
10
  data = json.loads(VERSION_FILE.read_text())
@@ -15,6 +16,7 @@ def load_local_version():
15
16
  except Exception:
16
17
  return "N/A", "error"
17
18
 
19
+
18
20
  if __name__ == "__main__":
19
21
  version, version_type = load_local_version()
20
22
  print(f"Version: {version}, Type: {version_type}")
user_scanner/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.0.2.0",
2
+ "version": "1.0.9.0",
3
3
  "version_type": "pypi"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: user-scanner
3
- Version: 1.0.2.1
3
+ Version: 1.0.9.0
4
4
  Summary: Check username availability across multiple popular platforms
5
5
  Keywords: username,checker,availability,social,tech,python,user-scanner
6
6
  Author-email: Kaif <kafcodec@gmail.com>
@@ -15,7 +15,7 @@ Project-URL: Homepage, https://github.com/kaifcodec/user-scanner
15
15
 
16
16
  ![1000136215](https://github.com/user-attachments/assets/49ec8d24-665b-4115-8525-01a8d0ca2ef4)
17
17
  <p align="center">
18
- <img src="https://img.shields.io/badge/Version-1.0.2.0-blueviolet?style=for-the-badge&logo=github" />
18
+ <img src="https://img.shields.io/badge/Version-1.0.9.0-blueviolet?style=for-the-badge&logo=github" />
19
19
  <img src="https://img.shields.io/github/issues/kaifcodec/user-scanner?style=for-the-badge&logo=github" />
20
20
  <img src="https://img.shields.io/badge/Tested%20on-Termux-black?style=for-the-badge&logo=termux" />
21
21
  <img src="https://img.shields.io/badge/Tested%20on-Windows-cyan?style=for-the-badge&logo=Windows" />
@@ -31,12 +31,16 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
31
31
 
32
32
  ### Features
33
33
 
34
- - ✅ Check usernames across **social networks**, **developer platforms**, and **creator communities**.
35
- - ✅ Clear **Available / Taken / Error** output for each platform.
36
- - ✅ Fully modular: add new platform modules easily.
37
- - ✅ Command-line interface ready: works directly after `pip install`.
38
- - ✅ Can be used as username OSINT tool.
39
- - ✅ Very low and lightweight dependencies, can be run on any machine.
34
+ - ✅ Check usernames across **social networks**, **developer platforms**, and **creator communities**
35
+ - ✅ Clear **Available / Taken / Error** output for each platform
36
+ - ✅ Robust error handling: It prints the exact reason (e.g. Cannot use underscores, hyphens at the start/end)
37
+ - ✅ Fully modular: add new platform modules easily
38
+ - ✅ Wildcard-based username permutations for automatic variation generation using provided suffix
39
+ - ✅ Selection of results format (e.g. json, csv, console (default))
40
+ - ✅ Get the scanning results in preferred format (json/csv) in specified output file (suitable for power users)
41
+ - ✅ Command-line interface ready: works directly after `pip install`
42
+ - ✅ Can be used as username OSINT tool
43
+ - ✅ Very low and lightweight dependencies, can be run on any machine
40
44
  ---
41
45
 
42
46
  ### Installation
@@ -60,56 +64,49 @@ Optionally, scan a specific category or single module:
60
64
  user-scanner -u <username> -c dev
61
65
  user-scanner -l # Lists all available modules
62
66
  user-scanner -u <username> -m github
67
+ ```
63
68
 
69
+ Also, the output file and format can be specified: <br>
70
+ \* Errors and warnings will only appear when the format is set to "console"
71
+ ```bash
72
+ user-scanner -u <username> -f console #Default format
73
+ user-scanner -u <username> -f csv
74
+ user-scanner -u <username> -f json
75
+ user-scanner -u <username> -f <format> -o <output-file>
64
76
  ```
65
- ---
66
- ### Example Output:
67
77
 
68
- - Note*: New modules are constantly getting added so this might have only limited, outdated output:
78
+ Generate multiple username variations by appending a suffix:
79
+
80
+ ```bash
81
+ user-scanner -u <username> -p <suffix>
82
+ ```
83
+ Optionally, scan a specific category or single module with limit:
84
+
69
85
  ```bash
70
- Checking username: johndoe078
71
-
72
- == DEV SITES ==
73
- [✔] Codeberg: Available
74
- [✔] Cratesio: Available
75
- [✔] Dockerhub: Available
76
- [✘] Github: Taken
77
- [✔] Gitlab: Available
78
- [✔] Launchpad: Available
79
- [✔] Npmjs: Available
80
- [✔] Replit: Available
81
-
82
- == SOCIAL SITES ==
83
- [✔] Bluesky: Available
84
- [✔] Discord: Available
85
- [✘] Instagram: Taken
86
- [✔] Mastodon: Available
87
- [✔] Pinterest: Available
88
- [✘] Reddit: Taken
89
- [✔] Snapchat: Available
90
- [✔] Telegram: Available
91
- [✘] Threads: Taken
92
- [✔] X (Twitter): Available
93
- [✔] Youtube: Available
94
-
95
- == CREATOR SITES ==
96
- [✔] Devto: Available
97
- [✔] Hashnode: Available
98
- [✔] Kaggle: Available
99
- [✔] Medium: Available
100
- [✔] Patreon: Available
101
-
102
- == COMMUNITY SITES ==
103
- [✔] Coderlegion: Available
104
-
105
- == GAMING SITES ==
106
- [✔] Chess_com: Available
107
- [✔] Osu: Available
108
- [✔] Roblox: Available
109
- ...
110
- ...
111
- ...
86
+ user-scanner -u <username> -p <suffix> -c dev
87
+ user-scanner -u <username> -p <suffix> -m github
88
+ user-scanner -u <username> -p <suffix> -s <number> # limit generation of usernames
89
+ user-scanner -u <username> -p <suffix> -d <seconds> # delay to avoid rate-limits (can be 0s-1s)
112
90
  ```
91
+
92
+ ---
93
+ ### Screenshot:
94
+
95
+ - Note*: New modules are constantly getting added so this might have only limited, outdated output:
96
+
97
+
98
+ <img width="1080" height="770" alt="1000140392" src="https://github.com/user-attachments/assets/4638c8f6-40c6-46f8-ae17-ac65cd199d81" />
99
+
100
+
101
+ ---
102
+
103
+ <img width="1080" height="352" alt="1000140393" src="https://github.com/user-attachments/assets/578b248c-2a05-4917-aab3-6372a7c28045" />
104
+
105
+ ---
106
+
107
+ <img width="992" height="556" alt="1000141265" src="https://github.com/user-attachments/assets/9babb19f-bc87-4e7b-abe5-c52b8b1b672c" />
108
+
109
+
113
110
  ### Contributing:
114
111
 
115
112
  Modules are organized by category:
@@ -121,21 +118,21 @@ user_scanner/
121
118
  ├── creator/ # Creator platforms (Hashnode, Dev.to, Medium, etc.)
122
119
  ├── community/ # Community platforms (forums, niche sites)
123
120
  ├── gaming/ # Gaming sites (chess.com, roblox, monkeytype etc.)
121
+ ├── donation/ # Donation taking sites (buymeacoffe.com, similar...)
124
122
  ```
125
123
 
126
124
  **Module guidelines:**
127
- - Each module must define a `validate_<site>()` function that takes a `username` and returns:
128
- - `1` → Available
129
- - `0` → Taken
130
- - `2`Error / Could not check
131
- - Use `httpx` for requests, `colorama` for colored output.
132
- - Optional: modules can define a CLI parser if they support custom arguments.
125
+ This project contains small "validator" modules that check whether a username exists on a given platform. Each validator is a single function that returns a Result object (see `core/orchestrator.py`).
126
+
127
+ Result semantics:
128
+ - Result.available()`available`
129
+ - Result.taken() `taken`
130
+ - Result.error(message: Optional[str]) `error`, blocked, unknown, or request failure (include short diagnostic message when helpful)
131
+
132
+ Follow this document when adding or updating validators.
133
133
 
134
134
  See [CONTRIBUTING.md](CONTRIBUTING.md) for examples.
135
135
 
136
- ### 📧 Contact:
137
- - [Email](kaifcodec@gmail.com)
138
-
139
136
  ---
140
137
 
141
138
  ### Dependencies:
@@ -149,8 +146,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for examples.
149
146
  This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for details.
150
147
 
151
148
 
152
- <!---
153
- ## 🌟 Stars:
149
+ ---
150
+
151
+ ### Star History
154
152
 
155
153
  <a href="https://www.star-history.com/#kaifcodec/user-scanner&type=date&legend=top-left">
156
154
  <picture>
@@ -159,7 +157,4 @@ This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for d
159
157
  <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=kaifcodec/user-scanner&type=date&legend=top-left" />
160
158
  </picture>
161
159
  </a>
162
- --->
163
- ---
164
- ## ⚠️ `community/` and `gaming/` are small, looking for contributions
165
160