added feature to view who a user follows or is followed by (won't compile because of a compiler bug)
This commit is contained in:
parent
1150a59e38
commit
2ce3ee6d84
8 changed files with 72 additions and 34 deletions
19
src/api.nim
19
src/api.nim
|
@ -3,7 +3,6 @@ import asyncdispatch, httpclient, uri, strutils, sequtils, sugar
|
|||
import packedjson
|
||||
import types, query, formatters, consts, apiutils, parser
|
||||
import experimental/parser as newParser
|
||||
import config
|
||||
|
||||
proc getGraphUser*(username: string): Future[User] {.async.} =
|
||||
if username.len == 0: return
|
||||
|
@ -112,6 +111,24 @@ proc getGraphRetweeters*(id: string; after=""): Future[UsersTimeline] {.async.}
|
|||
js = await fetch(graphRetweeters ? params, Api.retweeters)
|
||||
result = parseGraphRetweetersTimeline(js, id)
|
||||
|
||||
proc getGraphFollowing*(id: string; after=""): Future[UsersTimeline] {.async.} =
|
||||
if id.len == 0: return
|
||||
let
|
||||
cursor = if after.len > 0: "\"cursor\":\"$1\"," % after else: ""
|
||||
variables = followVariables % [id, cursor]
|
||||
params = {"variables": variables, "features": gqlFeatures}
|
||||
js = await fetch(graphFollowing ? params, Api.following)
|
||||
result = parseGraphFollowTimeline(js, id)
|
||||
|
||||
proc getGraphFollowers*(id: string; after=""): Future[UsersTimeline] {.async.} =
|
||||
if id.len == 0: return
|
||||
let
|
||||
cursor = if after.len > 0: "\"cursor\":\"$1\"," % after else: ""
|
||||
variables = followVariables % [id, cursor]
|
||||
params = {"variables": variables, "features": gqlFeatures}
|
||||
js = await fetch(graphFollowers ? params, Api.followers)
|
||||
result = parseGraphFollowTimeline(js, id)
|
||||
|
||||
proc getReplies*(id, after: string): Future[Result[Chain]] {.async.} =
|
||||
result = (await getGraphTweet(id, after)).replies
|
||||
result.beginning = after.len == 0
|
||||
|
|
|
@ -71,8 +71,8 @@ template fetchImpl(result, additional_headers, fetchBody) {.dirty.} =
|
|||
|
||||
getContent()
|
||||
|
||||
if resp.status == $Http429:
|
||||
raise rateLimitError()
|
||||
if resp.status == $Http429:
|
||||
raise rateLimitError()
|
||||
|
||||
if resp.status == $Http503:
|
||||
badClient = true
|
||||
|
|
|
@ -28,6 +28,8 @@ const
|
|||
graphListTweets* = graphql / "jZntL0oVJSdjhmPcdbw_eA/ListLatestTweetsTimeline"
|
||||
graphFavoriters* = graphql / "mDc_nU8xGv0cLRWtTaIEug/Favoriters"
|
||||
graphRetweeters* = graphql / "RCR9gqwYD1NEgi9FWzA50A/Retweeters"
|
||||
graphFollowers* = graphql / "EAqBhgcGr_qPOzhS4Q3scQ/Followers"
|
||||
graphFollowing* = graphql / "JPZiqKjET7_M1r5Tlr8pyA/Following"
|
||||
|
||||
timelineParams* = {
|
||||
"include_profile_interstitial_type": "0",
|
||||
|
@ -129,3 +131,9 @@ const
|
|||
"count" : 20,
|
||||
"includePromotedContent": false
|
||||
}"""
|
||||
|
||||
followVariables* = """{
|
||||
"userId" : "$1", $2
|
||||
"count" : 20,
|
||||
"includePromotedContent": false
|
||||
}"""
|
||||
|
|
|
@ -498,10 +498,10 @@ proc parseGraphTimeline*(js: JsonNode; root: string; after=""): Timeline =
|
|||
elif entryId.startsWith("cursor-bottom"):
|
||||
result.bottom = e{"content", "value"}.getStr
|
||||
|
||||
proc parseGraphUsersTimeline(js: JsonNode; root: string; key: string; after=""): UsersTimeline =
|
||||
proc parseGraphUsersTimeline(timeline: JsonNode; after=""): UsersTimeline =
|
||||
result = UsersTimeline(beginning: after.len == 0)
|
||||
|
||||
let instructions = ? js{"data", key, "timeline", "instructions"}
|
||||
let instructions = ? timeline{"instructions"}
|
||||
|
||||
if instructions.len == 0:
|
||||
return
|
||||
|
@ -520,10 +520,13 @@ proc parseGraphUsersTimeline(js: JsonNode; root: string; key: string; after=""):
|
|||
result.top = e{"content", "value"}.getStr
|
||||
|
||||
proc parseGraphFavoritersTimeline*(js: JsonNode; root: string; after=""): UsersTimeline =
|
||||
return parseGraphUsersTimeline(js, root, "favoriters_timeline", after)
|
||||
return parseGraphUsersTimeline(js{"data", "favoriters_timeline", "timeline"}, after)
|
||||
|
||||
proc parseGraphRetweetersTimeline*(js: JsonNode; root: string; after=""): UsersTimeline =
|
||||
return parseGraphUsersTimeline(js, root, "retweeters_timeline", after)
|
||||
return parseGraphUsersTimeline(js{"data", "retweeters_timeline", "timeline"}, after)
|
||||
|
||||
proc parseGraphFollowTimeline*(js: JsonNode; root: string; after=""): UsersTimeline =
|
||||
return parseGraphUsersTimeline(js{"data", "user", "result", "timeline", "timeline"}, after)
|
||||
|
||||
proc parseGraphSearch*(js: JsonNode; after=""): Timeline =
|
||||
result = Timeline(beginning: after.len == 0)
|
||||
|
|
|
@ -5,7 +5,7 @@ import jester, karax/vdom
|
|||
|
||||
import router_utils
|
||||
import ".."/[types, formatters, api]
|
||||
import ../views/[general, status, timeline, search]
|
||||
import ../views/[general, status, search]
|
||||
|
||||
export uri, sequtils, options, sugar
|
||||
export router_utils
|
||||
|
|
|
@ -127,35 +127,41 @@ proc createTimelineRouter*(cfg: Config) =
|
|||
get "/@name/?@tab?/?":
|
||||
cond '.' notin @"name"
|
||||
cond @"name" notin ["pic", "gif", "video", "search", "settings", "login", "intent", "i"]
|
||||
cond @"tab" in ["with_replies", "media", "search", "favorites", ""]
|
||||
cond @"tab" in ["with_replies", "media", "search", "favorites", "following", "followers", ""]
|
||||
let
|
||||
prefs = cookiePrefs()
|
||||
after = getCursor()
|
||||
names = getNames(@"name")
|
||||
|
||||
var query = request.getQuery(@"tab", @"name")
|
||||
if names.len != 1:
|
||||
query.fromUser = names
|
||||
|
||||
# used for the infinite scroll feature
|
||||
if @"scroll".len > 0:
|
||||
if query.fromUser.len != 1:
|
||||
var timeline = await getGraphSearch(query, after)
|
||||
if timeline.content.len == 0: resp Http404
|
||||
timeline.beginning = true
|
||||
resp $renderTweetSearch(timeline, cfg, prefs, getPath())
|
||||
case @"tab":
|
||||
of "followers":
|
||||
resp renderMain(renderUserList(await getGraphFollowers(await getUserId(@"name"), getCursor()), prefs), request, cfg, prefs)
|
||||
of "following":
|
||||
resp renderMain(renderUserList(await getGraphFollowing(await getUserId(@"name"), getCursor()), prefs), request, cfg, prefs)
|
||||
else:
|
||||
var profile = await fetchProfile(after, query, cfg, skipRail=true)
|
||||
if profile.tweets.content.len == 0: resp Http404
|
||||
profile.tweets.beginning = true
|
||||
resp $renderTimelineTweets(profile.tweets, prefs, getPath())
|
||||
var query = request.getQuery(@"tab", @"name")
|
||||
if names.len != 1:
|
||||
query.fromUser = names
|
||||
|
||||
let rss =
|
||||
if @"tab".len == 0:
|
||||
"/$1/rss" % @"name"
|
||||
elif @"tab" == "search":
|
||||
"/$1/search/rss?$2" % [@"name", genQueryUrl(query)]
|
||||
else:
|
||||
"/$1/$2/rss" % [@"name", @"tab"]
|
||||
# used for the infinite scroll feature
|
||||
if @"scroll".len > 0:
|
||||
if query.fromUser.len != 1:
|
||||
var timeline = await getGraphSearch(query, after)
|
||||
if timeline.content.len == 0: resp Http404
|
||||
timeline.beginning = true
|
||||
resp $renderTweetSearch(timeline, cfg, prefs, getPath())
|
||||
else:
|
||||
var profile = await fetchProfile(after, query, cfg, skipRail=true)
|
||||
if profile.tweets.content.len == 0: resp Http404
|
||||
profile.tweets.beginning = true
|
||||
resp $renderTimelineTweets(profile.tweets, prefs, getPath())
|
||||
|
||||
respTimeline(await showTimeline(request, query, cfg, prefs, rss, after))
|
||||
let rss =
|
||||
if @"tab".len == 0:
|
||||
"/$1/rss" % @"name"
|
||||
elif @"tab" == "search":
|
||||
"/$1/search/rss?$2" % [@"name", genQueryUrl(query)]
|
||||
else:
|
||||
"/$1/$2/rss" % [@"name", @"tab"]
|
||||
|
||||
respTimeline(await showTimeline(request, query, cfg, prefs, rss, after))
|
||||
|
|
|
@ -32,6 +32,8 @@ type
|
|||
userMedia
|
||||
favoriters
|
||||
retweeters
|
||||
following
|
||||
followers
|
||||
|
||||
RateLimit* = object
|
||||
remaining*: int
|
||||
|
|
|
@ -59,8 +59,10 @@ proc renderUserCard*(user: User; prefs: Prefs): VNode =
|
|||
tdiv(class="profile-card-extra-links"):
|
||||
ul(class="profile-statlist"):
|
||||
renderStat(user.tweets, "posts", text="Tweets")
|
||||
renderStat(user.following, "following")
|
||||
renderStat(user.followers, "followers")
|
||||
a(href="/" & user.username & "/following"):
|
||||
renderStat(user.following, "following")
|
||||
a(href="/" & user.username & "/followers"):
|
||||
renderStat(user.followers, "followers")
|
||||
renderStat(user.likes, "likes")
|
||||
|
||||
proc renderPhotoRail(profile: Profile): VNode =
|
||||
|
|
Loading…
Reference in a new issue