diff --git a/user_scanner/user_scan/community/forospyware.py b/user_scanner/user_scan/community/forospyware.py new file mode 100644 index 00000000..08f995a0 --- /dev/null +++ b/user_scanner/user_scan/community/forospyware.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_forospyware(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forospyware.com/u/{encoded_user}.json" + show_url = f"https://forospyware.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forospyware.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/intervals.py b/user_scanner/user_scan/community/intervals.py new file mode 100644 index 00000000..570be839 --- /dev/null +++ b/user_scanner/user_scan/community/intervals.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_intervals(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.intervals.icu/u/{encoded_user}.json" + show_url = f"https://forum.intervals.icu/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.intervals.icu{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/keyboardmaestro.py b/user_scanner/user_scan/community/keyboardmaestro.py new file mode 100644 index 00000000..2668f6df --- /dev/null +++ b/user_scanner/user_scan/community/keyboardmaestro.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_keyboardmaestro(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.keyboardmaestro.com/u/{encoded_user}.json" + show_url = f"https://forum.keyboardmaestro.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.keyboardmaestro.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/koishi.py b/user_scanner/user_scan/community/koishi.py new file mode 100644 index 00000000..a8beeac7 --- /dev/null +++ b/user_scanner/user_scan/community/koishi.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_koishi(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.koishi.xyz/u/{encoded_user}.json" + show_url = f"https://forum.koishi.xyz/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.koishi.xyz{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/latranchee.py b/user_scanner/user_scan/community/latranchee.py new file mode 100644 index 00000000..2aff2abd --- /dev/null +++ b/user_scanner/user_scan/community/latranchee.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_latranchee(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.latranchee.com/u/{encoded_user}.json" + show_url = f"https://forum.latranchee.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.latranchee.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/liberland.py b/user_scanner/user_scan/community/liberland.py new file mode 100644 index 00000000..12e98082 --- /dev/null +++ b/user_scanner/user_scan/community/liberland.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_liberland(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.liberland.org/u/{encoded_user}.json" + show_url = f"https://forum.liberland.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.liberland.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/openfoodfacts.py b/user_scanner/user_scan/community/openfoodfacts.py new file mode 100644 index 00000000..4475a284 --- /dev/null +++ b/user_scanner/user_scan/community/openfoodfacts.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_openfoodfacts(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.openfoodfacts.org/u/{encoded_user}.json" + show_url = f"https://forum.openfoodfacts.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.openfoodfacts.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/community/openhistoricalmap.py b/user_scanner/user_scan/community/openhistoricalmap.py new file mode 100644 index 00000000..3f381cca --- /dev/null +++ b/user_scanner/user_scan/community/openhistoricalmap.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_openhistoricalmap(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.openhistoricalmap.org/u/{encoded_user}.json" + show_url = f"https://forum.openhistoricalmap.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.openhistoricalmap.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/creative/kustom.py b/user_scanner/user_scan/creative/kustom.py new file mode 100644 index 00000000..f4ba768b --- /dev/null +++ b/user_scanner/user_scan/creative/kustom.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_kustom(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.kustom.rocks/u/{encoded_user}.json" + show_url = f"https://forum.kustom.rocks/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.kustom.rocks{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/krakenrf.py b/user_scanner/user_scan/dev/krakenrf.py new file mode 100644 index 00000000..f236844f --- /dev/null +++ b/user_scanner/user_scan/dev/krakenrf.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_krakenrf(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.krakenrf.com/u/{encoded_user}.json" + show_url = f"https://forum.krakenrf.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.krakenrf.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/lers.py b/user_scanner/user_scan/dev/lers.py new file mode 100644 index 00000000..7d2eb542 --- /dev/null +++ b/user_scanner/user_scan/dev/lers.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_lers(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.lers.ru/u/{encoded_user}.json" + show_url = f"https://forum.lers.ru/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.lers.ru{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/mbse_capella.py b/user_scanner/user_scan/dev/mbse_capella.py new file mode 100644 index 00000000..d3098ab9 --- /dev/null +++ b/user_scanner/user_scan/dev/mbse_capella.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_mbse_capella(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mbse-capella.org/u/{encoded_user}.json" + show_url = f"https://forum.mbse-capella.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.mbse-capella.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/mgear_framework.py b/user_scanner/user_scan/dev/mgear_framework.py new file mode 100644 index 00000000..7f4ffe31 --- /dev/null +++ b/user_scanner/user_scan/dev/mgear_framework.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_mgear_framework(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mgear-framework.com/u/{encoded_user}.json" + show_url = f"https://forum.mgear-framework.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.mgear-framework.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/msp360.py b/user_scanner/user_scan/dev/msp360.py new file mode 100644 index 00000000..8fd64efc --- /dev/null +++ b/user_scanner/user_scan/dev/msp360.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_msp360(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.msp360.com/u/{encoded_user}.json" + show_url = f"https://forum.msp360.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.msp360.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/ngsolve.py b/user_scanner/user_scan/dev/ngsolve.py new file mode 100644 index 00000000..2b56ee2a --- /dev/null +++ b/user_scanner/user_scan/dev/ngsolve.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_ngsolve(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.ngsolve.org/u/{encoded_user}.json" + show_url = f"https://forum.ngsolve.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.ngsolve.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/odin_lang.py b/user_scanner/user_scan/dev/odin_lang.py new file mode 100644 index 00000000..40e7f671 --- /dev/null +++ b/user_scanner/user_scan/dev/odin_lang.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_odin_lang(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.odin-lang.org/u/{encoded_user}.json" + show_url = f"https://forum.odin-lang.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.odin-lang.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/opencraft.py b/user_scanner/user_scan/dev/opencraft.py new file mode 100644 index 00000000..04291795 --- /dev/null +++ b/user_scanner/user_scan/dev/opencraft.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_opencraft(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.opencraft.com/u/{encoded_user}.json" + show_url = f"https://forum.opencraft.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.opencraft.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/openeuler.py b/user_scanner/user_scan/dev/openeuler.py new file mode 100644 index 00000000..75ce1da8 --- /dev/null +++ b/user_scanner/user_scan/dev/openeuler.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_openeuler(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.openeuler.org/u/{encoded_user}.json" + show_url = f"https://forum.openeuler.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.openeuler.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/openremote.py b/user_scanner/user_scan/dev/openremote.py new file mode 100644 index 00000000..ca7fc523 --- /dev/null +++ b/user_scanner/user_scan/dev/openremote.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_openremote(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.openremote.io/u/{encoded_user}.json" + show_url = f"https://forum.openremote.io/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.openremote.io{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/plexim.py b/user_scanner/user_scan/dev/plexim.py new file mode 100644 index 00000000..a9fac591 --- /dev/null +++ b/user_scanner/user_scan/dev/plexim.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_plexim(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.plexim.com/u/{encoded_user}.json" + show_url = f"https://forum.plexim.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.plexim.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/qorvo.py b/user_scanner/user_scan/dev/qorvo.py new file mode 100644 index 00000000..42c8f7ec --- /dev/null +++ b/user_scanner/user_scan/dev/qorvo.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_qorvo(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.qorvo.com/u/{encoded_user}.json" + show_url = f"https://forum.qorvo.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.qorvo.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/rakwireless.py b/user_scanner/user_scan/dev/rakwireless.py new file mode 100644 index 00000000..912f0059 --- /dev/null +++ b/user_scanner/user_scan/dev/rakwireless.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_rakwireless(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.rakwireless.com/u/{encoded_user}.json" + show_url = f"https://forum.rakwireless.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.rakwireless.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/sensmetry.py b/user_scanner/user_scan/dev/sensmetry.py new file mode 100644 index 00000000..be192a1d --- /dev/null +++ b/user_scanner/user_scan/dev/sensmetry.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_sensmetry(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.sensmetry.com/u/{encoded_user}.json" + show_url = f"https://forum.sensmetry.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.sensmetry.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/sienci.py b/user_scanner/user_scan/dev/sienci.py new file mode 100644 index 00000000..bbeadc38 --- /dev/null +++ b/user_scanner/user_scan/dev/sienci.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_sienci(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.sienci.com/u/{encoded_user}.json" + show_url = f"https://forum.sienci.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.sienci.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/dev/spacecubics.py b/user_scanner/user_scan/dev/spacecubics.py new file mode 100644 index 00000000..a4f1d553 --- /dev/null +++ b/user_scanner/user_scan/dev/spacecubics.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_spacecubics(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.spacecubics.com/u/{encoded_user}.json" + show_url = f"https://forum.spacecubics.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.spacecubics.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/inderes.py b/user_scanner/user_scan/finance/inderes.py new file mode 100644 index 00000000..6652beb0 --- /dev/null +++ b/user_scanner/user_scan/finance/inderes.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_inderes(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.inderes.com/u/{encoded_user}.json" + show_url = f"https://forum.inderes.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.inderes.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/monero_space.py b/user_scanner/user_scan/finance/monero_space.py new file mode 100644 index 00000000..145d491a --- /dev/null +++ b/user_scanner/user_scan/finance/monero_space.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_monero_space(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.monero.space/u/{encoded_user}.json" + show_url = f"https://forum.monero.space/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.monero.space{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/moonbeam.py b/user_scanner/user_scan/finance/moonbeam.py new file mode 100644 index 00000000..e7ea06a0 --- /dev/null +++ b/user_scanner/user_scan/finance/moonbeam.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_moonbeam(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.moonbeam.network/u/{encoded_user}.json" + show_url = f"https://forum.moonbeam.network/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.moonbeam.network{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/moonwell.py b/user_scanner/user_scan/finance/moonwell.py new file mode 100644 index 00000000..914114f7 --- /dev/null +++ b/user_scanner/user_scan/finance/moonwell.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_moonwell(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.moonwell.fi/u/{encoded_user}.json" + show_url = f"https://forum.moonwell.fi/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.moonwell.fi{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/mustachianpost.py b/user_scanner/user_scan/finance/mustachianpost.py new file mode 100644 index 00000000..633d285a --- /dev/null +++ b/user_scanner/user_scan/finance/mustachianpost.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_mustachianpost(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mustachianpost.com/u/{encoded_user}.json" + show_url = f"https://forum.mustachianpost.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.mustachianpost.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/nimiq.py b/user_scanner/user_scan/finance/nimiq.py new file mode 100644 index 00000000..56b91b19 --- /dev/null +++ b/user_scanner/user_scan/finance/nimiq.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_nimiq(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.nimiq.community/u/{encoded_user}.json" + show_url = f"https://forum.nimiq.community/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.nimiq.community{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/pancakeswap.py b/user_scanner/user_scan/finance/pancakeswap.py new file mode 100644 index 00000000..359368db --- /dev/null +++ b/user_scanner/user_scan/finance/pancakeswap.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_pancakeswap(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.pancakeswap.finance/u/{encoded_user}.json" + show_url = f"https://forum.pancakeswap.finance/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.pancakeswap.finance{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/pokt.py b/user_scanner/user_scan/finance/pokt.py new file mode 100644 index 00000000..7319f4c7 --- /dev/null +++ b/user_scanner/user_scan/finance/pokt.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_pokt(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.pokt.network/u/{encoded_user}.json" + show_url = f"https://forum.pokt.network/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.pokt.network{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/polygon.py b/user_scanner/user_scan/finance/polygon.py new file mode 100644 index 00000000..0dd54a0f --- /dev/null +++ b/user_scanner/user_scan/finance/polygon.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_polygon(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.polygon.technology/u/{encoded_user}.json" + show_url = f"https://forum.polygon.technology/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.polygon.technology{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/reserve.py b/user_scanner/user_scan/finance/reserve.py new file mode 100644 index 00000000..07dfe942 --- /dev/null +++ b/user_scanner/user_scan/finance/reserve.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_reserve(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.reserve.org/u/{encoded_user}.json" + show_url = f"https://forum.reserve.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.reserve.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/scroll.py b/user_scanner/user_scan/finance/scroll.py new file mode 100644 index 00000000..3996afa2 --- /dev/null +++ b/user_scanner/user_scan/finance/scroll.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_scroll(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.scroll.io/u/{encoded_user}.json" + show_url = f"https://forum.scroll.io/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.scroll.io{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/ssv.py b/user_scanner/user_scan/finance/ssv.py new file mode 100644 index 00000000..d91b2135 --- /dev/null +++ b/user_scanner/user_scan/finance/ssv.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_ssv(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.ssv.network/u/{encoded_user}.json" + show_url = f"https://forum.ssv.network/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.ssv.network{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/finance/stacks.py b/user_scanner/user_scan/finance/stacks.py new file mode 100644 index 00000000..da6a67ee --- /dev/null +++ b/user_scanner/user_scan/finance/stacks.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_stacks(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.stacks.org/u/{encoded_user}.json" + show_url = f"https://forum.stacks.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.stacks.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/killerchesstraining.py b/user_scanner/user_scan/gaming/killerchesstraining.py new file mode 100644 index 00000000..a27f68dc --- /dev/null +++ b/user_scanner/user_scan/gaming/killerchesstraining.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_killerchesstraining(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.killerchesstraining.com/u/{encoded_user}.json" + show_url = f"https://forum.killerchesstraining.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.killerchesstraining.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/nikeagames.py b/user_scanner/user_scan/gaming/nikeagames.py new file mode 100644 index 00000000..8a084e2e --- /dev/null +++ b/user_scanner/user_scan/gaming/nikeagames.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_nikeagames(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.nikeagames.com/u/{encoded_user}.json" + show_url = f"https://forum.nikeagames.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.nikeagames.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/playboundless.py b/user_scanner/user_scan/gaming/playboundless.py new file mode 100644 index 00000000..043a8c35 --- /dev/null +++ b/user_scanner/user_scan/gaming/playboundless.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_playboundless(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.playboundless.com/u/{encoded_user}.json" + show_url = f"https://forum.playboundless.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.playboundless.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/playhive.py b/user_scanner/user_scan/gaming/playhive.py new file mode 100644 index 00000000..f71b6285 --- /dev/null +++ b/user_scanner/user_scan/gaming/playhive.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_playhive(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.playhive.com/u/{encoded_user}.json" + show_url = f"https://forum.playhive.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.playhive.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/playinzoi.py b/user_scanner/user_scan/gaming/playinzoi.py new file mode 100644 index 00000000..e10da6f6 --- /dev/null +++ b/user_scanner/user_scan/gaming/playinzoi.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_playinzoi(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.playinzoi.com/u/{encoded_user}.json" + show_url = f"https://forum.playinzoi.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.playinzoi.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/gaming/pretendo.py b/user_scanner/user_scan/gaming/pretendo.py new file mode 100644 index 00000000..f23b6148 --- /dev/null +++ b/user_scanner/user_scan/gaming/pretendo.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_pretendo(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.pretendo.network/u/{encoded_user}.json" + show_url = f"https://forum.pretendo.network/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.pretendo.network{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/learning/obsidian_zh.py b/user_scanner/user_scan/learning/obsidian_zh.py new file mode 100644 index 00000000..baa016c4 --- /dev/null +++ b/user_scanner/user_scan/learning/obsidian_zh.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_obsidian_zh(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum-zh.obsidian.md/u/{encoded_user}.json" + show_url = f"https://forum-zh.obsidian.md/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum-zh.obsidian.md{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/music/hifiguides.py b/user_scanner/user_scan/music/hifiguides.py new file mode 100644 index 00000000..c39973fd --- /dev/null +++ b/user_scanner/user_scan/music/hifiguides.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_hifiguides(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.hifiguides.com/u/{encoded_user}.json" + show_url = f"https://forum.hifiguides.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.hifiguides.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/music/ikmultimedia.py b/user_scanner/user_scan/music/ikmultimedia.py new file mode 100644 index 00000000..fa351115 --- /dev/null +++ b/user_scanner/user_scan/music/ikmultimedia.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_ikmultimedia(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.ikmultimedia.com/u/{encoded_user}.json" + show_url = f"https://forum.ikmultimedia.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.ikmultimedia.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/music/midibox.py b/user_scanner/user_scan/music/midibox.py new file mode 100644 index 00000000..5affb373 --- /dev/null +++ b/user_scanner/user_scan/music/midibox.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_midibox(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.midibox.org/u/{encoded_user}.json" + show_url = f"https://forum.midibox.org/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.midibox.org{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/music/spinitron.py b/user_scanner/user_scan/music/spinitron.py new file mode 100644 index 00000000..05f8d368 --- /dev/null +++ b/user_scanner/user_scan/music/spinitron.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_spinitron(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.spinitron.com/u/{encoded_user}.json" + show_url = f"https://forum.spinitron.com/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.spinitron.com{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True) diff --git a/user_scanner/user_scan/social/jami.py b/user_scanner/user_scan/social/jami.py new file mode 100644 index 00000000..20f02241 --- /dev/null +++ b/user_scanner/user_scan/social/jami.py @@ -0,0 +1,67 @@ +import urllib.parse +from user_scanner.core.helpers import get_random_user_agent +from user_scanner.core.orchestrator import Result, generic_validate + +def validate_jami(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.jami.net/u/{encoded_user}.json" + show_url = f"https://forum.jami.net/u/{encoded_user}" + + headers = { + "User-Agent": get_random_user_agent(), + "Accept": "application/json", + } + + def process(response) -> Result: + if response.status_code == 404: + try: + data = response.json() + if ( + data.get("error_type") == "not_found" + or any("not be found" in str(err).lower() for err in data.get("errors", [])) + ): + return Result.available(url=show_url) + except Exception: + pass + return Result.error("Discourse 404 response missing expected error payload") + + if response.status_code == 200: + try: + data = response.json() + user_obj = data.get("user") + if user_obj and isinstance(user_obj, dict) and user_obj.get("username"): + extra: dict[str, str] = {} + media: dict[str, str] = {} + + if user_obj.get("name"): + extra["name"] = str(user_obj["name"]) + if user_obj.get("title"): + extra["title"] = str(user_obj["title"]) + if user_obj.get("location"): + extra["location"] = str(user_obj["location"]) + if user_obj.get("website_name") or user_obj.get("website"): + extra["website"] = str(user_obj.get("website") or user_obj.get("website_name")) + if user_obj.get("trust_level") is not None: + extra["trust_level"] = str(user_obj["trust_level"]) + if user_obj.get("badge_count") is not None: + extra["badges"] = str(user_obj["badge_count"]) + if user_obj.get("created_at"): + extra["joined"] = str(user_obj["created_at"]) + if user_obj.get("bio_raw") or user_obj.get("bio_cooked"): + extra["bio"] = str(user_obj.get("bio_raw") or user_obj.get("bio_cooked")) + + avatar_template = user_obj.get("avatar_template") + if avatar_template: + avatar_url = avatar_template.replace("{size}", "240") + if avatar_url.startswith("/"): + avatar_url = f"https://forum.jami.net{avatar_url}" + media["avatar"] = avatar_url + + return Result.taken(url=show_url, extra=extra, media=media) + except Exception: + pass + return Result.error("Discourse 200 response missing valid user payload") + + return Result.error(f"Unexpected status code: {response.status_code}") + + return generic_validate(url, process, headers=headers, show_url=show_url, follow_redirects=True)