-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
83 lines (77 loc) · 3.92 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// copy parameters like token from a fetch request in your network panel
const fetchPeopleIFollow = ({
token,
userId,
transactionId,
csrfToken,
path,
}) => {
const results = [];
const fetchNextPage = async (cursor) => {
console.log("fetchNextPage ...", cursor ? cursor : "");
const cursorVar = cursor ? `,"cursor":"${cursor}"` : "";
const variables = `{"userId":"${userId}","count":20,"includePromotedContent":false${cursorVar}}`;
const features =
'{"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false}';
const res = await fetch(
`https://twitter.com/i/api/graphql/${path}/Following?variables=${encodeURIComponent(
variables
)}&features=${encodeURIComponent(features)}`,
{
headers: {
accept: "*/*",
"accept-language": "de,en-US;q=0.9,en;q=0.8",
authorization: `Bearer ${token}`,
"content-type": "application/json",
"sec-ch-ua": '"Chromium";v="121", "Not A(Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-client-transaction-id": transactionId,
"x-csrf-token": csrfToken,
"x-twitter-active-user": "yes",
"x-twitter-auth-type": "OAuth2Session",
"x-twitter-client-language": "de",
},
referrer: "https://twitter.com",
referrerPolicy: "strict-origin-when-cross-origin",
body: null,
method: "GET",
mode: "cors",
credentials: "include",
}
);
const json = await res.json();
const entries = json.data.user.result.timeline.timeline.instructions.find(
(i) => i.type.includes("TimelineAddEntries")
).entries;
results.push(entries.slice(0, -2));
const bottomEntry = entries.find((e) =>
e.entryId?.includes("cursor-bottom-")
);
// find bottom cursor, if exists fetch with cursor until no cursor found
if (bottomEntry && entries.length > 2) {
fetchNextPage(bottomEntry.content.value);
} else {
const people = results.flat().map((r) => ({
name: r.content.itemContent.user_results.result.legacy.name,
screen_name:
r.content.itemContent.user_results.result.legacy.screen_name,
profile_banner_url:
r.content.itemContent.user_results.result.legacy.profile_banner_url,
followers_count:
r.content.itemContent.user_results.result.legacy.followers_count,
created_at: r.content.itemContent.user_results.result.legacy.created_at,
entities: r.content.itemContent.user_results.result.legacy.entities,
url: r.content.itemContent.user_results.result.legacy.url,
}));
console.log(
"Here are the results sorted by follower count: ",
people.sort((a, b) => b.followers_count - a.followers_count)
);
}
};
fetchNextPage();
};