diff --git a/user_scanner/user_scan/community/bambulab.py b/user_scanner/user_scan/community/bambulab.py new file mode 100644 index 00000000..9add58b3 --- /dev/null +++ b/user_scanner/user_scan/community/bambulab.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_bambulab(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.bambulab.com/u/{encoded_user}.json" + show_url = f"https://forum.bambulab.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.bambulab.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/calculate_linux.py b/user_scanner/user_scan/community/calculate_linux.py new file mode 100644 index 00000000..b8a08bae --- /dev/null +++ b/user_scanner/user_scan/community/calculate_linux.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_calculate_linux(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.calculate-linux.org/u/{encoded_user}.json" + show_url = f"https://forum.calculate-linux.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.calculate-linux.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/emacs_china.py b/user_scanner/user_scan/community/emacs_china.py new file mode 100644 index 00000000..73186c10 --- /dev/null +++ b/user_scanner/user_scan/community/emacs_china.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_emacs_china(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://emacs-china.org/u/{encoded_user}.json" + show_url = f"https://emacs-china.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://emacs-china.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/freifunk.py b/user_scanner/user_scan/community/freifunk.py new file mode 100644 index 00000000..d3629038 --- /dev/null +++ b/user_scanner/user_scan/community/freifunk.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_freifunk(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.freifunk.net/u/{encoded_user}.json" + show_url = f"https://forum.freifunk.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.freifunk.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) diff --git a/user_scanner/user_scan/community/garudalinux.py b/user_scanner/user_scan/community/garudalinux.py new file mode 100644 index 00000000..387e76ee --- /dev/null +++ b/user_scanner/user_scan/community/garudalinux.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_garudalinux(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.garudalinux.org/u/{encoded_user}.json" + show_url = f"https://forum.garudalinux.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.garudalinux.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/geocommuns.py b/user_scanner/user_scan/community/geocommuns.py new file mode 100644 index 00000000..c9b0591c --- /dev/null +++ b/user_scanner/user_scan/community/geocommuns.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_geocommuns(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.geocommuns.fr/u/{encoded_user}.json" + show_url = f"https://forum.geocommuns.fr/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.geocommuns.fr{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/hiveos.py b/user_scanner/user_scan/community/hiveos.py new file mode 100644 index 00000000..172b1bef --- /dev/null +++ b/user_scanner/user_scan/community/hiveos.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_hiveos(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.hiveos.farm/u/{encoded_user}.json" + show_url = f"https://forum.hiveos.farm/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.hiveos.farm{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/ilovegrowingmarijuana.py b/user_scanner/user_scan/community/ilovegrowingmarijuana.py new file mode 100644 index 00000000..aa01bdbf --- /dev/null +++ b/user_scanner/user_scan/community/ilovegrowingmarijuana.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_ilovegrowingmarijuana(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://support.ilovegrowingmarijuana.com/u/{encoded_user}.json" + show_url = f"https://support.ilovegrowingmarijuana.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://support.ilovegrowingmarijuana.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/inaturalist.py b/user_scanner/user_scan/community/inaturalist.py new file mode 100644 index 00000000..0d0c542b --- /dev/null +++ b/user_scanner/user_scan/community/inaturalist.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_inaturalist(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.inaturalist.org/u/{encoded_user}.json" + show_url = f"https://forum.inaturalist.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.inaturalist.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/infinityfree.py b/user_scanner/user_scan/community/infinityfree.py new file mode 100644 index 00000000..58c53854 --- /dev/null +++ b/user_scanner/user_scan/community/infinityfree.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_infinityfree(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.infinityfree.com/u/{encoded_user}.json" + show_url = f"https://forum.infinityfree.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.infinityfree.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/mapillary.py b/user_scanner/user_scan/community/mapillary.py new file mode 100644 index 00000000..69854809 --- /dev/null +++ b/user_scanner/user_scan/community/mapillary.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_mapillary(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mapillary.com/u/{encoded_user}.json" + show_url = f"https://forum.mapillary.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.mapillary.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/openmandriva.py b/user_scanner/user_scan/community/openmandriva.py new file mode 100644 index 00000000..99704960 --- /dev/null +++ b/user_scanner/user_scan/community/openmandriva.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_openmandriva(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.openmandriva.org/u/{encoded_user}.json" + show_url = f"https://forum.openmandriva.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.openmandriva.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/sandisk.py b/user_scanner/user_scan/community/sandisk.py new file mode 100644 index 00000000..d0231830 --- /dev/null +++ b/user_scanner/user_scan/community/sandisk.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_sandisk(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.sandisk.com/u/{encoded_user}.json" + show_url = f"https://forums.sandisk.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://forums.sandisk.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/welcome_suisse.py b/user_scanner/user_scan/community/welcome_suisse.py new file mode 100644 index 00000000..89f3277e --- /dev/null +++ b/user_scanner/user_scan/community/welcome_suisse.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_welcome_suisse(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.welcome-suisse.ch/u/{encoded_user}.json" + show_url = f"https://forum.welcome-suisse.ch/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.welcome-suisse.ch{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/wer_weiss_was.py b/user_scanner/user_scan/community/wer_weiss_was.py new file mode 100644 index 00000000..2bda5ea2 --- /dev/null +++ b/user_scanner/user_scan/community/wer_weiss_was.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_wer_weiss_was(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://wer-weiss-was.de/u/{encoded_user}.json" + show_url = f"https://wer-weiss-was.de/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://wer-weiss-was.de{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/cartridgecollectors.py b/user_scanner/user_scan/creative/cartridgecollectors.py new file mode 100644 index 00000000..4763c68a --- /dev/null +++ b/user_scanner/user_scan/creative/cartridgecollectors.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_cartridgecollectors(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.cartridgecollectors.org/u/{encoded_user}.json" + show_url = f"https://forum.cartridgecollectors.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.cartridgecollectors.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/frame_io.py b/user_scanner/user_scan/creative/frame_io.py new file mode 100644 index 00000000..dffb11eb --- /dev/null +++ b/user_scanner/user_scan/creative/frame_io.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_frame_io(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.frame.io/u/{encoded_user}.json" + show_url = f"https://forum.frame.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.frame.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/creative/icons8.py b/user_scanner/user_scan/creative/icons8.py new file mode 100644 index 00000000..5c4fcb67 --- /dev/null +++ b/user_scanner/user_scan/creative/icons8.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_icons8(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.icons8.com/u/{encoded_user}.json" + show_url = f"https://community.icons8.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://community.icons8.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/creative/inkdrop.py b/user_scanner/user_scan/creative/inkdrop.py new file mode 100644 index 00000000..c4e6b4eb --- /dev/null +++ b/user_scanner/user_scan/creative/inkdrop.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_inkdrop(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.inkdrop.app/u/{encoded_user}.json" + show_url = f"https://forum.inkdrop.app/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.inkdrop.app{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/inventables.py b/user_scanner/user_scan/creative/inventables.py new file mode 100644 index 00000000..179327c8 --- /dev/null +++ b/user_scanner/user_scan/creative/inventables.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_inventables(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://discuss.inventables.com/u/{encoded_user}.json" + show_url = f"https://discuss.inventables.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://discuss.inventables.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/creative/silver_collector.py b/user_scanner/user_scan/creative/silver_collector.py new file mode 100644 index 00000000..3e19208c --- /dev/null +++ b/user_scanner/user_scan/creative/silver_collector.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_silver_collector(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://www.silver-collector.com/u/{encoded_user}.json" + show_url = f"https://www.silver-collector.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://www.silver-collector.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/creative/sketchup.py b/user_scanner/user_scan/creative/sketchup.py new file mode 100644 index 00000000..5eb3f065 --- /dev/null +++ b/user_scanner/user_scan/creative/sketchup.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_sketchup(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.sketchup.com/u/{encoded_user}.json" + show_url = f"https://forums.sketchup.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://forums.sketchup.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/creative/zazzle.py b/user_scanner/user_scan/creative/zazzle.py new file mode 100644 index 00000000..10bde5e3 --- /dev/null +++ b/user_scanner/user_scan/creative/zazzle.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_zazzle(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.zazzle.com/u/{encoded_user}.json" + show_url = f"https://community.zazzle.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://community.zazzle.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/entertainment/dramatica.py b/user_scanner/user_scan/entertainment/dramatica.py new file mode 100644 index 00000000..b4340607 --- /dev/null +++ b/user_scanner/user_scan/entertainment/dramatica.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_dramatica(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://discuss.dramatica.com/u/{encoded_user}.json" + show_url = f"https://discuss.dramatica.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://discuss.dramatica.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/entertainment/filmfind.py b/user_scanner/user_scan/entertainment/filmfind.py new file mode 100644 index 00000000..5479d73c --- /dev/null +++ b/user_scanner/user_scan/entertainment/filmfind.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_filmfind(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://filmfind.me/u/{encoded_user}.json" + show_url = f"https://filmfind.me/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://filmfind.me{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/entertainment/logik_tv.py b/user_scanner/user_scan/entertainment/logik_tv.py new file mode 100644 index 00000000..c1709ae0 --- /dev/null +++ b/user_scanner/user_scan/entertainment/logik_tv.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_logik_tv(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.logik.tv/u/{encoded_user}.json" + show_url = f"https://forum.logik.tv/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.logik.tv{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/entertainment/mediaspy.py b/user_scanner/user_scan/entertainment/mediaspy.py new file mode 100644 index 00000000..54101b55 --- /dev/null +++ b/user_scanner/user_scan/entertainment/mediaspy.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_mediaspy(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.mediaspy.org/u/{encoded_user}.json" + show_url = f"https://forums.mediaspy.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://forums.mediaspy.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/entertainment/rocketbeans.py b/user_scanner/user_scan/entertainment/rocketbeans.py new file mode 100644 index 00000000..f80380d0 --- /dev/null +++ b/user_scanner/user_scan/entertainment/rocketbeans.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_rocketbeans(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.rocketbeans.tv/u/{encoded_user}.json" + show_url = f"https://forum.rocketbeans.tv/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.rocketbeans.tv{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/entertainment/shotcut.py b/user_scanner/user_scan/entertainment/shotcut.py new file mode 100644 index 00000000..ea3a1677 --- /dev/null +++ b/user_scanner/user_scan/entertainment/shotcut.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_shotcut(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.shotcut.org/u/{encoded_user}.json" + show_url = f"https://forum.shotcut.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.shotcut.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/entertainment/sonarr.py b/user_scanner/user_scan/entertainment/sonarr.py new file mode 100644 index 00000000..ff8bcf5a --- /dev/null +++ b/user_scanner/user_scan/entertainment/sonarr.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_sonarr(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.sonarr.tv/u/{encoded_user}.json" + show_url = f"https://forums.sonarr.tv/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://forums.sonarr.tv{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/entertainment/trakt.py b/user_scanner/user_scan/entertainment/trakt.py new file mode 100644 index 00000000..5c59b0d3 --- /dev/null +++ b/user_scanner/user_scan/entertainment/trakt.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_trakt(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.trakt.tv/u/{encoded_user}.json" + show_url = f"https://forums.trakt.tv/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://forums.trakt.tv{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/entertainment/ttvchannel.py b/user_scanner/user_scan/entertainment/ttvchannel.py new file mode 100644 index 00000000..d5ee90d7 --- /dev/null +++ b/user_scanner/user_scan/entertainment/ttvchannel.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_ttvchannel(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://board.ttvchannel.com/u/{encoded_user}.json" + show_url = f"https://board.ttvchannel.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://board.ttvchannel.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/brevo.py b/user_scanner/user_scan/finance/brevo.py new file mode 100644 index 00000000..9a293070 --- /dev/null +++ b/user_scanner/user_scan/finance/brevo.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_brevo(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.brevo.com/u/{encoded_user}.json" + show_url = f"https://community.brevo.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://community.brevo.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/consultoria_sap.py b/user_scanner/user_scan/finance/consultoria_sap.py new file mode 100644 index 00000000..1d22bd16 --- /dev/null +++ b/user_scanner/user_scan/finance/consultoria_sap.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_consultoria_sap(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://foros.consultoria-sap.com/u/{encoded_user}.json" + show_url = f"https://foros.consultoria-sap.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://foros.consultoria-sap.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/deriv.py b/user_scanner/user_scan/finance/deriv.py new file mode 100644 index 00000000..9432349c --- /dev/null +++ b/user_scanner/user_scan/finance/deriv.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_deriv(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.deriv.com/u/{encoded_user}.json" + show_url = f"https://community.deriv.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://community.deriv.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/emma_app.py b/user_scanner/user_scan/finance/emma_app.py new file mode 100644 index 00000000..dbd10824 --- /dev/null +++ b/user_scanner/user_scan/finance/emma_app.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_emma_app(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.emma-app.com/u/{encoded_user}.json" + show_url = f"https://community.emma-app.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://community.emma-app.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/fireblocks.py b/user_scanner/user_scan/finance/fireblocks.py new file mode 100644 index 00000000..df3688f7 --- /dev/null +++ b/user_scanner/user_scan/finance/fireblocks.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_fireblocks(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.fireblocks.com/u/{encoded_user}.json" + show_url = f"https://community.fireblocks.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://community.fireblocks.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/invoiceninja.py b/user_scanner/user_scan/finance/invoiceninja.py new file mode 100644 index 00000000..7247d000 --- /dev/null +++ b/user_scanner/user_scan/finance/invoiceninja.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_invoiceninja(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.invoiceninja.com/u/{encoded_user}.json" + show_url = f"https://forum.invoiceninja.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.invoiceninja.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/jelurida.py b/user_scanner/user_scan/finance/jelurida.py new file mode 100644 index 00000000..d8bd12ac --- /dev/null +++ b/user_scanner/user_scan/finance/jelurida.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_jelurida(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://talk.jelurida.com/u/{encoded_user}.json" + show_url = f"https://talk.jelurida.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://talk.jelurida.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/jup.py b/user_scanner/user_scan/finance/jup.py new file mode 100644 index 00000000..91264fa3 --- /dev/null +++ b/user_scanner/user_scan/finance/jup.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_jup(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://discuss.jup.ag/u/{encoded_user}.json" + show_url = f"https://discuss.jup.ag/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://discuss.jup.ag{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/kitco.py b/user_scanner/user_scan/finance/kitco.py new file mode 100644 index 00000000..e944eb94 --- /dev/null +++ b/user_scanner/user_scan/finance/kitco.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_kitco(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.kitco.com/u/{encoded_user}.json" + show_url = f"https://forum.kitco.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.kitco.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/leasehackr.py b/user_scanner/user_scan/finance/leasehackr.py new file mode 100644 index 00000000..e916e3c4 --- /dev/null +++ b/user_scanner/user_scan/finance/leasehackr.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_leasehackr(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.leasehackr.com/u/{encoded_user}.json" + show_url = f"https://forum.leasehackr.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.leasehackr.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/mergado.py b/user_scanner/user_scan/finance/mergado.py new file mode 100644 index 00000000..8f041669 --- /dev/null +++ b/user_scanner/user_scan/finance/mergado.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_mergado(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mergado.cz/u/{encoded_user}.json" + show_url = f"https://forum.mergado.cz/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.mergado.cz{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/metamask.py b/user_scanner/user_scan/finance/metamask.py new file mode 100644 index 00000000..e0ec1daf --- /dev/null +++ b/user_scanner/user_scan/finance/metamask.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_metamask(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://builder.metamask.io/u/{encoded_user}.json" + show_url = f"https://builder.metamask.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://builder.metamask.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/peercoin.py b/user_scanner/user_scan/finance/peercoin.py new file mode 100644 index 00000000..1c8f8d25 --- /dev/null +++ b/user_scanner/user_scan/finance/peercoin.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_peercoin(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://talk.peercoin.net/u/{encoded_user}.json" + show_url = f"https://talk.peercoin.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://talk.peercoin.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) diff --git a/user_scanner/user_scan/finance/ramp.py b/user_scanner/user_scan/finance/ramp.py new file mode 100644 index 00000000..a70129a3 --- /dev/null +++ b/user_scanner/user_scan/finance/ramp.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_ramp(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.ramp.com/u/{encoded_user}.json" + show_url = f"https://community.ramp.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://community.ramp.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/tawk.py b/user_scanner/user_scan/finance/tawk.py new file mode 100644 index 00000000..772846e1 --- /dev/null +++ b/user_scanner/user_scan/finance/tawk.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_tawk(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.tawk.to/u/{encoded_user}.json" + show_url = f"https://community.tawk.to/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://community.tawk.to{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/toggl.py b/user_scanner/user_scan/finance/toggl.py new file mode 100644 index 00000000..7e7eaafb --- /dev/null +++ b/user_scanner/user_scan/finance/toggl.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_toggl(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.toggl.com/u/{encoded_user}.json" + show_url = f"https://community.toggl.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://community.toggl.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/vtex.py b/user_scanner/user_scan/finance/vtex.py new file mode 100644 index 00000000..f09885b9 --- /dev/null +++ b/user_scanner/user_scan/finance/vtex.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_vtex(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.vtex.com/u/{encoded_user}.json" + show_url = f"https://community.vtex.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://community.vtex.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/zcashcommunity.py b/user_scanner/user_scan/finance/zcashcommunity.py new file mode 100644 index 00000000..cb65d035 --- /dev/null +++ b/user_scanner/user_scan/finance/zcashcommunity.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_zcashcommunity(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.zcashcommunity.com/u/{encoded_user}.json" + show_url = f"https://forum.zcashcommunity.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.zcashcommunity.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/crateentertainment.py b/user_scanner/user_scan/gaming/crateentertainment.py new file mode 100644 index 00000000..17a002fc --- /dev/null +++ b/user_scanner/user_scan/gaming/crateentertainment.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_crateentertainment(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.crateentertainment.com/u/{encoded_user}.json" + show_url = f"https://forums.crateentertainment.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://forums.crateentertainment.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/duelistsunite.py b/user_scanner/user_scan/gaming/duelistsunite.py new file mode 100644 index 00000000..49d09f2c --- /dev/null +++ b/user_scanner/user_scan/gaming/duelistsunite.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_duelistsunite(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.duelistsunite.org/u/{encoded_user}.json" + show_url = f"https://forum.duelistsunite.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.duelistsunite.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/entropiauniverse.py b/user_scanner/user_scan/gaming/entropiauniverse.py new file mode 100644 index 00000000..25e66836 --- /dev/null +++ b/user_scanner/user_scan/gaming/entropiauniverse.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_entropiauniverse(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.entropiauniverse.com/u/{encoded_user}.json" + show_url = f"https://forum.entropiauniverse.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.entropiauniverse.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/gamernation.py b/user_scanner/user_scan/gaming/gamernation.py new file mode 100644 index 00000000..2494c28a --- /dev/null +++ b/user_scanner/user_scan/gaming/gamernation.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_gamernation(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://gamernation.org/u/{encoded_user}.json" + show_url = f"https://gamernation.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://gamernation.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/hitmanforum.py b/user_scanner/user_scan/gaming/hitmanforum.py new file mode 100644 index 00000000..1f927102 --- /dev/null +++ b/user_scanner/user_scan/gaming/hitmanforum.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_hitmanforum(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://www.hitmanforum.com/u/{encoded_user}.json" + show_url = f"https://www.hitmanforum.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://www.hitmanforum.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/insertcredit.py b/user_scanner/user_scan/gaming/insertcredit.py new file mode 100644 index 00000000..8bb37578 --- /dev/null +++ b/user_scanner/user_scan/gaming/insertcredit.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_insertcredit(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.insertcredit.com/u/{encoded_user}.json" + show_url = f"https://forums.insertcredit.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://forums.insertcredit.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/ishtar_collective.py b/user_scanner/user_scan/gaming/ishtar_collective.py new file mode 100644 index 00000000..566214fc --- /dev/null +++ b/user_scanner/user_scan/gaming/ishtar_collective.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_ishtar_collective(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://commons.ishtar-collective.net/u/{encoded_user}.json" + show_url = f"https://commons.ishtar-collective.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://commons.ishtar-collective.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) diff --git a/user_scanner/user_scan/gaming/kingdomcomerpg.py b/user_scanner/user_scan/gaming/kingdomcomerpg.py new file mode 100644 index 00000000..810904a6 --- /dev/null +++ b/user_scanner/user_scan/gaming/kingdomcomerpg.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_kingdomcomerpg(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.kingdomcomerpg.com/u/{encoded_user}.json" + show_url = f"https://forum.kingdomcomerpg.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.kingdomcomerpg.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/neverwintervault.py b/user_scanner/user_scan/gaming/neverwintervault.py new file mode 100644 index 00000000..c9c0f567 --- /dev/null +++ b/user_scanner/user_scan/gaming/neverwintervault.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_neverwintervault(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.neverwintervault.org/u/{encoded_user}.json" + show_url = f"https://forum.neverwintervault.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.neverwintervault.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/nianticspatial.py b/user_scanner/user_scan/gaming/nianticspatial.py new file mode 100644 index 00000000..c3f10825 --- /dev/null +++ b/user_scanner/user_scan/gaming/nianticspatial.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_nianticspatial(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.nianticspatial.com/u/{encoded_user}.json" + show_url = f"https://community.nianticspatial.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://community.nianticspatial.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/norestforthewicked.py b/user_scanner/user_scan/gaming/norestforthewicked.py new file mode 100644 index 00000000..0859ae46 --- /dev/null +++ b/user_scanner/user_scan/gaming/norestforthewicked.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_norestforthewicked(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.norestforthewicked.com/u/{encoded_user}.json" + show_url = f"https://forum.norestforthewicked.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.norestforthewicked.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/online_go.py b/user_scanner/user_scan/gaming/online_go.py new file mode 100644 index 00000000..022a4074 --- /dev/null +++ b/user_scanner/user_scan/gaming/online_go.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_online_go(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.online-go.com/u/{encoded_user}.json" + show_url = f"https://forums.online-go.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://forums.online-go.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/quartertothree.py b/user_scanner/user_scan/gaming/quartertothree.py new file mode 100644 index 00000000..76a959d1 --- /dev/null +++ b/user_scanner/user_scan/gaming/quartertothree.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_quartertothree(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.quartertothree.com/u/{encoded_user}.json" + show_url = f"https://forum.quartertothree.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.quartertothree.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/revolutionarygames.py b/user_scanner/user_scan/gaming/revolutionarygames.py new file mode 100644 index 00000000..8f516616 --- /dev/null +++ b/user_scanner/user_scan/gaming/revolutionarygames.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_revolutionarygames(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.revolutionarygamesstudio.com/u/{encoded_user}.json" + show_url = f"https://community.revolutionarygamesstudio.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://community.revolutionarygamesstudio.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/sourceruns.py b/user_scanner/user_scan/gaming/sourceruns.py new file mode 100644 index 00000000..c6b4cd64 --- /dev/null +++ b/user_scanner/user_scan/gaming/sourceruns.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_sourceruns(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.sourceruns.org/u/{encoded_user}.json" + show_url = f"https://forums.sourceruns.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://forums.sourceruns.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/stepsmash.py b/user_scanner/user_scan/gaming/stepsmash.py new file mode 100644 index 00000000..2e5e6e22 --- /dev/null +++ b/user_scanner/user_scan/gaming/stepsmash.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_stepsmash(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.stepsmash.com/u/{encoded_user}.json" + show_url = f"https://community.stepsmash.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://community.stepsmash.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/trictrac.py b/user_scanner/user_scan/gaming/trictrac.py new file mode 100644 index 00000000..6315c1f7 --- /dev/null +++ b/user_scanner/user_scan/gaming/trictrac.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_trictrac(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.trictrac.net/u/{encoded_user}.json" + show_url = f"https://forum.trictrac.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.trictrac.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) diff --git a/user_scanner/user_scan/gaming/warthunder.py b/user_scanner/user_scan/gaming/warthunder.py new file mode 100644 index 00000000..25c61413 --- /dev/null +++ b/user_scanner/user_scan/gaming/warthunder.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_warthunder(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.warthunder.ru/u/{encoded_user}.json" + show_url = f"https://forum.warthunder.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.warthunder.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/learning/crossref.py b/user_scanner/user_scan/learning/crossref.py new file mode 100644 index 00000000..0d0b9f51 --- /dev/null +++ b/user_scanner/user_scan/learning/crossref.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_crossref(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.crossref.org/u/{encoded_user}.json" + show_url = f"https://community.crossref.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://community.crossref.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/learning/etymonline.py b/user_scanner/user_scan/learning/etymonline.py new file mode 100644 index 00000000..e2ab4751 --- /dev/null +++ b/user_scanner/user_scan/learning/etymonline.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_etymonline(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.etymonline.com/u/{encoded_user}.json" + show_url = f"https://forum.etymonline.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.etymonline.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/learning/freemdict.py b/user_scanner/user_scan/learning/freemdict.py new file mode 100644 index 00000000..0d9f6d80 --- /dev/null +++ b/user_scanner/user_scan/learning/freemdict.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_freemdict(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.freemdict.com/u/{encoded_user}.json" + show_url = f"https://forum.freemdict.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.freemdict.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/learning/itvdn.py b/user_scanner/user_scan/learning/itvdn.py new file mode 100644 index 00000000..4fe40517 --- /dev/null +++ b/user_scanner/user_scan/learning/itvdn.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_itvdn(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.itvdn.com/u/{encoded_user}.json" + show_url = f"https://forum.itvdn.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.itvdn.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/learning/lang_learning_netflix.py b/user_scanner/user_scan/learning/lang_learning_netflix.py new file mode 100644 index 00000000..b8a2675f --- /dev/null +++ b/user_scanner/user_scan/learning/lang_learning_netflix.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_lang_learning_netflix(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.languagelearningwithnetflix.com/u/{encoded_user}.json" + show_url = f"https://forum.languagelearningwithnetflix.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.languagelearningwithnetflix.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/learning/languagetool.py b/user_scanner/user_scan/learning/languagetool.py new file mode 100644 index 00000000..be204f6c --- /dev/null +++ b/user_scanner/user_scan/learning/languagetool.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_languagetool(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.languagetool.org/u/{encoded_user}.json" + show_url = f"https://forum.languagetool.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.languagetool.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/learning/lsst.py b/user_scanner/user_scan/learning/lsst.py new file mode 100644 index 00000000..e9ea931c --- /dev/null +++ b/user_scanner/user_scan/learning/lsst.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_lsst(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.lsst.org/u/{encoded_user}.json" + show_url = f"https://community.lsst.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://community.lsst.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/learning/mmcs.py b/user_scanner/user_scan/learning/mmcs.py new file mode 100644 index 00000000..0d3e4b6e --- /dev/null +++ b/user_scanner/user_scan/learning/mmcs.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_mmcs(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.mmcs.sfedu.ru/u/{encoded_user}.json" + show_url = f"https://forum.mmcs.sfedu.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.mmcs.sfedu.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/learning/osvita.py b/user_scanner/user_scan/learning/osvita.py new file mode 100644 index 00000000..722a5c53 --- /dev/null +++ b/user_scanner/user_scan/learning/osvita.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_osvita(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.osvita.ua/u/{encoded_user}.json" + show_url = f"https://forum.osvita.ua/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.osvita.ua{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/p2pu.py b/user_scanner/user_scan/learning/p2pu.py new file mode 100644 index 00000000..2b93e2c2 --- /dev/null +++ b/user_scanner/user_scan/learning/p2pu.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_p2pu(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.p2pu.org/u/{encoded_user}.json" + show_url = f"https://community.p2pu.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://community.p2pu.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/learning/sorumatik.py b/user_scanner/user_scan/learning/sorumatik.py new file mode 100644 index 00000000..fd8c222b --- /dev/null +++ b/user_scanner/user_scan/learning/sorumatik.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_sorumatik(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://sorumatik.co/u/{encoded_user}.json" + show_url = f"https://sorumatik.co/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://sorumatik.co{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/uit.py b/user_scanner/user_scan/learning/uit.py new file mode 100644 index 00000000..ff33f74d --- /dev/null +++ b/user_scanner/user_scan/learning/uit.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_uit(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.uit.edu.vn/u/{encoded_user}.json" + show_url = f"https://forum.uit.edu.vn/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.uit.edu.vn{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/worldhistory.py b/user_scanner/user_scan/learning/worldhistory.py new file mode 100644 index 00000000..19b0121f --- /dev/null +++ b/user_scanner/user_scan/learning/worldhistory.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_worldhistory(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.worldhistory.org/u/{encoded_user}.json" + show_url = f"https://community.worldhistory.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://community.worldhistory.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/learning/zorin.py b/user_scanner/user_scan/learning/zorin.py new file mode 100644 index 00000000..54c7b046 --- /dev/null +++ b/user_scanner/user_scan/learning/zorin.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_zorin(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.zorin.com/u/{encoded_user}.json" + show_url = f"https://forum.zorin.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.zorin.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/bcharts.py b/user_scanner/user_scan/music/bcharts.py new file mode 100644 index 00000000..acca8e09 --- /dev/null +++ b/user_scanner/user_scan/music/bcharts.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_bcharts(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://bcharts.com.br/u/{encoded_user}.json" + show_url = f"https://bcharts.com.br/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://bcharts.com.br{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/dastereo.py b/user_scanner/user_scan/music/dastereo.py new file mode 100644 index 00000000..57f9abaf --- /dev/null +++ b/user_scanner/user_scan/music/dastereo.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_dastereo(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://dastereo.ru/u/{encoded_user}.json" + show_url = f"https://dastereo.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://dastereo.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/music/elektronauts.py b/user_scanner/user_scan/music/elektronauts.py new file mode 100644 index 00000000..cbe27cc6 --- /dev/null +++ b/user_scanner/user_scan/music/elektronauts.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_elektronauts(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://elektronauts.com/u/{encoded_user}.json" + show_url = f"https://elektronauts.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://elektronauts.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/futureaudioworkshop.py b/user_scanner/user_scan/music/futureaudioworkshop.py new file mode 100644 index 00000000..c1304cc8 --- /dev/null +++ b/user_scanner/user_scan/music/futureaudioworkshop.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_futureaudioworkshop(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.futureaudioworkshop.com/u/{encoded_user}.json" + show_url = f"https://community.futureaudioworkshop.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://community.futureaudioworkshop.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/moogmusic.py b/user_scanner/user_scan/music/moogmusic.py new file mode 100644 index 00000000..96d056e4 --- /dev/null +++ b/user_scanner/user_scan/music/moogmusic.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_moogmusic(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.moogmusic.com/u/{encoded_user}.json" + show_url = f"https://forum.moogmusic.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.moogmusic.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/rembetiko.py b/user_scanner/user_scan/music/rembetiko.py new file mode 100644 index 00000000..a59dbf30 --- /dev/null +++ b/user_scanner/user_scan/music/rembetiko.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_rembetiko(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://rembetiko.gr/u/{encoded_user}.json" + show_url = f"https://rembetiko.gr/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://rembetiko.gr{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/renoise.py b/user_scanner/user_scan/music/renoise.py new file mode 100644 index 00000000..26e87dc4 --- /dev/null +++ b/user_scanner/user_scan/music/renoise.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_renoise(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.renoise.com/u/{encoded_user}.json" + show_url = f"https://forum.renoise.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.renoise.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/steinberg.py b/user_scanner/user_scan/music/steinberg.py new file mode 100644 index 00000000..9b69a274 --- /dev/null +++ b/user_scanner/user_scan/music/steinberg.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_steinberg(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.steinberg.net/u/{encoded_user}.json" + show_url = f"https://forums.steinberg.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://forums.steinberg.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) diff --git a/user_scanner/user_scan/social/aztec.py b/user_scanner/user_scan/social/aztec.py new file mode 100644 index 00000000..dfad4785 --- /dev/null +++ b/user_scanner/user_scan/social/aztec.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_aztec(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.aztec.network/u/{encoded_user}.json" + show_url = f"https://forum.aztec.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.aztec.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/social/cosmos.py b/user_scanner/user_scan/social/cosmos.py new file mode 100644 index 00000000..5d6c669b --- /dev/null +++ b/user_scanner/user_scan/social/cosmos.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_cosmos(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.cosmos.network/u/{encoded_user}.json" + show_url = f"https://forum.cosmos.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.cosmos.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/social/dronehub.py b/user_scanner/user_scan/social/dronehub.py new file mode 100644 index 00000000..bb5d22cf --- /dev/null +++ b/user_scanner/user_scan/social/dronehub.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_dronehub(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://dronehub.co.uk/u/{encoded_user}.json" + show_url = f"https://dronehub.co.uk/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://dronehub.co.uk{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/eeclub.py b/user_scanner/user_scan/social/eeclub.py new file mode 100644 index 00000000..9210e9fc --- /dev/null +++ b/user_scanner/user_scan/social/eeclub.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_eeclub(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://bbs.eeclub.top/u/{encoded_user}.json" + show_url = f"https://bbs.eeclub.top/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://bbs.eeclub.top{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/joinmastodon.py b/user_scanner/user_scan/social/joinmastodon.py new file mode 100644 index 00000000..dd7dcdde --- /dev/null +++ b/user_scanner/user_scan/social/joinmastodon.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_joinmastodon(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.joinmastodon.org/u/{encoded_user}.json" + show_url = f"https://community.joinmastodon.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://community.joinmastodon.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/social/ministryoftesting.py b/user_scanner/user_scan/social/ministryoftesting.py new file mode 100644 index 00000000..0325a1db --- /dev/null +++ b/user_scanner/user_scan/social/ministryoftesting.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_ministryoftesting(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://club.ministryoftesting.com/u/{encoded_user}.json" + show_url = f"https://club.ministryoftesting.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://club.ministryoftesting.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/polkadot.py b/user_scanner/user_scan/social/polkadot.py new file mode 100644 index 00000000..5dbebec4 --- /dev/null +++ b/user_scanner/user_scan/social/polkadot.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_polkadot(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.polkadot.network/u/{encoded_user}.json" + show_url = f"https://forum.polkadot.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.polkadot.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/social/rocket_chat.py b/user_scanner/user_scan/social/rocket_chat.py new file mode 100644 index 00000000..79273085 --- /dev/null +++ b/user_scanner/user_scan/social/rocket_chat.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_rocket_chat(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forums.rocket.chat/u/{encoded_user}.json" + show_url = f"https://forums.rocket.chat/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://forums.rocket.chat{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/scrt.py b/user_scanner/user_scan/social/scrt.py new file mode 100644 index 00000000..7a728172 --- /dev/null +++ b/user_scanner/user_scan/social/scrt.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_scrt(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://forum.scrt.network/u/{encoded_user}.json" + show_url = f"https://forum.scrt.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.scrt.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/social/signalusers.py b/user_scanner/user_scan/social/signalusers.py new file mode 100644 index 00000000..10f63896 --- /dev/null +++ b/user_scanner/user_scan/social/signalusers.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_signalusers(user: str) -> Result: + encoded_user = urllib.parse.quote(user) + url = f"https://community.signalusers.org/u/{encoded_user}.json" + show_url = f"https://community.signalusers.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://community.signalusers.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)