emusks 0.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -277
- package/build/graphql.js +24 -0
- package/build/v1.1.js +28 -0
- package/build/v2.js +28 -0
- package/package.json +16 -8
- package/src/clients.js +62 -0
- package/src/cycletls.js +26 -0
- package/src/flow.js +399 -0
- package/src/graphql.js +70 -0
- package/src/helpers/account.js +271 -0
- package/src/helpers/bookmarks.js +120 -0
- package/src/helpers/communities.js +271 -0
- package/src/helpers/dms.js +131 -0
- package/src/helpers/index.js +32 -0
- package/src/helpers/lists.js +229 -0
- package/src/helpers/media.js +290 -0
- package/src/helpers/notifications.js +49 -0
- package/src/helpers/search.js +129 -0
- package/src/helpers/spaces.js +55 -0
- package/src/helpers/syndication.js +33 -0
- package/src/helpers/timelines.js +84 -0
- package/src/helpers/topics.js +99 -0
- package/src/helpers/trends.js +86 -0
- package/src/helpers/tweets.js +405 -0
- package/src/helpers/users.js +321 -0
- package/src/index.js +125 -55
- package/src/parsers/timeline.js +141 -0
- package/src/parsers/tweet.js +9 -2
- package/src/static/graphql.js +1 -0
- package/src/static/v1.1.js +1 -0
- package/src/static/v2.js +1 -0
- package/src/v1.1.js +64 -0
- package/src/v2.js +64 -0
- package/src/methods/bookmarks.js +0 -91
- package/src/methods/follow.js +0 -88
- package/src/methods/like.js +0 -87
- package/src/methods/notifications.js +0 -121
- package/src/methods/retweet.js +0 -91
- package/src/methods/search.js +0 -124
- package/src/methods/timeline.js +0 -215
- package/src/methods/tweet.js +0 -396
- package/src/methods/users.js +0 -209
- package/src/utils/headers.js +0 -23
package/src/methods/search.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import headers from "../utils/headers.js";
|
|
2
|
-
|
|
3
|
-
export async function search(query, { resultsCount, product, cursor } = {}) {
|
|
4
|
-
if (!this.auth.cookies) {
|
|
5
|
-
throw new Error("you must be logged in to search");
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const variables = {
|
|
9
|
-
rawQuery: query,
|
|
10
|
-
count: resultsCount || 20,
|
|
11
|
-
querySource: "advanced_search_page",
|
|
12
|
-
product: product || "Latest",
|
|
13
|
-
includePromotedContent: false,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
if (cursor) {
|
|
17
|
-
variables.cursor = cursor;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const out = await (
|
|
21
|
-
await fetch(
|
|
22
|
-
`https://pro.x.com/i/api/graphql/EP_W_cLzULmRd5E_X-PJkA/SearchTimeline?variables=${encodeURIComponent(
|
|
23
|
-
JSON.stringify(variables)
|
|
24
|
-
)}&features=${encodeURIComponent(
|
|
25
|
-
JSON.stringify({
|
|
26
|
-
rweb_video_screen_enabled: false,
|
|
27
|
-
payments_enabled: false,
|
|
28
|
-
profile_label_improvements_pcf_label_in_post_enabled: true,
|
|
29
|
-
rweb_tipjar_consumption_enabled: true,
|
|
30
|
-
verified_phone_label_enabled: false,
|
|
31
|
-
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
32
|
-
responsive_web_graphql_timeline_navigation_enabled: true,
|
|
33
|
-
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
34
|
-
premium_content_api_read_enabled: false,
|
|
35
|
-
communities_web_enable_tweet_community_results_fetch: true,
|
|
36
|
-
c9s_tweet_anatomy_moderator_badge_enabled: true,
|
|
37
|
-
responsive_web_grok_analyze_button_fetch_trends_enabled: false,
|
|
38
|
-
responsive_web_grok_analyze_post_followups_enabled: true,
|
|
39
|
-
responsive_web_jetfuel_frame: false,
|
|
40
|
-
responsive_web_grok_share_attachment_enabled: true,
|
|
41
|
-
articles_preview_enabled: true,
|
|
42
|
-
responsive_web_edit_tweet_api_enabled: true,
|
|
43
|
-
graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
|
|
44
|
-
view_counts_everywhere_api_enabled: true,
|
|
45
|
-
longform_notetweets_consumption_enabled: true,
|
|
46
|
-
responsive_web_twitter_article_tweet_consumption_enabled: true,
|
|
47
|
-
tweet_awards_web_tipping_enabled: false,
|
|
48
|
-
responsive_web_grok_show_grok_translated_post: false,
|
|
49
|
-
responsive_web_grok_analysis_button_from_backend: false,
|
|
50
|
-
creator_subscriptions_quote_tweet_preview_enabled: false,
|
|
51
|
-
freedom_of_speech_not_reach_fetch_enabled: true,
|
|
52
|
-
standardized_nudges_misinfo: true,
|
|
53
|
-
tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
|
|
54
|
-
longform_notetweets_rich_text_read_enabled: true,
|
|
55
|
-
longform_notetweets_inline_media_enabled: true,
|
|
56
|
-
responsive_web_grok_image_annotation_enabled: true,
|
|
57
|
-
responsive_web_enhance_cards_enabled: false,
|
|
58
|
-
})
|
|
59
|
-
)}`,
|
|
60
|
-
{
|
|
61
|
-
headers: {
|
|
62
|
-
Accept: "*/*",
|
|
63
|
-
"accept-language": "en-US,en;q=0.9",
|
|
64
|
-
|
|
65
|
-
authorization:
|
|
66
|
-
"Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
|
|
67
|
-
|
|
68
|
-
"content-type": "application/json",
|
|
69
|
-
|
|
70
|
-
"x-client-transaction-id": Math.random().toString().replace("0.", ""),
|
|
71
|
-
"x-csrf-token": this.auth.csrfToken,
|
|
72
|
-
|
|
73
|
-
"x-twitter-active-user": "yes",
|
|
74
|
-
"x-twitter-auth-type": "OAuth2Session",
|
|
75
|
-
"x-twitter-client-language": "en",
|
|
76
|
-
|
|
77
|
-
cookie: this.auth.cookies,
|
|
78
|
-
...headers,
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
).json();
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
!out?.data?.search_by_raw_query?.search_timeline?.timeline?.instructions
|
|
86
|
-
) {
|
|
87
|
-
throw new Error(`failed to search: ${JSON.stringify(out, null, 2)}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const instructions =
|
|
91
|
-
out.data.search_by_raw_query.search_timeline.timeline.instructions;
|
|
92
|
-
|
|
93
|
-
// Find the TimelineAddEntries instruction
|
|
94
|
-
const addEntriesInstruction = instructions.find(
|
|
95
|
-
(instruction) => instruction.type === "TimelineAddEntries"
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
if (!addEntriesInstruction) {
|
|
99
|
-
throw new Error("failed to find timeline entries in search response");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const entries = addEntriesInstruction.entries;
|
|
103
|
-
|
|
104
|
-
// Extract cursors for pagination
|
|
105
|
-
const cursors = {
|
|
106
|
-
top: null,
|
|
107
|
-
bottom: null,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
entries.forEach((entry) => {
|
|
111
|
-
if (entry.entryId && entry.entryId.startsWith("cursor-")) {
|
|
112
|
-
if (entry.entryId.includes("top")) {
|
|
113
|
-
cursors.top = entry.content?.value;
|
|
114
|
-
} else if (entry.entryId.includes("bottom")) {
|
|
115
|
-
cursors.bottom = entry.content?.value;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
entries: entries.filter((entry) => !entry.entryId.startsWith("cursor-")),
|
|
122
|
-
cursors,
|
|
123
|
-
};
|
|
124
|
-
}
|
package/src/methods/timeline.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import headers from "../utils/headers.js";
|
|
2
|
-
import parseTweet from "../parsers/tweet.js";
|
|
3
|
-
|
|
4
|
-
export async function getTimeline({
|
|
5
|
-
count = 20,
|
|
6
|
-
cursor = undefined,
|
|
7
|
-
includeAds = false,
|
|
8
|
-
seenTweetIds = [],
|
|
9
|
-
type = "foryou",
|
|
10
|
-
} = {}) {
|
|
11
|
-
if (!this.auth.cookies) {
|
|
12
|
-
throw new Error("you must be logged in to get timeline");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!["foryou", "following"].includes(type)) {
|
|
16
|
-
throw new Error("type must be either 'foryou' or 'following'");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const isFollowing = type === "following";
|
|
20
|
-
const endpoint = isFollowing
|
|
21
|
-
? "https://pro.x.com/i/api/graphql/ewrSxRr-SMI1kW9gzg7JPg/HomeLatestTimeline"
|
|
22
|
-
: "https://pro.x.com/i/api/graphql/Ri47TC1RogqkfaInTxucqA/HomeTimeline";
|
|
23
|
-
|
|
24
|
-
const queryId = isFollowing
|
|
25
|
-
? "ewrSxRr-SMI1kW9gzg7JPg"
|
|
26
|
-
: "Ri47TC1RogqkfaInTxucqA";
|
|
27
|
-
|
|
28
|
-
const variables = {
|
|
29
|
-
count,
|
|
30
|
-
includePromotedContent: includeAds,
|
|
31
|
-
latestControlAvailable: true,
|
|
32
|
-
seenTweetIds,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (isFollowing) {
|
|
36
|
-
variables.requestContext = "launch";
|
|
37
|
-
} else {
|
|
38
|
-
variables.cursor = cursor;
|
|
39
|
-
variables.withCommunity = true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const features = {
|
|
43
|
-
rweb_video_screen_enabled: false,
|
|
44
|
-
payments_enabled: false,
|
|
45
|
-
profile_label_improvements_pcf_label_in_post_enabled: true,
|
|
46
|
-
rweb_tipjar_consumption_enabled: true,
|
|
47
|
-
verified_phone_label_enabled: false,
|
|
48
|
-
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
49
|
-
responsive_web_graphql_timeline_navigation_enabled: true,
|
|
50
|
-
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
51
|
-
premium_content_api_read_enabled: false,
|
|
52
|
-
communities_web_enable_tweet_community_results_fetch: true,
|
|
53
|
-
c9s_tweet_anatomy_moderator_badge_enabled: true,
|
|
54
|
-
responsive_web_grok_analyze_button_fetch_trends_enabled: false,
|
|
55
|
-
responsive_web_grok_analyze_post_followups_enabled: true,
|
|
56
|
-
responsive_web_jetfuel_frame: false,
|
|
57
|
-
responsive_web_grok_share_attachment_enabled: true,
|
|
58
|
-
articles_preview_enabled: true,
|
|
59
|
-
responsive_web_edit_tweet_api_enabled: true,
|
|
60
|
-
graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
|
|
61
|
-
view_counts_everywhere_api_enabled: true,
|
|
62
|
-
longform_notetweets_consumption_enabled: true,
|
|
63
|
-
responsive_web_twitter_article_tweet_consumption_enabled: true,
|
|
64
|
-
tweet_awards_web_tipping_enabled: false,
|
|
65
|
-
responsive_web_grok_show_grok_translated_post: isFollowing ? false : true,
|
|
66
|
-
responsive_web_grok_analysis_button_from_backend: isFollowing
|
|
67
|
-
? false
|
|
68
|
-
: true,
|
|
69
|
-
creator_subscriptions_quote_tweet_preview_enabled: false,
|
|
70
|
-
freedom_of_speech_not_reach_fetch_enabled: true,
|
|
71
|
-
standardized_nudges_misinfo: true,
|
|
72
|
-
tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
|
|
73
|
-
longform_notetweets_rich_text_read_enabled: true,
|
|
74
|
-
longform_notetweets_inline_media_enabled: true,
|
|
75
|
-
responsive_web_grok_image_annotation_enabled: true,
|
|
76
|
-
responsive_web_enhance_cards_enabled: false,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
const response = await fetch(endpoint, {
|
|
81
|
-
headers: {
|
|
82
|
-
accept: "*/*",
|
|
83
|
-
"accept-language": "en-US,en;q=0.9",
|
|
84
|
-
authorization:
|
|
85
|
-
"Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
|
|
86
|
-
"content-type": "application/json",
|
|
87
|
-
"x-client-transaction-id": Math.random().toString().replace("0.", ""),
|
|
88
|
-
"x-csrf-token": this.auth.csrfToken,
|
|
89
|
-
"x-twitter-active-user": "yes",
|
|
90
|
-
"x-twitter-auth-type": "OAuth2Session",
|
|
91
|
-
"x-twitter-client-language": "en",
|
|
92
|
-
cookie: this.auth.cookies,
|
|
93
|
-
...headers,
|
|
94
|
-
},
|
|
95
|
-
body: JSON.stringify({
|
|
96
|
-
variables,
|
|
97
|
-
features,
|
|
98
|
-
queryId,
|
|
99
|
-
}),
|
|
100
|
-
method: "POST",
|
|
101
|
-
mode: "cors",
|
|
102
|
-
credentials: "include",
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
throw new Error(
|
|
107
|
-
`Timeline request failed: ${response.status} ${response.statusText}`
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const data = await response.json();
|
|
112
|
-
return parseTimelineResponse(data);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
throw new Error(`Failed to fetch timeline: ${error.message}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function parseTimelineResponse(data) {
|
|
119
|
-
const result = {
|
|
120
|
-
timeline: [],
|
|
121
|
-
cursors: {
|
|
122
|
-
top: null,
|
|
123
|
-
bottom: null,
|
|
124
|
-
},
|
|
125
|
-
metadata: {
|
|
126
|
-
scribeConfig: null,
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const instructions =
|
|
132
|
-
data?.data?.home?.home_timeline_urt?.instructions || [];
|
|
133
|
-
|
|
134
|
-
const addEntriesInstruction = instructions.find(
|
|
135
|
-
(instruction) => instruction.type === "TimelineAddEntries"
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
if (addEntriesInstruction?.metadata?.scribeConfig) {
|
|
139
|
-
result.metadata.scribeConfig =
|
|
140
|
-
addEntriesInstruction.metadata.scribeConfig;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const entries = addEntriesInstruction?.entries || [];
|
|
144
|
-
|
|
145
|
-
for (const entry of entries) {
|
|
146
|
-
const { entryId, content } = entry;
|
|
147
|
-
|
|
148
|
-
if (entryId.startsWith("tweet-")) {
|
|
149
|
-
const tweetData = content?.itemContent?.tweet_results?.result;
|
|
150
|
-
if (tweetData && tweetData.__typename === "Tweet") {
|
|
151
|
-
const parsedTweet = parseTweet(tweetData);
|
|
152
|
-
if (parsedTweet) {
|
|
153
|
-
result.timeline.push({
|
|
154
|
-
type: "tweet",
|
|
155
|
-
data: parsedTweet,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
} else if (entryId.startsWith("home-conversation-")) {
|
|
160
|
-
const conversationData = content?.items || [];
|
|
161
|
-
const conversation = {
|
|
162
|
-
id: entryId.replace("home-conversation-", ""),
|
|
163
|
-
tweets: [],
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
for (const item of conversationData) {
|
|
167
|
-
const tweetData = item?.item?.itemContent?.tweet_results?.result;
|
|
168
|
-
if (tweetData && tweetData.__typename === "Tweet") {
|
|
169
|
-
const parsedTweet = parseTweet(tweetData);
|
|
170
|
-
if (parsedTweet) {
|
|
171
|
-
conversation.tweets.push(parsedTweet);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (conversation.tweets.length > 0) {
|
|
177
|
-
result.timeline.push({
|
|
178
|
-
type: "conversation",
|
|
179
|
-
data: conversation,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
} else if (entryId.startsWith("who-to-follow-")) {
|
|
183
|
-
const userItems = content?.items || [];
|
|
184
|
-
const users = [];
|
|
185
|
-
for (const item of userItems) {
|
|
186
|
-
const userData = item?.item?.itemContent?.user_results?.result;
|
|
187
|
-
if (userData && userData.__typename === "User") {
|
|
188
|
-
users.push(userData);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (users.length > 0) {
|
|
193
|
-
result.timeline.push({
|
|
194
|
-
type: "suggested_users",
|
|
195
|
-
data: {
|
|
196
|
-
id: entryId.replace("who-to-follow-", ""),
|
|
197
|
-
users: users,
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
} else if (entryId.startsWith("cursor-")) {
|
|
202
|
-
const cursorValue = content?.value;
|
|
203
|
-
if (entryId.includes("top")) {
|
|
204
|
-
result.cursors.top = cursorValue;
|
|
205
|
-
} else if (entryId.includes("bottom")) {
|
|
206
|
-
result.cursors.bottom = cursorValue;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return result;
|
|
212
|
-
} catch (error) {
|
|
213
|
-
throw new Error(`Failed to parse timeline response: ${error.message}`);
|
|
214
|
-
}
|
|
215
|
-
}
|