Skip to content

Commit 5faa92e

Browse files
authored
feat(user_scan): add Indiegogo username modules (#628)
- Add profile and creator availability checks - Extract account metadata, social links, and images
1 parent 261222f commit 5faa92e

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import json
2+
from urllib.parse import quote
3+
4+
from user_scanner.core.orchestrator import Result, generic_validate
5+
6+
7+
def validate_indiegogo(user: str) -> Result:
8+
url = f"https://www.indiegogo.com/en/profile/{quote(user, safe='')}"
9+
10+
def process(response):
11+
body = response.text
12+
if response.status_code == 404 and "<title>404: Page Not Found - Indiegogo</title>" in body:
13+
return Result.available()
14+
15+
if response.status_code != 200:
16+
return Result.error(f"Unexpected status: {response.status_code}")
17+
18+
props = _props(body)
19+
if not props or str(props.get("userUrlName", "")).casefold() != user.casefold():
20+
return Result.error("200 without the matching Indiegogo account data")
21+
22+
extra = {"id": props.get("userID"), "name": props.get("nickname")}
23+
for key, value in (props.get("navigationCounters") or {}).items():
24+
extra[key.removesuffix("Count")] = value
25+
26+
return Result.taken(extra=extra, media={"avatar": props.get("avatarUrl")})
27+
28+
return generic_validate(url, process, show_url=url)
29+
30+
31+
def _props(body: str) -> dict | None:
32+
marker = "'App.Views.UserProfileView', App.Views.UserProfileView, "
33+
start = body.find(marker)
34+
if start == -1:
35+
return None
36+
37+
start = body.find('{"props":', start)
38+
end = body.find(");</script>", start)
39+
if start == -1 or end == -1:
40+
return None
41+
42+
props = json.loads(body[start:end]).get("props")
43+
return props if isinstance(props, dict) else None
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import json
2+
from urllib.parse import quote
3+
4+
from user_scanner.core.orchestrator import Result, generic_validate
5+
6+
_SOCIAL_FIELDS = {
7+
0: "facebook",
8+
1: "twitter",
9+
2: "youtube",
10+
3: "instagram",
11+
4: "social_website",
12+
}
13+
14+
15+
def validate_indiegogo_creator(user: str) -> Result:
16+
url = f"https://www.indiegogo.com/en/creators/{quote(user, safe='')}"
17+
18+
def process(response):
19+
body = response.text
20+
if response.status_code == 404 and "<title>404: Page Not Found - Indiegogo</title>" in body:
21+
return Result.available()
22+
23+
if response.status_code != 200:
24+
return Result.error(f"Unexpected status: {response.status_code}")
25+
26+
props = _props(body)
27+
if not props or str(props.get("urlName", "")).casefold() != user.casefold():
28+
return Result.error("200 without the matching Indiegogo account data")
29+
30+
extra = {
31+
"id": props.get("creatorID"),
32+
"name": props.get("name"),
33+
"bio": props.get("description"),
34+
"location": props.get("displayedLocation"),
35+
"website": props.get("websiteUrl"),
36+
}
37+
for social in props.get("socialMediaUrls") or []:
38+
if isinstance(social, dict) and (field := _SOCIAL_FIELDS.get(social.get("type"))):
39+
extra[field] = social.get("url")
40+
41+
media = {"avatar": props.get("creatorImageUrl")}
42+
if props.get("bannerImages"):
43+
media["banner"] = props["bannerImages"][0]
44+
return Result.taken(extra=extra, media=media)
45+
46+
return generic_validate(url, process, show_url=url)
47+
48+
49+
def _props(body: str) -> dict | None:
50+
marker = "'App.Views.CreatorView', App.Views.CreatorView, "
51+
start = body.find(marker)
52+
if start == -1:
53+
return None
54+
55+
start = body.find('{"props":', start)
56+
end = body.find(");</script>", start)
57+
if start == -1 or end == -1:
58+
return None
59+
60+
props = json.loads(body[start:end]).get("props")
61+
return props if isinstance(props, dict) else None

0 commit comments

Comments
 (0)