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