user-scanner 1.0.9.1__tar.gz → 1.0.10.0__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.
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/PKG-INFO +17 -5
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/README.md +16 -4
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/pyproject.toml +1 -1
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/__main__.py +28 -5
- user_scanner-1.0.10.0/user_scanner/cli/banner.py +25 -0
- user_scanner-1.0.10.0/user_scanner/community/hackernews.py +33 -0
- user_scanner-1.0.10.0/user_scanner/config.json +1 -0
- {user_scanner-1.0.9.1/user_scanner/utils → user_scanner-1.0.10.0/user_scanner/core}/version.py +12 -3
- user_scanner-1.0.10.0/user_scanner/creator/substack.py +36 -0
- user_scanner-1.0.10.0/user_scanner/gaming/lichess.py +40 -0
- user_scanner-1.0.10.0/user_scanner/utils/update.py +34 -0
- user_scanner-1.0.10.0/user_scanner/utils/updater_logic.py +62 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/version.json +1 -1
- user_scanner-1.0.9.1/user_scanner/cli/banner.py +0 -34
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/LICENSE +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/cli/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/cli/printer.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/community/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/community/coderlegion.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/community/stackoverflow.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/core/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/core/orchestrator.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/core/result.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/core/utils.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/devto.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/hashnode.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/itch_io.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/kaggle.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/medium.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/patreon.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/creator/producthunt.py +0 -0
- {user_scanner-1.0.9.1/user_scanner/social → user_scanner-1.0.10.0/user_scanner/creator}/twitch.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/bitbucket.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/codeberg.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/cratesio.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/dockerhub.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/github.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/gitlab.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/huggingface.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/launchpad.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/leetcode.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/npmjs.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/replit.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/dev/sourceforge.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/donation/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/donation/buymeacoffee.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/donation/liberapay.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/chess_com.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/minecraft.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/monkeytype.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/osu.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/roblox.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/gaming/steam.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/__init__.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/bluesky.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/discord.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/instagram.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/mastodon.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/pinterest.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/reddit.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/snapchat.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/soundcloud.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/telegram.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/threads.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/x.py +0 -0
- {user_scanner-1.0.9.1 → user_scanner-1.0.10.0}/user_scanner/social/youtube.py +0 -0
- /user_scanner-1.0.9.1/user_scanner/utils/update.py → /user_scanner-1.0.10.0/user_scanner/utils/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: user-scanner
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.10.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>
|
|
@@ -13,9 +13,9 @@ Project-URL: Homepage, https://github.com/kaifcodec/user-scanner
|
|
|
13
13
|
|
|
14
14
|
# User Scanner
|
|
15
15
|
|
|
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.10.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" />
|
|
@@ -32,6 +32,8 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
|
|
|
32
32
|
### Features
|
|
33
33
|
|
|
34
34
|
- ✅ Check usernames across **social networks**, **developer platforms**, and **creator communities**
|
|
35
|
+
- ✅ Can be used as a username OSINT tool
|
|
36
|
+
- ✅ Smart auto-update system, Detects new releases on PyPI and interactively prompts the user to upgrade.
|
|
35
37
|
- ✅ Clear **Available / Taken / Error** output for each platform
|
|
36
38
|
- ✅ Robust error handling: It prints the exact reason (e.g. Cannot use underscores, hyphens at the start/end)
|
|
37
39
|
- ✅ Fully modular: add new platform modules easily
|
|
@@ -39,7 +41,6 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
|
|
|
39
41
|
- ✅ Selection of results format (e.g. json, csv, console (default))
|
|
40
42
|
- ✅ Get the scanning results in preferred format (json/csv) in specified output file (suitable for power users)
|
|
41
43
|
- ✅ Command-line interface ready: works directly after `pip install`
|
|
42
|
-
- ✅ Can be used as username OSINT tool
|
|
43
44
|
- ✅ Very low and lightweight dependencies, can be run on any machine
|
|
44
45
|
---
|
|
45
46
|
|
|
@@ -78,7 +79,7 @@ user-scanner -u <username> -f <format> -o <output-file>
|
|
|
78
79
|
Generate multiple username variations by appending a suffix:
|
|
79
80
|
|
|
80
81
|
```bash
|
|
81
|
-
user-scanner -u <username> -p <suffix>
|
|
82
|
+
user-scanner -u <username> -p <suffix>
|
|
82
83
|
```
|
|
83
84
|
Optionally, scan a specific category or single module with limit:
|
|
84
85
|
|
|
@@ -87,9 +88,20 @@ user-scanner -u <username> -p <suffix> -c dev
|
|
|
87
88
|
user-scanner -u <username> -p <suffix> -m github
|
|
88
89
|
user-scanner -u <username> -p <suffix> -s <number> # limit generation of usernames
|
|
89
90
|
user-scanner -u <username> -p <suffix> -d <seconds> # delay to avoid rate-limits (can be 0s-1s)
|
|
91
|
+
```
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Update
|
|
95
|
+
|
|
96
|
+
Update the tool to the latest PyPI version:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
user-scanner -U
|
|
100
|
+
|
|
90
101
|
```
|
|
91
102
|
|
|
92
103
|
---
|
|
104
|
+
|
|
93
105
|
### Screenshot:
|
|
94
106
|
|
|
95
107
|
- Note*: New modules are constantly getting added so this might have only limited, outdated output:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# User Scanner
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
<p align="center">
|
|
5
|
-
<img src="https://img.shields.io/badge/Version-1.0.
|
|
5
|
+
<img src="https://img.shields.io/badge/Version-1.0.10.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" />
|
|
@@ -19,6 +19,8 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
|
|
|
19
19
|
### Features
|
|
20
20
|
|
|
21
21
|
- ✅ Check usernames across **social networks**, **developer platforms**, and **creator communities**
|
|
22
|
+
- ✅ Can be used as a username OSINT tool
|
|
23
|
+
- ✅ Smart auto-update system, Detects new releases on PyPI and interactively prompts the user to upgrade.
|
|
22
24
|
- ✅ Clear **Available / Taken / Error** output for each platform
|
|
23
25
|
- ✅ Robust error handling: It prints the exact reason (e.g. Cannot use underscores, hyphens at the start/end)
|
|
24
26
|
- ✅ Fully modular: add new platform modules easily
|
|
@@ -26,7 +28,6 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
|
|
|
26
28
|
- ✅ Selection of results format (e.g. json, csv, console (default))
|
|
27
29
|
- ✅ Get the scanning results in preferred format (json/csv) in specified output file (suitable for power users)
|
|
28
30
|
- ✅ Command-line interface ready: works directly after `pip install`
|
|
29
|
-
- ✅ Can be used as username OSINT tool
|
|
30
31
|
- ✅ Very low and lightweight dependencies, can be run on any machine
|
|
31
32
|
---
|
|
32
33
|
|
|
@@ -65,7 +66,7 @@ user-scanner -u <username> -f <format> -o <output-file>
|
|
|
65
66
|
Generate multiple username variations by appending a suffix:
|
|
66
67
|
|
|
67
68
|
```bash
|
|
68
|
-
user-scanner -u <username> -p <suffix>
|
|
69
|
+
user-scanner -u <username> -p <suffix>
|
|
69
70
|
```
|
|
70
71
|
Optionally, scan a specific category or single module with limit:
|
|
71
72
|
|
|
@@ -74,9 +75,20 @@ user-scanner -u <username> -p <suffix> -c dev
|
|
|
74
75
|
user-scanner -u <username> -p <suffix> -m github
|
|
75
76
|
user-scanner -u <username> -p <suffix> -s <number> # limit generation of usernames
|
|
76
77
|
user-scanner -u <username> -p <suffix> -d <seconds> # delay to avoid rate-limits (can be 0s-1s)
|
|
78
|
+
```
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### Update
|
|
82
|
+
|
|
83
|
+
Update the tool to the latest PyPI version:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
user-scanner -U
|
|
87
|
+
|
|
77
88
|
```
|
|
78
89
|
|
|
79
90
|
---
|
|
91
|
+
|
|
80
92
|
### Screenshot:
|
|
81
93
|
|
|
82
94
|
- Note*: New modules are constantly getting added so this might have only limited, outdated output:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import time
|
|
3
3
|
import re
|
|
4
|
+
import sys
|
|
4
5
|
from user_scanner.cli import printer
|
|
5
6
|
from user_scanner.core.orchestrator import generate_permutations, load_categories
|
|
6
7
|
from colorama import Fore, Style
|
|
@@ -8,10 +9,22 @@ from user_scanner.cli.banner import print_banner
|
|
|
8
9
|
from typing import List
|
|
9
10
|
from user_scanner.core.result import Result
|
|
10
11
|
from user_scanner.core.utils import is_last_value
|
|
12
|
+
from user_scanner.utils.updater_logic import check_for_updates
|
|
13
|
+
from user_scanner.utils.update import update_self
|
|
14
|
+
|
|
15
|
+
# Color configs
|
|
16
|
+
R = Fore.RED
|
|
17
|
+
G = Fore.GREEN
|
|
18
|
+
C = Fore.CYAN
|
|
19
|
+
Y = Fore.YELLOW
|
|
20
|
+
X = Fore.RESET
|
|
21
|
+
|
|
11
22
|
|
|
12
23
|
MAX_PERMUTATIONS_LIMIT = 100 # To prevent excessive generation
|
|
13
24
|
|
|
25
|
+
|
|
14
26
|
def main():
|
|
27
|
+
|
|
15
28
|
parser = argparse.ArgumentParser(
|
|
16
29
|
prog="user-scanner",
|
|
17
30
|
description="Scan usernames across multiple platforms."
|
|
@@ -51,15 +64,25 @@ def main():
|
|
|
51
64
|
parser.add_argument(
|
|
52
65
|
"-o", "--output", type=str, help="Specify the output file"
|
|
53
66
|
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"-U", "--update", action="store_true", help="Update user-scanner to latest version"
|
|
69
|
+
)
|
|
54
70
|
|
|
55
71
|
args = parser.parse_args()
|
|
56
72
|
|
|
57
73
|
Printer = printer.Printer(args.format)
|
|
58
74
|
|
|
75
|
+
if args.update is True:
|
|
76
|
+
update_self()
|
|
77
|
+
print(f"[{G}+{X}] {G}Update successful. Please restart the tool.{X}")
|
|
78
|
+
sys.exit(0)
|
|
79
|
+
|
|
59
80
|
if args.list:
|
|
60
81
|
Printer.print_modules(args.category)
|
|
61
82
|
return
|
|
62
83
|
|
|
84
|
+
check_for_updates()
|
|
85
|
+
|
|
63
86
|
if not args.username:
|
|
64
87
|
parser.print_help()
|
|
65
88
|
return
|
|
@@ -70,19 +93,19 @@ def main():
|
|
|
70
93
|
|
|
71
94
|
if args.permute and args.delay == 0 and Printer.is_console:
|
|
72
95
|
print(
|
|
73
|
-
|
|
96
|
+
Y
|
|
74
97
|
+ "[!] Warning: You're generating multiple usernames with NO delay between requests. "
|
|
75
98
|
"This may trigger rate limits or IP bans. Use --delay 1 or higher. (Use only if the sites throw errors otherwise ignore)\n"
|
|
76
99
|
+ Style.RESET_ALL)
|
|
77
100
|
|
|
78
101
|
usernames = [args.username] # Default single username list
|
|
79
102
|
|
|
80
|
-
#Added permutation support , generate all possible permutation of given sequence.
|
|
103
|
+
# Added permutation support , generate all possible permutation of given sequence.
|
|
81
104
|
if args.permute:
|
|
82
105
|
usernames = generate_permutations(args.username, args.permute , args.stop)
|
|
83
106
|
if Printer.is_console:
|
|
84
107
|
print(
|
|
85
|
-
|
|
108
|
+
C + f"[+] Generated {len(usernames)} username permutations" + Style.RESET_ALL)
|
|
86
109
|
|
|
87
110
|
if args.module and "." in args.module:
|
|
88
111
|
args.module = args.module.replace(".", "_")
|
|
@@ -118,7 +141,7 @@ def main():
|
|
|
118
141
|
results.extend(run_all_usernames(run_module_single, module))
|
|
119
142
|
else:
|
|
120
143
|
print(
|
|
121
|
-
|
|
144
|
+
R + f"[!] Module '{args.module}' not found in any category." + Style.RESET_ALL)
|
|
122
145
|
|
|
123
146
|
elif args.category:
|
|
124
147
|
# Category-wise scan
|
|
@@ -139,7 +162,7 @@ def main():
|
|
|
139
162
|
"\n[!] The console format cannot be "
|
|
140
163
|
f"written to file: '{args.output}'."
|
|
141
164
|
)
|
|
142
|
-
print(
|
|
165
|
+
print(R + msg + Style.RESET_ALL)
|
|
143
166
|
return
|
|
144
167
|
|
|
145
168
|
content = Printer.get_start()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from colorama import Fore, Style, init
|
|
3
|
+
from ..core.version import load_local_version
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
version, version_type = load_local_version()
|
|
7
|
+
init(autoreset=True)
|
|
8
|
+
C_RED = Fore.RED + Style.BRIGHT
|
|
9
|
+
C_CYAN = Fore.CYAN + Style.BRIGHT
|
|
10
|
+
C_GREEN = Fore.GREEN + Style.BRIGHT
|
|
11
|
+
C_WHITE = Fore.WHITE + Style.BRIGHT
|
|
12
|
+
C_MAGENTA = Fore.MAGENTA + Style.BRIGHT
|
|
13
|
+
BANNER_ASCII = fr"""{C_CYAN} _ _ ___ ___ _ __ ___ ___ __ _ _ __ _ __ ___ _ __
|
|
14
|
+
| | | / __|/ _ \ '__|____/ __|/ __/ _` | '_ \| '_ \ / _ \ '__|
|
|
15
|
+
| |_| \__ \ __/ | |_____\__ \ (_| (_| | | | | | | | __/ |
|
|
16
|
+
\__,_|___/\___|_| |___/\___\__,_|_| |_|_| |_|\___|_| Version: {version}
|
|
17
|
+
{Style.RESET_ALL}""".strip()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def print_banner():
|
|
21
|
+
print(BANNER_ASCII)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
print_banner()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from user_scanner.core.orchestrator import generic_validate, Result
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def validate_hackernews(user: str) -> Result:
|
|
6
|
+
if not (2 <= len(user) <= 15):
|
|
7
|
+
return Result.error("Length must be 2-15 characters")
|
|
8
|
+
|
|
9
|
+
if not re.match(r'^[a-zA-Z0-9_-]+$', user):
|
|
10
|
+
return Result.error("Only use letters, numbers, underscores, and hyphens")
|
|
11
|
+
|
|
12
|
+
url = f"https://news.ycombinator.com/user?id={user}"
|
|
13
|
+
|
|
14
|
+
def process(response):
|
|
15
|
+
if "No such user." in response.text:
|
|
16
|
+
return Result.available()
|
|
17
|
+
if f"profile: {user}" in response.text.lower() or "created:" in response.text:
|
|
18
|
+
return Result.taken()
|
|
19
|
+
return Result.error("Unexpected response structure")
|
|
20
|
+
|
|
21
|
+
return generic_validate(url, process, timeout=3.0, follow_redirects=True)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
user = input("Username?: ").strip()
|
|
26
|
+
result = validate_hackernews(user)
|
|
27
|
+
|
|
28
|
+
if result == 1:
|
|
29
|
+
print("Available!")
|
|
30
|
+
elif result == 0:
|
|
31
|
+
print("Unavailable!")
|
|
32
|
+
else:
|
|
33
|
+
print(f"Error occurred! Reason: {result.get_reason()}")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"auto_update_status": true}
|
{user_scanner-1.0.9.1/user_scanner/utils → user_scanner-1.0.10.0/user_scanner/core}/version.py
RENAMED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import httpx
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
VERSION_FILE =
|
|
5
|
+
SCRIPT_DIR = Path(__file__).parent
|
|
6
|
+
VERSION_FILE = SCRIPT_DIR.parent / "version.json"
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
def load_local_version():
|
|
9
10
|
try:
|
|
10
11
|
data = json.loads(VERSION_FILE.read_text())
|
|
11
|
-
return data.get("version", "
|
|
12
|
+
return data.get("version", "error_report_via_gh_issues"), data.get("version_type", "local")
|
|
12
13
|
except FileNotFoundError:
|
|
13
14
|
return "N/A", "file_missing"
|
|
14
15
|
except json.JSONDecodeError:
|
|
@@ -17,6 +18,14 @@ def load_local_version():
|
|
|
17
18
|
return "N/A", "error"
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
def get_pypi_version(pypi_url):
|
|
22
|
+
try:
|
|
23
|
+
pypi_version = httpx.get(pypi_url, timeout=7).json()["info"]["version"]
|
|
24
|
+
except Exception as e:
|
|
25
|
+
print(e)
|
|
26
|
+
return None
|
|
27
|
+
return pypi_version
|
|
28
|
+
|
|
20
29
|
if __name__ == "__main__":
|
|
21
30
|
version, version_type = load_local_version()
|
|
22
31
|
print(f"Version: {version}, Type: {version_type}")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from user_scanner.core.orchestrator import status_validate, Result
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def validate_substack(user: str) -> Result:
|
|
6
|
+
if not (4 <= len(user) <= 32):
|
|
7
|
+
return Result.error("Length must be 4-32 characters")
|
|
8
|
+
|
|
9
|
+
if not re.match(r'^[a-z0-9]+$', user):
|
|
10
|
+
if re.search(r'[A-Z]', user):
|
|
11
|
+
return Result.error("Use lowercase letters only")
|
|
12
|
+
return Result.error("Usernames can only contain lowercase letters and numbers")
|
|
13
|
+
|
|
14
|
+
url = f"https://{user}.substack.com"
|
|
15
|
+
|
|
16
|
+
headers = {
|
|
17
|
+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
|
|
18
|
+
'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",
|
|
19
|
+
'Accept-Encoding': "identity",
|
|
20
|
+
'accept-language': "en-US,en;q=0.9",
|
|
21
|
+
'priority': "u=0, i"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return status_validate(url, 404, 200, headers=headers, follow_redirects=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
user = input("Username?: ").strip()
|
|
29
|
+
result = validate_substack(user)
|
|
30
|
+
|
|
31
|
+
if result == 1:
|
|
32
|
+
print("Available!")
|
|
33
|
+
elif result == 0:
|
|
34
|
+
print("Unavailable!")
|
|
35
|
+
else:
|
|
36
|
+
print(f"Error occurred! Reason: {result.get_reason()}")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from user_scanner.core.orchestrator import generic_validate, Result
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def validate_lichess(user: str) -> Result:
|
|
6
|
+
if not (2 <= len(user) <= 20):
|
|
7
|
+
return Result.error("Length must be 2-20 characters")
|
|
8
|
+
|
|
9
|
+
if not re.match(r'^[a-zA-Z0-9_-]+$', user):
|
|
10
|
+
return Result.error("Usernames can only contain letters, numbers, underscores, and hyphens")
|
|
11
|
+
|
|
12
|
+
if re.search(r'[_-]{2,}', user):
|
|
13
|
+
return Result.error("Username cannot contain consecutive underscores or hyphens")
|
|
14
|
+
|
|
15
|
+
if not re.match(r'.*[a-zA-Z0-9]$', user):
|
|
16
|
+
return Result.error("Username must end with a letter or a number")
|
|
17
|
+
|
|
18
|
+
url = f"https://lichess.org/api/player/autocomplete?term={user}&exists=1"
|
|
19
|
+
|
|
20
|
+
def process(response):
|
|
21
|
+
res_text = response.text.strip().lower()
|
|
22
|
+
if res_text == "true":
|
|
23
|
+
return Result.taken()
|
|
24
|
+
if res_text == "false":
|
|
25
|
+
return Result.available()
|
|
26
|
+
return Result.error("Unexpected error, report it via github issues")
|
|
27
|
+
|
|
28
|
+
return generic_validate(url, process, timeout=3.0)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
user = input("Username?: ").strip()
|
|
33
|
+
result = validate_lichess(user)
|
|
34
|
+
|
|
35
|
+
if result == 1:
|
|
36
|
+
print("Available!")
|
|
37
|
+
elif result == 0:
|
|
38
|
+
print("Unavailable!")
|
|
39
|
+
else:
|
|
40
|
+
print(f"Error occurred! Reason: {result.get_reason()}")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from colorama import Fore
|
|
4
|
+
|
|
5
|
+
def get_version(package_name):
|
|
6
|
+
try:
|
|
7
|
+
from importlib.metadata import version # Python 3.8+
|
|
8
|
+
return version(package_name)
|
|
9
|
+
except Exception:
|
|
10
|
+
return "Unknown"
|
|
11
|
+
|
|
12
|
+
def update_self():
|
|
13
|
+
print("Updating user-scanner using pip...\n")
|
|
14
|
+
try:
|
|
15
|
+
subprocess.check_call([
|
|
16
|
+
sys.executable, "-m", "pip", "uninstall", "user-scanner", "-y"
|
|
17
|
+
])
|
|
18
|
+
subprocess.check_call([
|
|
19
|
+
sys.executable, "-m", "pip", "install", "user-scanner"
|
|
20
|
+
])
|
|
21
|
+
except subprocess.CalledProcessError as e:
|
|
22
|
+
print(f"{Fore.RED}Failed to update user-scanner: {e}{Fore.reset}")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
user_scanner_ver = get_version("user-scanner")
|
|
27
|
+
|
|
28
|
+
print("\nInstalled Version:")
|
|
29
|
+
print(f" • user-scanner: {user_scanner_ver}")
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
user_scanner_ver = get_version("user-scanner")
|
|
33
|
+
print(user_scanner_ver)
|
|
34
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from colorama import Fore
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
from user_scanner.core.version import get_pypi_version, load_local_version
|
|
6
|
+
from user_scanner.utils.update import update_self
|
|
7
|
+
|
|
8
|
+
# Color configs
|
|
9
|
+
R = Fore.RED
|
|
10
|
+
G = Fore.GREEN
|
|
11
|
+
C = Fore.CYAN
|
|
12
|
+
Y = Fore.YELLOW
|
|
13
|
+
X = Fore.RESET
|
|
14
|
+
|
|
15
|
+
CONFIG_PATH = Path(__file__).parent.parent / "config.json"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def load_config() -> dict:
|
|
19
|
+
if CONFIG_PATH.exists():
|
|
20
|
+
return json.loads(CONFIG_PATH.read_text())
|
|
21
|
+
|
|
22
|
+
default = {"auto_update_status": True}
|
|
23
|
+
CONFIG_PATH.write_text(json.dumps(default, indent=2))
|
|
24
|
+
return default
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def save_config_change(status: bool):
|
|
28
|
+
content = load_config()
|
|
29
|
+
content["auto_update_status"] = status
|
|
30
|
+
CONFIG_PATH.write_text(json.dumps(content, indent=2))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_for_updates():
|
|
34
|
+
if not load_config().get("auto_update_status", False):
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
PYPI_URL = "https://pypi.org/pypi/user-scanner/json"
|
|
39
|
+
latest_ver = get_pypi_version(PYPI_URL)
|
|
40
|
+
current_ver, _ = load_local_version()
|
|
41
|
+
|
|
42
|
+
if current_ver != latest_ver:
|
|
43
|
+
print(
|
|
44
|
+
f"\n[!] New version available: "
|
|
45
|
+
f"{R}{current_ver}{X} -> {C}{latest_ver}{X}\n"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
choice = input(
|
|
49
|
+
f"{Y}Do you want to update?{X} (y/n/d: {R}don't ask again{X}): "
|
|
50
|
+
).strip().lower()
|
|
51
|
+
|
|
52
|
+
if choice == "y":
|
|
53
|
+
update_self()
|
|
54
|
+
print(f"[{G}+{X}] {G}Update successful. Please restart the tool.{X}")
|
|
55
|
+
sys.exit(0)
|
|
56
|
+
|
|
57
|
+
elif choice == "d":
|
|
58
|
+
save_config_change(False)
|
|
59
|
+
print(f"[{Y}*{X}] {R}Auto-update checks disabled.{X}")
|
|
60
|
+
|
|
61
|
+
except Exception as e:
|
|
62
|
+
print(f"[{Y}!{X}] {R}Update check failed{X}: {e}")
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from colorama import Fore, Style, init
|
|
3
|
-
from ..utils.version import load_local_version
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
version, version_type = load_local_version()
|
|
7
|
-
init(autoreset=True)
|
|
8
|
-
C_RED = Fore.RED + Style.BRIGHT
|
|
9
|
-
C_CYAN = Fore.CYAN + Style.BRIGHT
|
|
10
|
-
C_GREEN = Fore.GREEN + Style.BRIGHT
|
|
11
|
-
C_WHITE = Fore.WHITE + Style.BRIGHT
|
|
12
|
-
C_MAGENTA = Fore.MAGENTA + Style.BRIGHT
|
|
13
|
-
BANNER_ASCII = fr"""{C_CYAN} _ _ ___ ___ _ __ ___ ___ __ _ _ __ _ __ ___ _ __
|
|
14
|
-
| | | / __|/ _ \ '__|____/ __|/ __/ _` | '_ \| '_ \ / _ \ '__|
|
|
15
|
-
| |_| \__ \ __/ | |_____\__ \ (_| (_| | | | | | | | __/ |
|
|
16
|
-
\__,_|___/\___|_| |___/\___\__,_|_| |_|_| |_|\___|_| Version: {version}
|
|
17
|
-
{Style.RESET_ALL}""".strip()
|
|
18
|
-
|
|
19
|
-
INFO_BOX = f"""{C_MAGENTA} ╔════════════════════════════════════════╗
|
|
20
|
-
║ {C_RED}♚ {C_GREEN}Project Name{C_WHITE} : UserScanner {C_MAGENTA}║
|
|
21
|
-
║ {C_RED}♚ {C_GREEN}Author{C_WHITE} : Kaif {C_MAGENTA}║
|
|
22
|
-
║ {C_RED}♚ {C_GREEN}Github{C_WHITE} : github.com/kaifcodec {C_MAGENTA}║
|
|
23
|
-
║ {C_RED}♚ {C_GREEN}Email{C_WHITE} : kaifcodec@gmail.com {C_MAGENTA}║
|
|
24
|
-
══════════════════════════════════════════{Style.RESET_ALL}""".strip()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def print_banner():
|
|
28
|
-
print(BANNER_ASCII)
|
|
29
|
-
print(INFO_BOX)
|
|
30
|
-
print(" ")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if __name__ == "__main__":
|
|
34
|
-
print_banner()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{user_scanner-1.0.9.1/user_scanner/social → user_scanner-1.0.10.0/user_scanner/creator}/twitch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|