diff --git a/README.md b/README.md index 7897be5..1ad1e90 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,10 @@ $ python3 main.py - [Twitch](https://twitch.tv/) - [X](https://x.com/) - \ No newline at end of file + + +## 🖇️ Proxy support + +We allow the use of proxies, however, if you use public proxies you'll likely encounter an infinite ratelimit from hundreds or thousands of people using the same proxy. Proxies can dramatically speed up or slow down the process depending on their quality. + +Proxies should be stored in a format in a `protocol://ip:port` format. \ No newline at end of file diff --git a/src/base/checker.py b/src/base/checker.py index f5f18e1..26b6000 100644 --- a/src/base/checker.py +++ b/src/base/checker.py @@ -1,29 +1,21 @@ -import concurrent.futures +"""Base username availability checker class. +""" from functools import singledispatchmethod -from httpx._types import ProxiesTypes +from utils.proxies import get_proxy class BaseChecker: ENDPOINT = "" RATELIMIT_TIMEOUT = 0.5 - def __init__(self, proxies:ProxiesTypes=None, max_workers:int=5) -> None: - self.proxies = proxies - self.max_workers = max_workers - @singledispatchmethod def check(self) -> str|None: - """Checks if username is available""" + """Checks if username is available.""" raise NotImplementedError - - @check.register - def _(self, usernames:list) -> list[str]: - with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor: - futures = {executor.submit(self.check, username): username for username in usernames} - r = [] - for future in concurrent.futures.as_completed(futures): - r.append(future.result()) - r = filter(lambda item: item is not None, r) - return r \ No newline at end of file + def get_proxy(self, proxy_path:str) -> dict: + """Returns a valid proxy.""" + if len(proxy_path) == 0: + return {} + return get_proxy(proxy_path) diff --git a/src/checkers/beacons-ai.py b/src/checkers/beacons-ai.py index e00449e..20380f9 100644 --- a/src/checkers/beacons-ai.py +++ b/src/checkers/beacons-ai.py @@ -12,7 +12,9 @@ class Checker(BaseChecker): ENDPOINT = "https://account.beacons.ai/api/user_profile" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + if len(username) > 30: return None elif username.startswith(".") or username.endswith(".") or ".." in username: @@ -21,15 +23,15 @@ def _(self, username:str) -> str|None: return None elif not all(c.isalnum() and c.isascii() or c in "_." for c in username): return None - + headers = {"X-Beacons-Application-Viewed": "web", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"} payload = {"new_username": username, "action": "is_username_taken"} r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.post(self.ENDPOINT, json=payload, headers=headers) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()["username_taken"] == False else None \ No newline at end of file + + return username if r.json()["username_taken"] is False else None diff --git a/src/checkers/chess-com.py b/src/checkers/chess-com.py index 4a05aec..52b8720 100644 --- a/src/checkers/chess-com.py +++ b/src/checkers/chess-com.py @@ -12,12 +12,14 @@ class Checker(BaseChecker): ENDPOINT = "https://www.chess.com/callback/user/valid?username=" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()["valid"] else None \ No newline at end of file + + return username if r.json()["valid"] else None diff --git a/src/checkers/github.py b/src/checkers/github.py index 566734c..8192ff6 100644 --- a/src/checkers/github.py +++ b/src/checkers/github.py @@ -12,19 +12,21 @@ class Checker(BaseChecker): ENDPOINT = "https://github.com/" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + if len(username) > 39: return None elif username.startswith("-") or username.endswith("-") or "--" in username: return None elif not all(c.isalnum() and c.isascii() or c in "-" for c in username): return None - + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.status_code == 404 else None \ No newline at end of file + + return username if r.status_code == 404 else None diff --git a/src/checkers/gitlab.py b/src/checkers/gitlab.py index 4371012..87d9c18 100644 --- a/src/checkers/gitlab.py +++ b/src/checkers/gitlab.py @@ -12,12 +12,14 @@ class Checker(BaseChecker): ENDPOINT = "https://gitlab.com/users/" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}/exists") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()["exists"] == False else None \ No newline at end of file + + return username if r.json()["exists"] is False else None diff --git a/src/checkers/instagram.py b/src/checkers/instagram.py index ae8e77f..b9138ff 100644 --- a/src/checkers/instagram.py +++ b/src/checkers/instagram.py @@ -12,15 +12,17 @@ class Checker(BaseChecker): ENDPOINT = "https://www.instagram.com/api/v1/web/accounts/web_create_ajax/attempt/" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + headers = {"X-CSRFToken": "en"} payload = {"email": "", "username": username, "first_name": "", "opt_into_one_tap": False} - + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.post(self.ENDPOINT, data=payload, headers=headers) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if not "\"username\": [{\"message\": " in r.text else None \ No newline at end of file + + return username if not "\"username\": [{\"message\": " in r.text else None diff --git a/src/checkers/kahoot.py b/src/checkers/kahoot.py index 8cdd1a4..dce8a85 100644 --- a/src/checkers/kahoot.py +++ b/src/checkers/kahoot.py @@ -12,14 +12,16 @@ class Checker(BaseChecker): ENDPOINT = "https://create.kahoot.it/rest/users/usernameavailable" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + headers={"x-kahoot-user-identifier": username} r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(self.ENDPOINT, headers=headers) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json().get("isUsernameAvailable") else None \ No newline at end of file + + return username if r.json().get("isUsernameAvailable") else None diff --git a/src/checkers/lichess.py b/src/checkers/lichess.py index c35222d..e4b432d 100644 --- a/src/checkers/lichess.py +++ b/src/checkers/lichess.py @@ -12,14 +12,16 @@ class Checker(BaseChecker): ENDPOINT = "https://lichess.org/api/player/autocomplete?term=" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + payload = f"{username}&exists=1" r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{payload}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json() == False else None \ No newline at end of file + + return username if r.json() is False else None diff --git a/src/checkers/linktree.py b/src/checkers/linktree.py index 1a18f83..153de71 100644 --- a/src/checkers/linktree.py +++ b/src/checkers/linktree.py @@ -12,15 +12,17 @@ class Checker(BaseChecker): ENDPOINT = "https://linktr.ee/validate/username" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"} payload = {"username": username, "returnSuggestions": False} r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.post(self.ENDPOINT, json=payload, headers=headers) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()["result"] == "success" else None \ No newline at end of file + + return username if r.json()["result"] == "success" else None diff --git a/src/checkers/minecraft.py b/src/checkers/minecraft.py index 2c1aa14..9a418f5 100644 --- a/src/checkers/minecraft.py +++ b/src/checkers/minecraft.py @@ -12,12 +12,14 @@ class Checker(BaseChecker): ENDPOINT = "https://api.mojang.com/users/profiles/minecraft/" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.head(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.status_code == 404 else None \ No newline at end of file + + return username if r.status_code == 404 else None diff --git a/src/checkers/replit.py b/src/checkers/replit.py index 516d8c2..2bd446b 100644 --- a/src/checkers/replit.py +++ b/src/checkers/replit.py @@ -12,8 +12,10 @@ class Checker(BaseChecker): ENDPOINT = "https://replit.com/@" @BaseChecker.check.register - def _(self, username:str) -> str|None: - if not (2 < len(username) <= 15): + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + + if not 2 < len(username) <= 15: return None elif "--" in username: return None @@ -22,9 +24,9 @@ def _(self, username:str) -> str|None: r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.head(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.status_code == 404 else None \ No newline at end of file + + return username if r.status_code == 404 else None diff --git a/src/checkers/roblox.py b/src/checkers/roblox.py index 50dd8f1..88988e6 100644 --- a/src/checkers/roblox.py +++ b/src/checkers/roblox.py @@ -12,12 +12,14 @@ class Checker(BaseChecker): ENDPOINT = "https://auth.roblox.com/v1/usernames/validate?birthday=2000-01-01T00:00:00.000Z&context=Signup&username=" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()['code'] == 0 else None \ No newline at end of file + + return username if r.json()['code'] == 0 else None diff --git a/src/checkers/solo-to.py b/src/checkers/solo-to.py index 4a351bd..6d447e6 100644 --- a/src/checkers/solo-to.py +++ b/src/checkers/solo-to.py @@ -12,21 +12,23 @@ class Checker(BaseChecker): ENDPOINT = "https://api.solo.to/" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + if not (1 < len(username) <= 20): return None elif username.endswith(".") or username.endswith(".") or ".." in username: return None elif not all(c.isalnum() and c.isascii() or c in "-_." for c in username): return None - + headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"} r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}", headers=headers) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if "page not found" in r.text else None \ No newline at end of file + + return username if "page not found" in r.text else None diff --git a/src/checkers/soundcloud.py b/src/checkers/soundcloud.py index 9fef09c..32697b2 100644 --- a/src/checkers/soundcloud.py +++ b/src/checkers/soundcloud.py @@ -12,8 +12,10 @@ class Checker(BaseChecker): ENDPOINT = "https://soundcloud.com/" @BaseChecker.check.register - def _(self, username:str) -> str|None: - if not (3 < len(username) <= 25): + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + + if not 3 < len(username) <= 25: return None elif username.startswith("-") or username.startswith("_"): return None @@ -24,9 +26,9 @@ def _(self, username:str) -> str|None: r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.head(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.status_code == 404 else None \ No newline at end of file + + return username if r.status_code == 404 else None diff --git a/src/checkers/speedrun-com.py b/src/checkers/speedrun-com.py index 455f21a..e940602 100644 --- a/src/checkers/speedrun-com.py +++ b/src/checkers/speedrun-com.py @@ -12,14 +12,16 @@ class Checker(BaseChecker): ENDPOINT = "https://www.speedrun.com/api/v2/PutAuthSignup" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + payload = {"areaId": "", "email": "email@example.com", "name": username, "password": "realpassword123"} - + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.post(self.ENDPOINT, json=payload) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.status_code == 200 else None \ No newline at end of file + + return username if r.status_code == 200 else None diff --git a/src/checkers/steam.py b/src/checkers/steam.py index ecb8ba2..280965c 100644 --- a/src/checkers/steam.py +++ b/src/checkers/steam.py @@ -12,17 +12,19 @@ class Checker(BaseChecker): ENDPOINT = "https://steamcommunity.com/id/" @BaseChecker.check.register - def _(self, username:str) -> str|None: - if not (2 < len(username) <= 32): + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + + if not 2 < len(username) <= 32: return None elif not all(c.isalnum() and c.isascii() or c in "-_" for c in username): return None r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if "The specified profile could not be found." in r.text else None \ No newline at end of file + + return username if "The specified profile could not be found." in r.text else None diff --git a/src/checkers/twitch.py b/src/checkers/twitch.py index 55f0b84..3b0c307 100644 --- a/src/checkers/twitch.py +++ b/src/checkers/twitch.py @@ -12,15 +12,17 @@ class Checker(BaseChecker): ENDPOINT = "https://gql.twitch.tv/gql" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + headers={"client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko"} payload = [{"operationName": "UsernameValidator_User", "variables": {"username": username}, "extensions": {"persistedQuery": {"version": 1, "sha256Hash": "fd1085cf8350e309b725cf8ca91cd90cac03909a3edeeedbd0872ac912f3d660"}}}] r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.post(self.ENDPOINT, headers=headers, json=payload) if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) - - return username if r.json()[0]["data"]["isUsernameAvailable"] else None \ No newline at end of file + + return username if r.json()[0]["data"]["isUsernameAvailable"] else None diff --git a/src/checkers/x.py b/src/checkers/x.py index c892fee..3d2d0da 100644 --- a/src/checkers/x.py +++ b/src/checkers/x.py @@ -12,15 +12,17 @@ class Checker(BaseChecker): ENDPOINT = "https://api.twitter.com/i/users/username_available.json?username=" @BaseChecker.check.register - def _(self, username:str) -> str|None: + def _(self, username:str, proxies:str="") -> str|None: + proxies = self.get_proxy(proxies) + r = Response(429) while r.status_code == 429: - with httpx.Client(verify=False, proxies=self.proxies) as client: + with httpx.Client(verify=False, proxies=proxies) as client: r = client.get(f"{self.ENDPOINT}{username}") if r.status_code == 429: time.sleep(self.RATELIMIT_TIMEOUT) elif not r.json().get("valid"): r = Response(429) # API failed to respond, retry. - - print(r.json()) - return username if r.json()["valid"] else None \ No newline at end of file + + #print(r.json()) + return username if r.json()["valid"] else None diff --git a/src/main.py b/src/main.py index dead2cc..3c924f3 100644 --- a/src/main.py +++ b/src/main.py @@ -1,12 +1,19 @@ +"""User menu for checking username availability. +""" +import concurrent.futures +import itertools import pathlib import time from utils.checkers import get_checker, path from utils.output import clear, title -from utils.prompts import select_checker, select_usernames +from utils.prompts import bool_input, select_checker, select_file def main(): + """ + Prompts the user for username data and saves the hits as a file. + """ clear() title() try: @@ -16,27 +23,40 @@ def main(): checker = get_checker(checker_name) # Username list selector - usernames = select_usernames() - print(f"\nSelected {len(usernames)} usernames from list.") + print("\nSelect your usernames list.") + usernames = select_file() + print(f"Selected {len(usernames)} usernames from list.") - # TODO: Prompt user for proxies and amount of threads + # Proxy selector + proxies = [] + if bool_input("\nUse proxies?", False): + print("Select your proxy list.") + proxies = select_file() + print(f"Loaded {len(proxies)} proxies.") # Get hits print("\nStarting...") start = time.perf_counter() - hits = [r for r in checker.check(usernames)] + + with concurrent.futures.ThreadPoolExecutor() as executor: + hits = set(executor.map(checker.check, usernames, itertools.repeat(proxies))) + if None in hits: + hits.remove(None) + elapsed = time.perf_counter() - start print(f"Done! Took {elapsed:.2f}s") # Save hits pathlib.Path(f"{path}/hits").mkdir(exist_ok=True) output_name = f"{checker_name.lower()}-{time.strftime('%Y%m%d-%H%M%S')}" - with open(f"{path}/hits/{output_name}.txt", "w") as f: + with open(f"{path}/hits/{output_name}.txt", "w", encoding="utf8") as f: f.writelines("\n".join(hits)) + except (KeyboardInterrupt, EOFError): pass + print("\nGoodbye!") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/src/utils/checkers.py b/src/utils/checkers.py index fc969cc..0ebceb9 100644 --- a/src/utils/checkers.py +++ b/src/utils/checkers.py @@ -1,3 +1,5 @@ +"""Checker modules utils. +""" import pathlib from base.checker import BaseChecker @@ -15,9 +17,9 @@ def get_checkers() -> list[str]: return checkers -def get_checker(name:str) -> BaseChecker: +def get_checker(name:str, kwargs:dict={}) -> BaseChecker: """Imports a checker module and returns it's Checker class""" module = __import__(f"checkers.{name.replace('.', '-').lower()}", fromlist=[None]) - checker = module.Checker() + checker = module.Checker(**kwargs) - return checker \ No newline at end of file + return checker diff --git a/src/utils/output.py b/src/utils/output.py index 747b724..383e437 100644 --- a/src/utils/output.py +++ b/src/utils/output.py @@ -1,3 +1,5 @@ +"""Output utils. +""" import os @@ -26,5 +28,5 @@ def print_columns(values:list, columns:int=3, start:str="", end:str="\n") -> Non for i, value in enumerate(values, 1): out += f"{value: <{seperator}}" out += f"\n{start}" if i % columns == 0 else " " - - print(out, end=end) \ No newline at end of file + + print(out, end=end) diff --git a/src/utils/prompts.py b/src/utils/prompts.py index 0da2be8..5d1eef6 100644 --- a/src/utils/prompts.py +++ b/src/utils/prompts.py @@ -1,3 +1,5 @@ +"""User prompts utils. +""" import tkinter as tk from tkinter import filedialog @@ -19,20 +21,33 @@ def select_checker() -> str: while name.capitalize() not in checkers: print(" Invalid checker! Try again.\n") name = input("Which checker do you want to use: ") - + return name -def select_usernames() -> str: - """Opens file dialog and prompts for list of usernames. If cancelled, exits.""" +def select_file() -> str: + """Opens file dialog and prompts for text file. If cancelled, exits.""" file = filedialog.askopenfilename( initialdir=f"{path}/presets", filetypes=[("Text files", "*.txt"), ("All files", "*.*")] ) if not file: exit() - - with open(file) as f: + + with open(file, encoding="utf8") as f: usernames = f.read().splitlines() - - return usernames \ No newline at end of file + + return usernames + + +def bool_input(input_prompt:str, default:bool=True) -> bool: + """Prompts user for a bool.""" + input_str:str = input(input_prompt + f" ({'Y/n' if default else 'y/N'}): ") + + if input_str.lower().startswith("y"): + return True + + elif input_str.lower().startswith("n"): + return False + + return default diff --git a/src/utils/proxies.py b/src/utils/proxies.py new file mode 100644 index 0000000..18f752b --- /dev/null +++ b/src/utils/proxies.py @@ -0,0 +1,32 @@ +"""Proxy utils. +""" +import httpx + + +def test_proxy(proxy:str) -> bool: + """Tests the validity of a proxy.""" + proxies = {"http://":f"{proxy}", "https://":f"{proxy}"} + + try: + with httpx.Client(verify=False, proxies=proxies) as client: + _ = client.get("https://httpbin.io/ip").json() + return True + except: + return False + + +def get_proxy(proxies:list) -> dict: + """Gets a valid proxy from a list of proxies.""" + for proxy in proxies: + proxies.remove(proxy) + proxy = proxy.removesuffix("\n") + if test_proxy(proxy): + return {"http://":f"{proxy}", "https://":f"{proxy}"} + + print("No valid proxy in your provided list! Make sure you're using HTTP proxies and not SOCK5.") + exit(1) + + +if __name__ == "__main__": + test = "".splitlines() # put an IP to test there + print(get_proxy(test)) diff --git a/update_list.py b/update_list.py index 5c2ca8f..b499229 100644 --- a/update_list.py +++ b/update_list.py @@ -11,13 +11,13 @@ for file in files: file = file.replace("\\", "/") - with open(file, "r") as f: + with open(file, "r", encoding="utf8") as f: link = f.readlines()[0].strip().removeprefix("\"\"\"") website = file.split("/")[-1].removesuffix(".py").replace("-", ".").capitalize() md += f"\n- [{website}]({link})" - + md += "\n\n" md += f_text.split("")[1] with open("README.md", "w", encoding="utf-8") as f: - f.write(md) \ No newline at end of file + f.write(md)