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/social/reddit.py
CHANGED
|
@@ -1,42 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
from
|
|
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
|
-
|
|
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
|
|
22
|
-
return
|
|
10
|
+
if "Sorry, nobody on Reddit goes by that name." in response.text:
|
|
11
|
+
return Result.available()
|
|
23
12
|
else:
|
|
24
|
-
return
|
|
13
|
+
return Result.taken()
|
|
25
14
|
else:
|
|
26
|
-
|
|
15
|
+
return Result.error()
|
|
27
16
|
|
|
28
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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!")
|
user_scanner/social/snapchat.py
CHANGED
|
@@ -1,48 +1,35 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
27
|
+
user = input("Username?: ").strip()
|
|
28
|
+
result = validate_snapchat(user)
|
|
42
29
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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!")
|
user_scanner/social/telegram.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
27
|
-
|
|
21
|
+
user = input("Username?: ").strip()
|
|
22
|
+
result = validate_telegram(user)
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
if result == 1:
|
|
25
|
+
print("Available!")
|
|
26
|
+
elif result == 0:
|
|
27
|
+
print("Unavailable!")
|
|
28
|
+
else:
|
|
29
|
+
print("Error occured!")
|
user_scanner/social/threads.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
21
|
+
user = input("Username?: ").strip()
|
|
22
|
+
result = validate_instagram(user)
|
|
36
23
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
2
|
-
import
|
|
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
|
-
|
|
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
|
|
27
|
+
return Result.available()
|
|
32
28
|
elif data.get('reason') == 'taken':
|
|
33
|
-
return
|
|
29
|
+
return Result.taken()
|
|
34
30
|
elif (data.get('reason') == "improper_format" or data.get('reason') == "invalid_username"):
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return 2
|
|
31
|
+
return Result.error(f"X says: {data.get('desc')}")
|
|
32
|
+
|
|
33
|
+
return Result.error()
|
|
39
34
|
|
|
40
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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!")
|
user_scanner/social/youtube.py
CHANGED
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
import
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
|
user_scanner/utils/version.py
CHANGED
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: user-scanner
|
|
3
|
-
Version: 1.0.
|
|
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
|

|
|
17
17
|
<p align="center">
|
|
18
|
-
<img src="https://img.shields.io/badge/Version-1.0.
|
|
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
|
-
- ✅
|
|
37
|
-
- ✅
|
|
38
|
-
- ✅
|
|
39
|
-
- ✅
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
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
|
-
|
|
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
|
|