@the-convocation/twitter-scraper 0.17.2 → 0.18.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/dist/default/cjs/index.js +208 -10
- package/dist/default/cjs/index.js.map +1 -1
- package/dist/default/esm/index.mjs +208 -10
- package/dist/default/esm/index.mjs.map +1 -1
- package/dist/node/cjs/index.cjs +208 -10
- package/dist/node/cjs/index.cjs.map +1 -1
- package/dist/node/esm/index.mjs +208 -10
- package/dist/node/esm/index.mjs.map +1 -1
- package/dist/types/index.d.ts +185 -1
- package/package.json +1 -1
|
@@ -791,13 +791,16 @@ class ApiRequest {
|
|
|
791
791
|
toRequestUrl() {
|
|
792
792
|
const params = new URLSearchParams();
|
|
793
793
|
if (this.variables) {
|
|
794
|
-
|
|
794
|
+
const variablesStr = stringify(this.variables);
|
|
795
|
+
if (variablesStr) params.set("variables", variablesStr);
|
|
795
796
|
}
|
|
796
797
|
if (this.features) {
|
|
797
|
-
|
|
798
|
+
const featuresStr = stringify(this.features);
|
|
799
|
+
if (featuresStr) params.set("features", featuresStr);
|
|
798
800
|
}
|
|
799
801
|
if (this.fieldToggles) {
|
|
800
|
-
|
|
802
|
+
const fieldTogglesStr = stringify(this.fieldToggles);
|
|
803
|
+
if (fieldTogglesStr) params.set("fieldToggles", fieldTogglesStr);
|
|
801
804
|
}
|
|
802
805
|
return `${this.url}?${params.toString()}`;
|
|
803
806
|
}
|
|
@@ -1523,9 +1526,12 @@ async function getSearchTimeline(query, maxItems, searchMode, auth, cursor) {
|
|
|
1523
1526
|
break;
|
|
1524
1527
|
}
|
|
1525
1528
|
const params = new URLSearchParams();
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
+
const featuresStr = stringify(features);
|
|
1530
|
+
const fieldTogglesStr = stringify(fieldToggles);
|
|
1531
|
+
const variablesStr = stringify(variables);
|
|
1532
|
+
if (featuresStr) params.set("features", featuresStr);
|
|
1533
|
+
if (fieldTogglesStr) params.set("fieldToggles", fieldTogglesStr);
|
|
1534
|
+
if (variablesStr) params.set("variables", variablesStr);
|
|
1529
1535
|
const res = await requestApi(
|
|
1530
1536
|
`https://api.x.com/graphql/gkjsKepM6gl_HmFWoWKfgg/SearchTimeline?${params.toString()}`,
|
|
1531
1537
|
auth
|
|
@@ -1639,8 +1645,10 @@ async function getFollowingTimeline(userId, maxItems, auth, cursor) {
|
|
|
1639
1645
|
variables["cursor"] = cursor;
|
|
1640
1646
|
}
|
|
1641
1647
|
const params = new URLSearchParams();
|
|
1642
|
-
|
|
1643
|
-
|
|
1648
|
+
const featuresStr = stringify(features);
|
|
1649
|
+
const variablesStr = stringify(variables);
|
|
1650
|
+
if (featuresStr) params.set("features", featuresStr);
|
|
1651
|
+
if (variablesStr) params.set("variables", variablesStr);
|
|
1644
1652
|
const res = await requestApi(
|
|
1645
1653
|
`https://x.com/i/api/graphql/iSicc7LrzWGBgDPL0tM_TQ/Following?${params.toString()}`,
|
|
1646
1654
|
auth
|
|
@@ -1674,8 +1682,10 @@ async function getFollowersTimeline(userId, maxItems, auth, cursor) {
|
|
|
1674
1682
|
variables["cursor"] = cursor;
|
|
1675
1683
|
}
|
|
1676
1684
|
const params = new URLSearchParams();
|
|
1677
|
-
|
|
1678
|
-
|
|
1685
|
+
const featuresStr = stringify(features);
|
|
1686
|
+
const variablesStr = stringify(variables);
|
|
1687
|
+
if (featuresStr) params.set("features", featuresStr);
|
|
1688
|
+
if (variablesStr) params.set("variables", variablesStr);
|
|
1679
1689
|
const res = await requestApi(
|
|
1680
1690
|
`https://x.com/i/api/graphql/rRXFSG5vR6drKr5M37YOTw/Followers?${params.toString()}`,
|
|
1681
1691
|
auth
|
|
@@ -1951,6 +1961,155 @@ async function getTweetAnonymous(id, auth) {
|
|
|
1951
1961
|
return parseTimelineEntryItemContentRaw(res.value.data, id);
|
|
1952
1962
|
}
|
|
1953
1963
|
|
|
1964
|
+
async function* getDmConversationMessagesGenerator(conversationId, maxMessages, initialCursor, fetchFunc) {
|
|
1965
|
+
let nMessages = 0;
|
|
1966
|
+
let cursor = initialCursor;
|
|
1967
|
+
while (nMessages < maxMessages) {
|
|
1968
|
+
const batch = await fetchFunc(
|
|
1969
|
+
conversationId,
|
|
1970
|
+
maxMessages,
|
|
1971
|
+
cursor
|
|
1972
|
+
);
|
|
1973
|
+
const { conversation, next } = batch;
|
|
1974
|
+
if (!conversation?.entries || conversation?.entries?.length === 0) {
|
|
1975
|
+
break;
|
|
1976
|
+
}
|
|
1977
|
+
for (const entry of conversation.entries) {
|
|
1978
|
+
if (nMessages < maxMessages) {
|
|
1979
|
+
yield entry;
|
|
1980
|
+
nMessages++;
|
|
1981
|
+
} else {
|
|
1982
|
+
break;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
cursor = next;
|
|
1986
|
+
if (conversation.status === "AT_END" || !next) {
|
|
1987
|
+
break;
|
|
1988
|
+
}
|
|
1989
|
+
await jitter(1e3);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
async function fetchDmInbox(auth) {
|
|
1994
|
+
if (!await auth.isLoggedIn()) {
|
|
1995
|
+
throw new AuthenticationError(
|
|
1996
|
+
"Scraper is not logged-in for fetching direct messages."
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
const params = new URLSearchParams();
|
|
2000
|
+
addApiParams(params, false);
|
|
2001
|
+
params.set("nsfw_filtering_enabled", "false");
|
|
2002
|
+
params.set("filter_low_quality", "true");
|
|
2003
|
+
params.set("include_quality", "all");
|
|
2004
|
+
params.set("include_ext_profile_image_shape", "1");
|
|
2005
|
+
params.set("dm_secret_conversations_enabled", "false");
|
|
2006
|
+
params.set("krs_registration_enabled", "false");
|
|
2007
|
+
params.set("include_ext_limited_action_results", "true");
|
|
2008
|
+
params.set("dm_users", "true");
|
|
2009
|
+
params.set("include_groups", "true");
|
|
2010
|
+
params.set("include_inbox_timelines", "true");
|
|
2011
|
+
params.set("supports_reactions", "true");
|
|
2012
|
+
params.set("supports_edit", "true");
|
|
2013
|
+
params.set("include_ext_edit_control", "true");
|
|
2014
|
+
params.set("include_ext_business_affiliations_label", "true");
|
|
2015
|
+
params.set("include_ext_parody_commentary_fan_label", "true");
|
|
2016
|
+
params.set(
|
|
2017
|
+
"ext",
|
|
2018
|
+
"mediaColor,altText,mediaStats,highlightedLabel,parodyCommentaryFanLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article"
|
|
2019
|
+
);
|
|
2020
|
+
const res = await requestApi(
|
|
2021
|
+
`https://x.com/i/api/1.1/dm/inbox_initial_state.json?${params.toString()}`,
|
|
2022
|
+
auth
|
|
2023
|
+
);
|
|
2024
|
+
if (!res.success) {
|
|
2025
|
+
throw res.err;
|
|
2026
|
+
}
|
|
2027
|
+
return parseDmInbox(res.value);
|
|
2028
|
+
}
|
|
2029
|
+
async function parseDmInbox(inbox) {
|
|
2030
|
+
return inbox.inbox_initial_state;
|
|
2031
|
+
}
|
|
2032
|
+
async function getDmInbox(auth) {
|
|
2033
|
+
return await fetchDmInbox(auth);
|
|
2034
|
+
}
|
|
2035
|
+
async function fetchDmConversation(conversationId, cursor, auth) {
|
|
2036
|
+
if (!await auth.isLoggedIn()) {
|
|
2037
|
+
throw new AuthenticationError(
|
|
2038
|
+
"Scraper is not logged-in for fetching direct messages."
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
const params = new URLSearchParams();
|
|
2042
|
+
addApiParams(params, false);
|
|
2043
|
+
params.set("context", "FETCH_DM_CONVERSATION_HISTORY");
|
|
2044
|
+
params.set("include_ext_profile_image_shape", "1");
|
|
2045
|
+
params.set("dm_secret_conversations_enabled", "false");
|
|
2046
|
+
params.set("krs_registration_enabled", "false");
|
|
2047
|
+
params.set("include_ext_limited_action_results", "true");
|
|
2048
|
+
params.set("dm_users", "true");
|
|
2049
|
+
params.set("include_groups", "true");
|
|
2050
|
+
params.set("include_inbox_timelines", "true");
|
|
2051
|
+
params.set("supports_reactions", "true");
|
|
2052
|
+
params.set("supports_edit", "true");
|
|
2053
|
+
params.set("include_conversation_info", "true");
|
|
2054
|
+
params.set(
|
|
2055
|
+
"ext",
|
|
2056
|
+
"mediaColor,altText,mediaStats,highlightedLabel,parodyCommentaryFanLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article"
|
|
2057
|
+
);
|
|
2058
|
+
if (cursor) {
|
|
2059
|
+
if (cursor.maxId) {
|
|
2060
|
+
params.set("max_id", cursor.maxId);
|
|
2061
|
+
}
|
|
2062
|
+
if (cursor.minId) {
|
|
2063
|
+
params.set("min_id", cursor.minId);
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
const url = `https://x.com/i/api/1.1/dm/conversation/${conversationId}.json?${params.toString()}`;
|
|
2067
|
+
const res = await requestApi(url, auth);
|
|
2068
|
+
if (!res.success) {
|
|
2069
|
+
throw res.err;
|
|
2070
|
+
}
|
|
2071
|
+
return parseDmConversation(res.value);
|
|
2072
|
+
}
|
|
2073
|
+
async function parseDmConversation(conversation) {
|
|
2074
|
+
return conversation.conversation_timeline;
|
|
2075
|
+
}
|
|
2076
|
+
async function getDmConversation(conversationId, cursor, auth) {
|
|
2077
|
+
return await fetchDmConversation(conversationId, cursor, auth);
|
|
2078
|
+
}
|
|
2079
|
+
function getDmMessages(conversationId, maxMessages, cursor, auth) {
|
|
2080
|
+
return getDmConversationMessagesGenerator(
|
|
2081
|
+
conversationId,
|
|
2082
|
+
maxMessages,
|
|
2083
|
+
cursor,
|
|
2084
|
+
async (id, _max, cursor2) => {
|
|
2085
|
+
const conversation = await fetchDmConversation(id, cursor2, auth);
|
|
2086
|
+
let next = void 0;
|
|
2087
|
+
if (cursor2?.minId && conversation.max_entry_id) {
|
|
2088
|
+
next = { minId: conversation.max_entry_id };
|
|
2089
|
+
} else if (conversation.min_entry_id) {
|
|
2090
|
+
next = { maxId: conversation.min_entry_id };
|
|
2091
|
+
}
|
|
2092
|
+
return {
|
|
2093
|
+
conversation,
|
|
2094
|
+
next
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
function findDmConversationsByUserId(inbox, userId) {
|
|
2100
|
+
const conversations = [];
|
|
2101
|
+
for (const conversationId in inbox.conversations) {
|
|
2102
|
+
const conversation = inbox.conversations[conversationId];
|
|
2103
|
+
const hasUser = conversation.participants.some(
|
|
2104
|
+
(participant) => participant.user_id === userId
|
|
2105
|
+
);
|
|
2106
|
+
if (hasUser) {
|
|
2107
|
+
conversations.push(conversation);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
return conversations;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
1954
2113
|
const twUrl = "https://x.com";
|
|
1955
2114
|
class Scraper {
|
|
1956
2115
|
/**
|
|
@@ -2215,6 +2374,45 @@ class Scraper {
|
|
|
2215
2374
|
return getTweetAnonymous(id, this.auth);
|
|
2216
2375
|
}
|
|
2217
2376
|
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Retrieves the direct message inbox for the authenticated user.
|
|
2379
|
+
*
|
|
2380
|
+
* @return A promise that resolves to an object representing the direct message inbox.
|
|
2381
|
+
*/
|
|
2382
|
+
getDmInbox() {
|
|
2383
|
+
return getDmInbox(this.auth);
|
|
2384
|
+
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Retrieves the direct message conversation for the specified conversation ID.
|
|
2387
|
+
*
|
|
2388
|
+
* @param conversationId - The unique identifier of the DM conversation to retrieve.
|
|
2389
|
+
* @param cursor - Use `maxId` to get messages before a message ID (older messages), or `minId` to get messages after a message ID (newer messages).
|
|
2390
|
+
* @return A promise that resolves to the timeline of the DM conversation.
|
|
2391
|
+
*/
|
|
2392
|
+
getDmConversation(conversationId, cursor) {
|
|
2393
|
+
return getDmConversation(conversationId, cursor, this.auth);
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* Retrieves direct messages from a specific conversation.
|
|
2397
|
+
*
|
|
2398
|
+
* @param conversationId - The unique identifier of the conversation to fetch messages from.
|
|
2399
|
+
* @param [maxMessages=20] - The maximum number of messages to retrieve per request.
|
|
2400
|
+
* @param cursor - Use `maxId` to get messages before a message ID (older messages), or `minId` to get messages after a message ID (newer messages).
|
|
2401
|
+
* @returns An {@link AsyncGenerator} of messages from the provided conversation.
|
|
2402
|
+
*/
|
|
2403
|
+
getDmMessages(conversationId, maxMessages = 20, cursor) {
|
|
2404
|
+
return getDmMessages(conversationId, maxMessages, cursor, this.auth);
|
|
2405
|
+
}
|
|
2406
|
+
/**
|
|
2407
|
+
* Retrieves a list of direct message conversations for a specific user based on their user ID.
|
|
2408
|
+
*
|
|
2409
|
+
* @param inbox - The DM inbox containing all available conversations.
|
|
2410
|
+
* @param userId - The unique identifier of the user whose DM conversations are to be retrieved.
|
|
2411
|
+
* @return An array of DM conversations associated with the specified user ID.
|
|
2412
|
+
*/
|
|
2413
|
+
findDmConversationsByUserId(inbox, userId) {
|
|
2414
|
+
return findDmConversationsByUserId(inbox, userId);
|
|
2415
|
+
}
|
|
2218
2416
|
/**
|
|
2219
2417
|
* Returns if the scraper has a guest token. The token may not be valid.
|
|
2220
2418
|
* @returns `true` if the scraper has a guest token; otherwise `false`.
|