user-scanner 1.0.9.0__tar.gz → 1.0.9.1__tar.gz

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 (65) hide show
  1. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/PKG-INFO +3 -3
  2. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/README.md +2 -2
  3. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/pyproject.toml +1 -1
  4. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/core/orchestrator.py +5 -3
  5. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/hashnode.py +3 -6
  6. user_scanner-1.0.9.1/user_scanner/creator/itch_io.py +30 -0
  7. user_scanner-1.0.9.1/user_scanner/dev/bitbucket.py +34 -0
  8. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/github.py +1 -1
  9. user_scanner-1.0.9.1/user_scanner/dev/leetcode.py +35 -0
  10. user_scanner-1.0.9.1/user_scanner/dev/sourceforge.py +30 -0
  11. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/discord.py +4 -4
  12. user_scanner-1.0.9.1/user_scanner/social/twitch.py +83 -0
  13. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/version.json +1 -1
  14. user_scanner-1.0.9.0/user_scanner/creator/itch_io.py +0 -19
  15. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/LICENSE +0 -0
  16. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/__init__.py +0 -0
  17. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/__main__.py +0 -0
  18. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/cli/__init__.py +0 -0
  19. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/cli/banner.py +0 -0
  20. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/cli/printer.py +0 -0
  21. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/community/__init__.py +0 -0
  22. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/community/coderlegion.py +0 -0
  23. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/community/stackoverflow.py +0 -0
  24. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/core/__init__.py +0 -0
  25. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/core/result.py +0 -0
  26. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/core/utils.py +0 -0
  27. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/__init__.py +0 -0
  28. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/devto.py +0 -0
  29. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/kaggle.py +0 -0
  30. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/medium.py +0 -0
  31. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/patreon.py +0 -0
  32. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/creator/producthunt.py +0 -0
  33. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/__init__.py +0 -0
  34. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/codeberg.py +0 -0
  35. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/cratesio.py +0 -0
  36. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/dockerhub.py +0 -0
  37. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/gitlab.py +0 -0
  38. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/huggingface.py +0 -0
  39. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/launchpad.py +0 -0
  40. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/npmjs.py +0 -0
  41. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/dev/replit.py +0 -0
  42. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/donation/__init__.py +0 -0
  43. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/donation/buymeacoffee.py +0 -0
  44. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/donation/liberapay.py +0 -0
  45. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/__init__.py +0 -0
  46. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/chess_com.py +0 -0
  47. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/minecraft.py +0 -0
  48. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/monkeytype.py +0 -0
  49. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/osu.py +0 -0
  50. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/roblox.py +0 -0
  51. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/gaming/steam.py +0 -0
  52. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/__init__.py +0 -0
  53. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/bluesky.py +0 -0
  54. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/instagram.py +0 -0
  55. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/mastodon.py +0 -0
  56. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/pinterest.py +0 -0
  57. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/reddit.py +0 -0
  58. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/snapchat.py +0 -0
  59. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/soundcloud.py +0 -0
  60. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/telegram.py +0 -0
  61. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/threads.py +0 -0
  62. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/x.py +0 -0
  63. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/social/youtube.py +0 -0
  64. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/utils/update.py +0 -0
  65. {user_scanner-1.0.9.0 → user_scanner-1.0.9.1}/user_scanner/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: user-scanner
3
- Version: 1.0.9.0
3
+ Version: 1.0.9.1
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.9.0-blueviolet?style=for-the-badge&logo=github" />
18
+ <img src="https://img.shields.io/badge/Version-1.0.9.1-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" />
@@ -67,7 +67,7 @@ user-scanner -u <username> -m github
67
67
  ```
68
68
 
69
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"
70
+
71
71
  ```bash
72
72
  user-scanner -u <username> -f console #Default format
73
73
  user-scanner -u <username> -f csv
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![1000136215](https://github.com/user-attachments/assets/49ec8d24-665b-4115-8525-01a8d0ca2ef4)
4
4
  <p align="center">
5
- <img src="https://img.shields.io/badge/Version-1.0.9.0-blueviolet?style=for-the-badge&logo=github" />
5
+ <img src="https://img.shields.io/badge/Version-1.0.9.1-blueviolet?style=for-the-badge&logo=github" />
6
6
  <img src="https://img.shields.io/github/issues/kaifcodec/user-scanner?style=for-the-badge&logo=github" />
7
7
  <img src="https://img.shields.io/badge/Tested%20on-Termux-black?style=for-the-badge&logo=termux" />
8
8
  <img src="https://img.shields.io/badge/Tested%20on-Windows-cyan?style=for-the-badge&logo=Windows" />
@@ -54,7 +54,7 @@ user-scanner -u <username> -m github
54
54
  ```
55
55
 
56
56
  Also, the output file and format can be specified: <br>
57
- \* Errors and warnings will only appear when the format is set to "console"
57
+
58
58
  ```bash
59
59
  user-scanner -u <username> -f console #Default format
60
60
  user-scanner -u <username> -f csv
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
4
4
 
5
5
  [project]
6
6
  name = "user-scanner"
7
- version = "1.0.9.0"
7
+ version = "1.0.9.1"
8
8
  description = "Check username availability across multiple popular platforms"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -138,7 +138,7 @@ def run_checks(username: str, printer: Printer, last: bool = True) -> List[Resul
138
138
  return results
139
139
 
140
140
 
141
- def make_get_request(url: str, **kwargs) -> httpx.Response:
141
+ def make_request(url: str, **kwargs) -> httpx.Response:
142
142
  """Simple wrapper to **httpx.get** that predefines headers and timeout"""
143
143
  if not "headers" in kwargs:
144
144
  kwargs["headers"] = {
@@ -152,7 +152,9 @@ def make_get_request(url: str, **kwargs) -> httpx.Response:
152
152
  if not "timeout" in kwargs:
153
153
  kwargs["timeout"] = 5.0
154
154
 
155
- return httpx.get(url, **kwargs)
155
+ method = kwargs.pop("method", "GET")
156
+
157
+ return httpx.request(method.upper(), url, **kwargs)
156
158
 
157
159
 
158
160
  def generic_validate(url: str, func: Callable[[httpx.Response], AnyResult], **kwargs) -> AnyResult:
@@ -160,7 +162,7 @@ def generic_validate(url: str, func: Callable[[httpx.Response], AnyResult], **kw
160
162
  A generic validate function that makes a request and executes the provided function on the response.
161
163
  """
162
164
  try:
163
- response = make_get_request(url, **kwargs)
165
+ response = make_request(url, **kwargs)
164
166
  result = func(response)
165
167
  result.url = url
166
168
  return result
@@ -1,5 +1,6 @@
1
1
  import httpx
2
2
  from user_scanner.core.result import Result
3
+ from user_scanner.core.orchestrator import generic_validate
3
4
 
4
5
 
5
6
  def validate_hashnode(user):
@@ -18,9 +19,7 @@ def validate_hashnode(user):
18
19
  'Referer': "https://hashnode.com/signup",
19
20
  }
20
21
 
21
- try:
22
- response = httpx.post(url, json=payload, headers=headers, timeout=3.0)
23
-
22
+ def process(response):
24
23
  if response.status_code == 200:
25
24
  data = response.json()
26
25
 
@@ -35,9 +34,7 @@ def validate_hashnode(user):
35
34
  else:
36
35
  return Result.error("Invalid status code")
37
36
 
38
- except Exception as e:
39
- return Result.error(e)
40
-
37
+ return generic_validate(url, process, method="POST", json=payload, headers=headers, timeout=3.0)
41
38
 
42
39
  if __name__ == "__main__":
43
40
  user = input("Username?: ").strip()
@@ -0,0 +1,30 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
3
+
4
+
5
+ def validate_itch_io(user: str) -> Result:
6
+ if not (2 <= len(user) <= 25):
7
+ return Result.error("Length must be 2-25 characters.")
8
+
9
+ if not re.match(r'^[a-z0-9_-]+$', user):
10
+
11
+ if re.search(r'[A-Z]', user):
12
+ return Result.error("Use lowercase letters only.")
13
+
14
+ return Result.error("Only use lowercase letters, numbers, underscores, and hyphens.")
15
+
16
+ url = f"https://itch.io/profile/{user}"
17
+
18
+ return status_validate(url, 404, 200, follow_redirects=True)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ user = input("Username?: ").strip()
23
+ result = validate_itch_io(user)
24
+
25
+ if result == 1:
26
+ print("Available!")
27
+ elif result == 0:
28
+ print("Unavailable!")
29
+ else:
30
+ print(f"Error occurred! Reason: {result.get_reason()}")
@@ -0,0 +1,34 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
3
+
4
+
5
+ def validate_bitbucket(user: str) -> Result:
6
+ if not (1 <= len(user) <= 30):
7
+ return Result.error("Length must be 1-30 characters.")
8
+
9
+ if not re.match(r'^[a-z0-9][a-z0-9_-]*$', user):
10
+
11
+ if re.search(r'[A-Z]', user):
12
+ return Result.error("Use lowercase letters only.")
13
+
14
+ return Result.error("Only use lowercase letters, numbers, hyphens, and underscores.")
15
+
16
+ url = f"https://bitbucket.org/{user}/"
17
+
18
+ return status_validate(url, 404, [200, 302], follow_redirects=True)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ user = input("Username?: ").strip()
23
+ result = validate_bitbucket(user)
24
+
25
+ if result == 1:
26
+ print("Available!")
27
+ elif result == 0:
28
+ print("Unavailable!")
29
+ else:
30
+ print(f"Error occurred! Reason: {result.get_reason()}")
31
+
32
+
33
+
34
+
@@ -29,7 +29,7 @@ def validate_github(user):
29
29
 
30
30
  if response.status_code == 422:
31
31
  if GITHUB_INVALID_MSG in response.text:
32
- return Result.error("Cannot start/end with hyphen or use double hyphens")
32
+ return Result.error("Cannot start/end with hyphen or use double hyphens, underscores")
33
33
 
34
34
  return Result.taken()
35
35
 
@@ -0,0 +1,35 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
3
+
4
+
5
+ def validate_leetcode(user: str) -> Result:
6
+ if not (3 <= len(user) <= 30):
7
+ return Result.error("Length must be between 3 and 30 characters")
8
+
9
+ if not re.match(r'^[a-zA-Z0-9._-]+$', user):
10
+ return Result.error("Can only use letters, numbers, underscores, periods, or hyphens")
11
+
12
+ url = f"https://leetcode.com/u/{user}/"
13
+
14
+ headers = {
15
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
16
+ '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",
17
+ 'Accept-Encoding': "identity",
18
+ 'upgrade-insecure-requests': "1",
19
+ 'accept-language': "en-US,en;q=0.9",
20
+ 'priority': "u=0, i"
21
+ }
22
+
23
+ return status_validate(url, 404, 200, headers=headers, follow_redirects=True)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ user = input("Username?: ").strip()
28
+ result = validate_leetcode(user)
29
+
30
+ if result == 1:
31
+ print("Available!")
32
+ elif result == 0:
33
+ print("Unavailable!")
34
+ else:
35
+ print(f"Error occurred! Reason: {result.get_reason()}")
@@ -0,0 +1,30 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
3
+
4
+
5
+ def validate_sourceforge(user: str) -> Result:
6
+ if not (3 <= len(user) <= 30):
7
+ return Result.error("Length must be 3-30 characters.")
8
+
9
+ if not re.match(r'^[a-z0-9-]+$', user):
10
+
11
+ if re.search(r'[A-Z]', user):
12
+ return Result.error("Use lowercase letters only.")
13
+
14
+ return Result.error("Only use lowercase letters, numbers, and dashes.")
15
+
16
+ url = f"https://sourceforge.net/u/{user}/"
17
+
18
+ return status_validate(url, 404, 200, follow_redirects=True)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ user = input("Username?: ").strip()
23
+ result = validate_sourceforge(user)
24
+
25
+ if result == 1:
26
+ print("Available!")
27
+ elif result == 0:
28
+ print("Unavailable!")
29
+ else:
30
+ print(f"Error occurred! Reason: {result.get_reason()}")
@@ -1,5 +1,6 @@
1
1
  import httpx
2
2
  from user_scanner.core.result import Result
3
+ from user_scanner.core.orchestrator import generic_validate
3
4
 
4
5
  def validate_discord(user):
5
6
  url = "https://discord.com/api/v9/unique-username/username-attempt-unauthed"
@@ -15,8 +16,7 @@ def validate_discord(user):
15
16
 
16
17
  data = {"username": user}
17
18
 
18
- try:
19
- response = httpx.post(url, headers=headers, json=data, timeout=3.0)
19
+ def process(response):
20
20
  if response.status_code == 200:
21
21
  status = response.json().get("taken")
22
22
  if status is True:
@@ -24,8 +24,8 @@ def validate_discord(user):
24
24
  elif status is False:
25
25
  return Result.available()
26
26
  return Result.error("Invalid status code")
27
- except Exception as e:
28
- return Result.error(e)
27
+
28
+ return generic_validate(url, process, method="POST", json=data, headers=headers, timeout=3.0)
29
29
 
30
30
 
31
31
  if __name__ == "__main__":
@@ -0,0 +1,83 @@
1
+ import json
2
+ import re
3
+ import httpx
4
+ from user_scanner.core.orchestrator import generic_validate, Result
5
+
6
+
7
+ def validate_twitch(user: str) -> Result:
8
+ if not (4 <= len(user) <= 25):
9
+ return Result.error("Username must be between 4 and 25 characters long")
10
+
11
+ if not re.match(r"^[a-zA-Z0-9]+$", user):
12
+ return Result.error("Username can only contain alphanumeric characters (a-z, 0-9)")
13
+
14
+ url = "https://gql.twitch.tv/gql"
15
+
16
+ payload = [
17
+ {
18
+ "operationName": "ChannelLayout",
19
+ "variables": {
20
+ "channelLogin": user,
21
+ "includeIsDJ": True
22
+ },
23
+ "extensions": {
24
+ "persistedQuery": {
25
+ "version": 1,
26
+ "sha256Hash": "4c361fa1874dc8f6a49e62b56aa1032eccb31311bdb653918a924f96a8b2d1a6"
27
+ }
28
+ }
29
+ }
30
+ ]
31
+
32
+ headers = {
33
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
34
+ 'Accept-Encoding': "identity",
35
+ 'Content-Type': "application/json",
36
+ 'sec-ch-ua-platform': "\"Android\"",
37
+ 'accept-language': "en-US",
38
+ 'client-id': "kimne78kx3ncx6brgo4mv6wki5h1ko",
39
+ 'client-version': "7bb0442d-1175-4ab5-9d32-b1f370536cbf",
40
+ 'origin': "https://m.twitch.tv",
41
+ 'referer': "https://m.twitch.tv/",
42
+ }
43
+
44
+ def process(response: httpx.Response) -> Result:
45
+ if response.status_code != 200:
46
+ return Result.error(f"Unexpected status code: {response.status_code}")
47
+
48
+ try:
49
+ data = response.json()
50
+ except json.JSONDecodeError as e:
51
+ return Result.error(f"Failed to decode JSON response: {e}")
52
+
53
+ user_data = data[0].get('data', {}).get('user', {})
54
+ typename = user_data.get('__typename')
55
+
56
+ if typename == "User":
57
+ return Result.taken()
58
+ elif typename == "UserDoesNotExist":
59
+ return Result.available()
60
+ else:
61
+ return Result.error("Unexpected GraphQL response structure or type.")
62
+
63
+ return generic_validate(
64
+ url,
65
+ process,
66
+ headers=headers,
67
+ method='POST',
68
+ content=json.dumps(payload),
69
+ follow_redirects=False
70
+ )
71
+
72
+
73
+ if __name__ == "__main__":
74
+ user = input("Twitch Username?: ").strip()
75
+ result = validate_twitch(user)
76
+
77
+ if result == 1:
78
+ print("Available!")
79
+ elif result == 0:
80
+ print("Unavailable!")
81
+ else:
82
+ reason = result.get_reason()
83
+ print(f"Error occurred! Reason: {reason}")
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.0.9.0",
2
+ "version": "1.0.9.1",
3
3
  "version_type": "pypi"
4
4
  }
@@ -1,19 +0,0 @@
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!")
File without changes