fix headers so UserByRestId works

This commit is contained in:
Cynthia Foxwell 2025-11-13 20:48:34 -07:00
parent 0e74c1e9bd
commit ec019eef72
No known key found for this signature in database
3 changed files with 43 additions and 15 deletions

View File

@ -6,23 +6,41 @@ import experimental/parser as newParser
proc getGraphUser*(username: string): Future[User] {.async.} =
if username.len == 0: return
let
headers = newHttpHeaders()
headers.add("Referer", """https://x.com/$1""" % username)
let
variables = """{"screen_name":"$1"}""" % username
fieldToggles = """{"withAuxiliaryUserLabels":true}"""
params = {"variables": variables, "features": gqlFeatures, "fieldToggles": fieldToggles}
js = await fetch(graphUser ? params, Api.userScreenName)
js = await fetch(graphUser ? params, Api.userScreenName, headers)
result = parseGraphUser(js)
proc getGraphUserById*(id: string): Future[User] {.async.} =
if id.len == 0 or id.any(c => not c.isDigit): return
let
headers = newHttpHeaders()
headers.add("Referer", """https://x.com/i/user/$1""" % id)
let
variables = """{"userId":"$1"}""" % id
params = {"variables": variables, "features": gqlFeatures}
js = await fetch(graphUserById ? params, Api.userRestId)
js = await fetch(graphUserById ? params, Api.userRestId, headers)
result = parseGraphUser(js)
proc getGraphUserTweets*(id: string; kind: TimelineKind; after=""): Future[Profile] {.async.} =
if id.len == 0: return
let endpoint = case kind
of TimelineKind.tweets: ""
of TimelineKind.replies: "/with_replies"
of TimelineKind.media: "/media"
let
headers = newHttpHeaders()
headers.add("Referer", """https://x.com/$1$2""" % [id, endpoint])
let
cursor = if after.len > 0: "\"cursor\":\"$1\"," % after else: ""
variables = if kind == TimelineKind.media: userMediaVariables % [id, cursor] else: userTweetsVariables % [id, cursor]
@ -32,7 +50,7 @@ proc getGraphUserTweets*(id: string; kind: TimelineKind; after=""): Future[Profi
of TimelineKind.tweets: (graphUserTweets, Api.userTweets)
of TimelineKind.replies: (graphUserTweetsAndReplies, Api.userTweetsAndReplies)
of TimelineKind.media: (graphUserMedia, Api.userMedia)
js = await fetch(url ? params, apiId)
js = await fetch(url ? params, apiId, headers)
result = parseGraphTimeline(js, if kind == TimelineKind.media: "" else: "user", after)
proc getGraphListTweets*(id: string; after=""): Future[Timeline] {.async.} =
@ -90,19 +108,27 @@ proc getFavorites*(id: string; cfg: Config; after=""): Future[Profile] {.async.}
proc getGraphTweetResult*(id: string): Future[Tweet] {.async.} =
if id.len == 0: return
let
headers = newHttpHeaders()
headers.add("Referer", """https://x.com/i/status/$1""" % id)
let
variables = """{"rest_id":"$1"}""" % id
params = {"variables": variables, "features": gqlFeatures}
js = await fetch(graphTweetResult ? params, Api.tweetResult)
js = await fetch(graphTweetResult ? params, Api.tweetResult, headers)
result = parseGraphTweetResult(js)
proc getGraphTweet*(id: string; after=""): Future[Conversation] {.async.} =
if id.len == 0: return
let
headers = newHttpHeaders()
headers.add("Referer", """https://x.com/i/status/$1""" % id)
let
cursor = if after.len > 0: "\"cursor\":\"$1\"," % after else: ""
variables = tweetVariables % [id, cursor]
params = {"variables": variables, "features": gqlFeatures, "fieldToggles": tweetFieldToggles}
js = await fetch(graphTweet ? params, Api.tweetDetail)
js = await fetch(graphTweet ? params, Api.tweetDetail, headers)
result = parseGraphConversation(js, id)
proc getGraphFavoriters*(id: string; after=""): Future[UsersTimeline] {.async.} =

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-only
import httpclient, asyncdispatch, options, strutils, uri, times, tables
import httpclient, asyncdispatch, options, strutils, uri, times, tables, math
import jsony, packedjson, zippy
import types, tokens, consts, parserutils, http_pool
import experimental/types/common
@ -32,6 +32,9 @@ proc genParams*(pars: openArray[(string, string)] = @[]; cursor="";
#proc genHeaders*(token: Token = nil): HttpHeaders =
proc genHeaders*(): HttpHeaders =
let
t = getTime()
ffVersion = floor(124 + ((t.toUnix() / 1000) - 1710892800) / 2419200)
result = newHttpHeaders({
"connection": "keep-alive",
"authorization": auth,
@ -45,8 +48,12 @@ proc genHeaders*(): HttpHeaders =
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Sec-GPC": "1",
"TE": "trailers"
})
"TE": "trailers",
"User-Agent": """Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:$1.0) Gecko/20100101 Firefox/$1.0""" % $ffVersion,
"x-twitter-active-user": "yes",
"x-twitter-auth-type": "OAuth2Session",
"x-twitter-client-language": "en"
}, true)
#template updateToken() =
# if resp.headers.hasKey(rlRemaining):
@ -66,21 +73,16 @@ template fetchImpl(result, additional_headers, fetchBody) {.dirty.} =
if len(cfg.cookieHeader) != 0:
additional_headers.add("Cookie", cfg.cookieHeader)
additional_headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0")
if len(cfg.xCsrfToken) != 0:
additional_headers.add("x-csrf-token", cfg.xCsrfToken)
additional_headers.add("x-twitter-active-user", "yes")
additional_headers.add("x-twitter-auth-type", "OAuth2Session")
additional_headers.add("x-twitter-client-language", "en")
try:
var resp: AsyncResponse
#var headers = genHeaders(token)
var headers = genHeaders()
for key, value in additional_headers.pairs():
headers.add(key, value)
pool.use(headers):
template getContent =
resp = await c.get($url)

View File

@ -151,7 +151,7 @@ proc getCachedUsername*(userId: string): Future[string] {.async.} =
key = "i:" & userId
username = await get(key)
if username != redisNil:
if username != redisNil and username.len > 0:
result = username
else:
let user = await getGraphUserById(userId)