Add back search
This commit is contained in:
		
							parent
							
								
									b290f6fd29
								
							
						
					
					
						commit
						67203a431d
					
				
							
								
								
									
										16
									
								
								src/api.nim
								
								
								
								
							
							
						
						
									
										16
									
								
								src/api.nim
								
								
								
								
							|  | @ -115,6 +115,22 @@ proc getGraphSearch*(query: Query; after=""): Future[Profile] {.async.} = | |||
|   result = Profile(tweets: parseGraphSearch(await fetch(url, Api.search), after)) | ||||
|   result.tweets.query = query | ||||
| 
 | ||||
| proc getTweetSearch*(query: Query; after=""): Future[Timeline] {.async.} = | ||||
|   let q = genQueryParam(query) | ||||
|   if q.len == 0 or q == emptyQuery: | ||||
|     return Timeline(query: query, beginning: true) | ||||
| 
 | ||||
|   let url = tweetSearch ? genParams({ | ||||
|     "q": q, | ||||
|     "tweet_search_mode": "live", | ||||
|     "max_id": after | ||||
|   }) | ||||
| 
 | ||||
|   result = parseTweetSearch(await fetch(url, Api.search)) | ||||
|   result.query = query | ||||
|   if after.len == 0: | ||||
|     result.beginning = true | ||||
| 
 | ||||
| proc getUserSearch*(query: Query; page="1"): Future[Result[User]] {.async.} = | ||||
|   if query.text.len == 0: | ||||
|     return Result[User](query: query, beginning: true) | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ const | |||
| 
 | ||||
|   photoRail* = api / "1.1/statuses/media_timeline.json" | ||||
|   userSearch* = api / "1.1/users/search.json" | ||||
|   tweetSearch* = api / "1.1/search/tweets.json" | ||||
| 
 | ||||
|   graphql = api / "graphql" | ||||
|   graphUser* = graphql / "u7wQyGi6oExe8_TRWGMq4Q/UserResultByScreenNameQuery" | ||||
|  |  | |||
|  | @ -82,12 +82,16 @@ proc parseVideo(js: JsonNode): Video = | |||
|   result = Video( | ||||
|     thumb: js{"media_url_https"}.getImageStr, | ||||
|     views: js{"ext", "mediaStats", "r", "ok", "viewCount"}.getStr($js{"mediaStats", "viewCount"}.getInt), | ||||
|     available: js{"ext_media_availability", "status"}.getStr.toLowerAscii == "available", | ||||
|     available: true, | ||||
|     title: js{"ext_alt_text"}.getStr, | ||||
|     durationMs: js{"video_info", "duration_millis"}.getInt | ||||
|     # playbackType: mp4 | ||||
|   ) | ||||
| 
 | ||||
|   with status, js{"ext_media_availability", "status"}: | ||||
|     if status.getStr.len > 0 and status.getStr.toLowerAscii != "available": | ||||
|       result.available = false | ||||
| 
 | ||||
|   with title, js{"additional_media_info", "title"}: | ||||
|     result.title = title.getStr | ||||
| 
 | ||||
|  | @ -219,7 +223,9 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet = | |||
|   if result.hasThread and result.threadId == 0: | ||||
|     result.threadId = js{"self_thread", "id_str"}.getId | ||||
| 
 | ||||
|   if js{"is_quote_status"}.getBool: | ||||
|   if "retweeted_status" in js: | ||||
|     result.retweet = some Tweet() | ||||
|   elif js{"is_quote_status"}.getBool: | ||||
|     result.quote = some Tweet(id: js{"quoted_status_id_str"}.getId) | ||||
| 
 | ||||
|   # legacy | ||||
|  | @ -281,6 +287,30 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet = | |||
|       result.text.removeSuffix(" Learn more.") | ||||
|       result.available = false | ||||
| 
 | ||||
| proc parseLegacyTweet(js: JsonNode): Tweet = | ||||
|   result = parseTweet(js, js{"card"}) | ||||
|   if not result.isNil and result.available: | ||||
|     result.user = parseUser(js{"user"}) | ||||
| 
 | ||||
|     if result.quote.isSome: | ||||
|       result.quote = some parseLegacyTweet(js{"quoted_status"}) | ||||
| 
 | ||||
| proc parseTweetSearch*(js: JsonNode): Timeline = | ||||
|   if js.kind == JNull or "statuses" notin js: | ||||
|     return Timeline(beginning: true) | ||||
| 
 | ||||
|   for tweet in js{"statuses"}: | ||||
|     let parsed = parseLegacyTweet(tweet) | ||||
| 
 | ||||
|     if parsed.retweet.isSome: | ||||
|       parsed.retweet = some parseLegacyTweet(tweet{"retweeted_status"}) | ||||
| 
 | ||||
|     result.content.add @[parsed] | ||||
| 
 | ||||
|   let cursor = js{"search_metadata", "next_results"}.getStr | ||||
|   if cursor.len > 0 and "max_id" in cursor: | ||||
|     result.bottom = cursor[cursor.find("=") + 1 .. cursor.find("&q=")] | ||||
| 
 | ||||
| proc finalizeTweet(global: GlobalObjects; id: string): Tweet = | ||||
|   let intId = if id.len > 0: parseBiggestInt(id) else: 0 | ||||
|   result = global.tweets.getOrDefault(id, Tweet(id: intId)) | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ proc timelineRss*(req: Request; cfg: Config; query: Query): Future[Rss] {.async. | |||
|   else: | ||||
|     var q = query | ||||
|     q.fromUser = names | ||||
|     profile = await getGraphSearch(q, after) | ||||
|     profile.tweets = await getTweetSearch(q, after) | ||||
|     # this is kinda dumb | ||||
|     profile.user = User( | ||||
|       username: name, | ||||
|  | @ -59,29 +59,29 @@ template respRss*(rss, page) = | |||
| 
 | ||||
| proc createRssRouter*(cfg: Config) = | ||||
|   router rss: | ||||
|     # get "/search/rss": | ||||
|     #   cond cfg.enableRss | ||||
|     #   if @"q".len > 200: | ||||
|     #     resp Http400, showError("Search input too long.", cfg) | ||||
|     get "/search/rss": | ||||
|       cond cfg.enableRss | ||||
|       if @"q".len > 200: | ||||
|         resp Http400, showError("Search input too long.", cfg) | ||||
| 
 | ||||
|     #   let query = initQuery(params(request)) | ||||
|     #   if query.kind != tweets: | ||||
|     #     resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg) | ||||
|       let query = initQuery(params(request)) | ||||
|       if query.kind != tweets: | ||||
|         resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg) | ||||
| 
 | ||||
|     #   let | ||||
|     #     cursor = getCursor() | ||||
|     #     key = redisKey("search", $hash(genQueryUrl(query)), cursor) | ||||
|       let | ||||
|         cursor = getCursor() | ||||
|         key = redisKey("search", $hash(genQueryUrl(query)), cursor) | ||||
| 
 | ||||
|     #   var rss = await getCachedRss(key) | ||||
|     #   if rss.cursor.len > 0: | ||||
|     #     respRss(rss, "Search") | ||||
|       var rss = await getCachedRss(key) | ||||
|       if rss.cursor.len > 0: | ||||
|         respRss(rss, "Search") | ||||
| 
 | ||||
|     #   let tweets = await getGraphSearch(query, cursor) | ||||
|     #   rss.cursor = tweets.bottom | ||||
|     #   rss.feed = renderSearchRss(tweets.content, query.text, genQueryUrl(query), cfg) | ||||
|       let tweets = await getTweetSearch(query, cursor) | ||||
|       rss.cursor = tweets.bottom | ||||
|       rss.feed = renderSearchRss(tweets.content, query.text, genQueryUrl(query), cfg) | ||||
| 
 | ||||
|     #   await cacheRss(key, rss) | ||||
|     #   respRss(rss, "Search") | ||||
|       await cacheRss(key, rss) | ||||
|       respRss(rss, "Search") | ||||
| 
 | ||||
|     get "/@name/rss": | ||||
|       cond cfg.enableRss | ||||
|  |  | |||
|  | @ -34,15 +34,11 @@ proc createSearchRouter*(cfg: Config) = | |||
|           users = Result[User](beginning: true, query: query) | ||||
|         resp renderMain(renderUserSearch(users, prefs), request, cfg, prefs, title) | ||||
|       of tweets: | ||||
|         # let | ||||
|         #   tweets = await getGraphSearch(query, getCursor()) | ||||
|         #   rss = "/search/rss?" & genQueryUrl(query) | ||||
|         # resp renderMain(renderTweetSearch(tweets, prefs, getPath()), | ||||
|         #                 request, cfg, prefs, title, rss=rss) | ||||
|         var fakeTimeline = Timeline(beginning: true) | ||||
|         fakeTimeline.content.add Tweet(tombstone: "Tweet search is unavailable for now") | ||||
| 
 | ||||
|         resp renderMain(renderTweetSearch(fakeTimeline, prefs, getPath()), request, cfg, prefs, title) | ||||
|         let | ||||
|           tweets = await getTweetSearch(query, getCursor()) | ||||
|           rss = "/search/rss?" & genQueryUrl(query) | ||||
|         resp renderMain(renderTweetSearch(tweets, prefs, getPath()), | ||||
|                         request, cfg, prefs, title, rss=rss) | ||||
|       else: | ||||
|         resp Http404, showError("Invalid search", cfg) | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,8 +56,7 @@ proc fetchProfile*(after: string; query: Query; skipRail=false; | |||
|     of posts: await getGraphUserTweets(userId, TimelineKind.tweets, after) | ||||
|     of replies: await getGraphUserTweets(userId, TimelineKind.replies, after) | ||||
|     of media: await getGraphUserTweets(userId, TimelineKind.media, after) | ||||
|     else: Profile(tweets: Timeline(beginning: true, content: @[@[Tweet(tombstone: "Tweet search is unavailable for now")]])) | ||||
|     # else: await getGraphSearch(query, after) | ||||
|     else: Profile(tweets: await getTweetSearch(query, after)) | ||||
| 
 | ||||
|   result.user = await user | ||||
|   result.photoRail = await rail | ||||
|  | @ -71,9 +70,8 @@ proc showTimeline*(request: Request; query: Query; cfg: Config; prefs: Prefs; | |||
|                    rss, after: string): Future[string] {.async.} = | ||||
|   if query.fromUser.len != 1: | ||||
|     let | ||||
|       # timeline = await getGraphSearch(query, after) | ||||
|       timeline = Profile(tweets: Timeline(beginning: true, content: @[@[Tweet(tombstone: "This features is unavailable for now")]])) | ||||
|       html = renderTweetSearch(timeline.tweets, prefs, getPath()) | ||||
|       timeline = await getTweetSearch(query, after) | ||||
|       html = renderTweetSearch(timeline, prefs, getPath()) | ||||
|     return renderMain(html, request, cfg, prefs, "Multi", rss=rss) | ||||
| 
 | ||||
|   var profile = await fetchProfile(after, query, skipPinned=prefs.hidePins) | ||||
|  |  | |||
|  | @ -41,9 +41,9 @@ proc getPoolJson*(): JsonNode = | |||
|       let | ||||
|         maxReqs = | ||||
|           case api | ||||
|           of Api.timeline: 180 | ||||
|           of Api.timeline, Api.search: 180 | ||||
|           of Api.userTweets, Api.userTweetsAndReplies, Api.userRestId, | ||||
|              Api.userScreenName, Api.tweetDetail, Api.tweetResult, Api.search: 500 | ||||
|              Api.userScreenName, Api.tweetDetail, Api.tweetResult: 500 | ||||
|           of Api.list, Api.listTweets, Api.listMembers, Api.listBySlug, Api.userMedia: 500 | ||||
|           of Api.userSearch: 900 | ||||
|         reqs = maxReqs - token.apis[api].remaining | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue