Skip to content
This repository was archived by the owner on Feb 21, 2025. It is now read-only.

Commit 0edab46

Browse files
authored
Switch from web to mobile tweet endpoint (#11)
1 parent 2142b25 commit 0edab46

File tree

4 files changed

+23
-16
lines changed

4 files changed

+23
-16
lines changed

src/api.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ proc getGraphTweet(id: string; after=""): Future[Conversation] {.async.} =
8484
variables = tweetVariables % [id, cursor]
8585
params = {"variables": variables, "features": gqlFeatures}
8686
js = await fetch(graphTweet ? params, Api.tweetDetail)
87-
result = parseGraphConversation(js, id)
87+
result = parseGraphConversation(js, id, true)
8888

8989
proc getReplies*(id, after: string): Future[Result[Chain]] {.async.} =
9090
result = (await getGraphTweet(id, after)).replies

src/auth.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const
99
dayInSeconds = 24 * 60 * 60
1010
apiMaxReqs: Table[Api, int] = {
1111
Api.search: 50,
12-
Api.tweetDetail: 150,
12+
Api.tweetDetail: 500,
1313
Api.userTweets: 500,
1414
Api.userTweetsAndReplies: 500,
1515
Api.userMedia: 500,

src/consts.nim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const
1313
graphUserTweets* = graphql / "3JNH4e9dq1BifLxAa3UMWg/UserWithProfileTweetsQueryV2"
1414
graphUserTweetsAndReplies* = graphql / "8IS8MaO-2EN6GZZZb8jF0g/UserWithProfileTweetsAndRepliesQueryV2"
1515
graphUserMedia* = graphql / "PDfFf8hGeJvUCiTyWtw4wQ/MediaTimelineV2"
16-
graphTweet* = graphql / "q94uRCEn65LZThakYcPT6g/TweetDetail"
16+
graphTweet* = graphql / "Vorskcd2tZ-tc4Gx3zbk4Q/ConversationTimelineV2"
1717
graphTweetResult* = graphql / "sITyJdhRPpvpEjg4waUmTA/TweetResultByIdQuery"
1818
graphSearchTimeline* = graphql / "gkjsKepM6gl_HmFWoWKfgg/SearchTimeline"
1919
graphListById* = graphql / "iTpgCtbdxrsJfyx0cFjHqg/ListByRestId"
@@ -77,7 +77,9 @@ const
7777
"unified_cards_ad_metadata_container_dynamic_card_content_query_enabled": false,
7878
"verified_phone_label_enabled": false,
7979
"vibe_api_enabled": false,
80-
"view_counts_everywhere_api_enabled": false
80+
"view_counts_everywhere_api_enabled": false,
81+
"articles_api_enabled": false,
82+
"immersive_video_status_linkable_timestamps": false
8183
}""".replace(" ", "").replace("\n", "")
8284

8385
tweetVariables* = """{

src/parser.nim

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -352,18 +352,23 @@ proc parseGraphTweetResult*(js: JsonNode): Tweet =
352352
with tweet, js{"data", "tweet_result", "result"}:
353353
result = parseGraphTweet(tweet, false)
354354

355-
proc parseGraphConversation*(js: JsonNode; tweetId: string): Conversation =
355+
proc parseGraphConversation*(js: JsonNode; tweetId: string; v2=true): Conversation =
356356
result = Conversation(replies: Result[Chain](beginning: true))
357357

358-
let instructions = ? js{"data", "threaded_conversation_with_injections_v2", "instructions"}
358+
let
359+
rootKey = if v2: "timeline_response" else: "threaded_conversation_with_injections_v2"
360+
contentKey = if v2: "content" else: "itemContent"
361+
resultKey = if v2: "tweetResult" else: "tweet_results"
362+
363+
let instructions = ? js{"data", rootKey, "instructions"}
359364
if instructions.len == 0:
360365
return
361366

362367
for e in instructions[0]{"entries"}:
363368
let entryId = e{"entryId"}.getStr
364369
if entryId.startsWith("tweet"):
365-
with tweetResult, e{"content", "itemContent", "tweet_results", "result"}:
366-
let tweet = parseGraphTweet(tweetResult, true)
370+
with tweetResult, e{"content", contentKey, resultKey, "result"}:
371+
let tweet = parseGraphTweet(tweetResult, not v2)
367372

368373
if not tweet.available:
369374
tweet.id = parseBiggestInt(entryId.getId())
@@ -372,26 +377,26 @@ proc parseGraphConversation*(js: JsonNode; tweetId: string): Conversation =
372377
result.tweet = tweet
373378
else:
374379
result.before.content.add tweet
380+
elif entryId.startsWith("conversationthread"):
381+
let (thread, self) = parseGraphThread(e)
382+
if self:
383+
result.after = thread
384+
else:
385+
result.replies.content.add thread
375386
elif entryId.startsWith("tombstone"):
376387
let id = entryId.getId()
377388
let tweet = Tweet(
378389
id: parseBiggestInt(id),
379390
available: false,
380-
text: e{"content", "itemContent", "tombstoneInfo", "richText"}.getTombstone
391+
text: e{"content", contentKey, "tombstoneInfo", "richText"}.getTombstone
381392
)
382393

383394
if id == tweetId:
384395
result.tweet = tweet
385396
else:
386397
result.before.content.add tweet
387-
elif entryId.startsWith("conversationthread"):
388-
let (thread, self) = parseGraphThread(e)
389-
if self:
390-
result.after = thread
391-
else:
392-
result.replies.content.add thread
393398
elif entryId.startsWith("cursor-bottom"):
394-
result.replies.bottom = e{"content", "itemContent", "value"}.getStr
399+
result.replies.bottom = e{"content", contentKey, "value"}.getStr
395400

396401
proc parseGraphTimeline*(js: JsonNode; root: string; after=""): Profile =
397402
result = Profile(tweets: Timeline(beginning: after.len == 0))

0 commit comments

Comments
 (0)