From 735b30c2da336cc57be2b98c48a6f7e826fdaed0 Mon Sep 17 00:00:00 2001 From: LS <66217791+DrSocket@users.noreply.github.com> Date: Mon, 30 Oct 2023 13:13:06 +0100 Subject: [PATCH] fix(nitter): add graphql user search (#1047) * fix(nitter): add graphql user search * fix(nitter): rm gitignore 2nd guest_accounts * fix(nitter): keep query from user search in result. remove personal mods * fix(nitter): removce useless line gitignore --- src/api.nim | 28 ++++++++++++++++------------ src/consts.nim | 3 +-- src/parser.nim | 24 +++++++++++++++--------- src/routes/search.nim | 2 +- src/tokens.nim | 1 - src/types.nim | 1 - 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/api.nim b/src/api.nim index 4ac999c..d6a4564 100644 --- a/src/api.nim +++ b/src/api.nim @@ -112,25 +112,29 @@ proc getGraphTweetSearch*(query: Query; after=""): Future[Timeline] {.async.} = if after.len > 0: variables["cursor"] = % after let url = graphSearchTimeline ? {"variables": $variables, "features": gqlFeatures} - result = parseGraphSearch(await fetch(url, Api.search), after) + result = parseGraphSearch[Tweets](await fetch(url, Api.search), after) result.query = query -proc getUserSearch*(query: Query; page="1"): Future[Result[User]] {.async.} = +proc getGraphUserSearch*(query: Query; after=""): Future[Result[User]] {.async.} = if query.text.len == 0: return Result[User](query: query, beginning: true) - let - page = if page.len == 0: "1" else: page - url = userSearch ? genParams({"q": query.text, "skip_status": "1", "page": page}) - js = await fetchRaw(url, Api.userSearch) - - result = parseUsers(js) + var + variables = %*{ + "rawQuery": query.text, + "count": 20, + "product": "People", + "withDownvotePerspective": false, + "withReactionsMetadata": false, + "withReactionsPerspective": false + } + if after.len > 0: + variables["cursor"] = % after + result.beginning = false + let url = graphSearchTimeline ? {"variables": $variables, "features": gqlFeatures} + result = parseGraphSearch[User](await fetch(url, Api.search), after) result.query = query - if page.len == 0: - result.bottom = "2" - elif page.allCharsInSet(Digits): - result.bottom = $(parseInt(page) + 1) proc getPhotoRail*(name: string): Future[PhotoRail] {.async.} = if name.len == 0: return diff --git a/src/consts.nim b/src/consts.nim index 96cea47..d3a3d80 100644 --- a/src/consts.nim +++ b/src/consts.nim @@ -9,7 +9,6 @@ const activate* = $(api / "1.1/guest/activate.json") photoRail* = api / "1.1/statuses/media_timeline.json" - userSearch* = api / "1.1/users/search.json" graphql = api / "graphql" graphUser* = graphql / "u7wQyGi6oExe8_TRWGMq4Q/UserResultByScreenNameQuery" @@ -35,7 +34,7 @@ const "include_user_entities": "1", "include_ext_reply_count": "1", "include_ext_is_blue_verified": "1", - #"include_ext_verified_type": "1", + # "include_ext_verified_type": "1", "include_ext_media_color": "0", "cards_platform": "Web-13", "tweet_mode": "extended", diff --git a/src/parser.nim b/src/parser.nim index 776f176..cebf6f1 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -443,8 +443,8 @@ proc parseGraphTimeline*(js: JsonNode; root: string; after=""): Profile = tweet.id = parseBiggestInt(entryId) result.pinned = some tweet -proc parseGraphSearch*(js: JsonNode; after=""): Timeline = - result = Timeline(beginning: after.len == 0) +proc parseGraphSearch*[T: User | Tweets](js: JsonNode; after=""): Result[T] = + result = Result[T](beginning: after.len == 0) let instructions = js{"data", "search_by_raw_query", "search_timeline", "timeline", "instructions"} if instructions.len == 0: @@ -455,13 +455,19 @@ proc parseGraphSearch*(js: JsonNode; after=""): Timeline = if typ == "TimelineAddEntries": for e in instruction{"entries"}: let entryId = e{"entryId"}.getStr - if entryId.startsWith("tweet"): - with tweetRes, e{"content", "itemContent", "tweet_results", "result"}: - let tweet = parseGraphTweet(tweetRes, true) - if not tweet.available: - tweet.id = parseBiggestInt(entryId.getId()) - result.content.add tweet - elif entryId.startsWith("cursor-bottom"): + when T is Tweets: + if entryId.startsWith("tweet"): + with tweetRes, e{"content", "itemContent", "tweet_results", "result"}: + let tweet = parseGraphTweet(tweetRes) + if not tweet.available: + tweet.id = parseBiggestInt(entryId.getId()) + result.content.add tweet + elif T is User: + if entryId.startsWith("user"): + with userRes, e{"content", "itemContent"}: + result.content.add parseGraphUser(userRes) + + if entryId.startsWith("cursor-bottom"): result.bottom = e{"content", "value"}.getStr elif typ == "TimelineReplaceEntry": if instruction{"entry_id_to_replace"}.getStr.startsWith("cursor-bottom"): diff --git a/src/routes/search.nim b/src/routes/search.nim index 676229e..e9f991d 100644 --- a/src/routes/search.nim +++ b/src/routes/search.nim @@ -29,7 +29,7 @@ proc createSearchRouter*(cfg: Config) = redirect("/" & q) var users: Result[User] try: - users = await getUserSearch(query, getCursor()) + users = await getGraphUserSearch(query, getCursor()) except InternalError: users = Result[User](beginning: true, query: query) resp renderMain(renderUserSearch(users, prefs), request, cfg, prefs, title) diff --git a/src/tokens.nim b/src/tokens.nim index b8a50e3..ca74ddc 100644 --- a/src/tokens.nim +++ b/src/tokens.nim @@ -62,7 +62,6 @@ proc getPoolJson*(): JsonNode = Api.userRestId, Api.userScreenName, Api.tweetResult, Api.list, Api.listTweets, Api.listMembers, Api.listBySlug: 500 - of Api.userSearch: 900 reqs = maxReqs - apiStatus.remaining reqsPerApi[$api] = reqsPerApi.getOrDefault($api, 0) + reqs diff --git a/src/types.nim b/src/types.nim index 4cacc4b..3f5f8ac 100644 --- a/src/types.nim +++ b/src/types.nim @@ -19,7 +19,6 @@ type tweetResult photoRail search - userSearch list listBySlug listMembers