From a901e50df5bebd7ab5afdeaf36b8707afb1d9e5b Mon Sep 17 00:00:00 2001 From: Zed Date: Mon, 1 Jul 2019 03:13:12 +0200 Subject: [PATCH] Display "more replies" --- public/style.css | 26 ++++++++++++++++++++++++++ src/api.nim | 19 ++++++++++--------- src/parser.nim | 18 ++++++++++-------- src/parserutils.nim | 7 +++++++ src/types.nim | 16 +++++++++------- src/views/user.nimf | 24 +++++++++++++++--------- 6 files changed, 77 insertions(+), 33 deletions(-) diff --git a/public/style.css b/public/style.css index 65150b0..6542428 100644 --- a/public/style.css +++ b/public/style.css @@ -505,6 +505,18 @@ video { margin-bottom: 10px; } +.more-replies { + padding-top: 0.3em; +} + +.more-replies-text { + display: block; + margin-left: 58px; + padding: 7px 0; + text-overflow: ellipsis; + white-space: nowrap; +} + .thread-line .status-el::before { background: #8a3731; content: ''; @@ -530,6 +542,20 @@ video { margin: 0; } +.thread-line .more-replies::before { + content: '...'; + background: unset; + color: #b94e46; + font-weight: bold; + font-size: 22px; + line-height: 0.25em; + left: 1.2em; + width: 5px; + top: 2px; + margin-bottom: 0px; + margin-left: -5px; +} + .panel { margin: auto; font-size: 130%; diff --git a/src/api.nim b/src/api.nim index b6c3ae1..e1d2232 100644 --- a/src/api.nim +++ b/src/api.nim @@ -110,14 +110,14 @@ proc getVideo*(tweet: Tweet; token: string) {.async.} = tweet.video = some(parseVideo(json)) tokenUses.inc -proc getVideos*(tweets: Tweets; token="") {.async.} = +proc getVideos*(thread: Thread; token="") {.async.} = var gToken = token var videoFuts: seq[Future[void]] if gToken.len == 0: gToken = await getGuestToken() - for tweet in tweets.filterIt(it.video.isSome): + for tweet in thread.tweets.filterIt(it.video.isSome): videoFuts.add getVideo(tweet, token) await all(videoFuts) @@ -150,8 +150,8 @@ proc getPoll*(tweet: Tweet) {.async.} = tweet.poll = some(parsePoll(html)) -proc getPolls*(tweets: Tweets) {.async.} = - var polls = tweets.filterIt(it.poll.isSome) +proc getPolls*(thread: Thread) {.async.} = + var polls = thread.tweets.filterIt(it.poll.isSome) await all(polls.map(getPoll)) proc getConversationPolls*(convo: Conversation) {.async.} = @@ -222,13 +222,14 @@ proc getTimeline*(username: string; after=""): Future[Timeline] {.async.} = if json["new_latent_count"].to(int) == 0: return if not json.hasKey("items_html"): return - let html = parseHtml(json["items_html"].to(string)) + let + html = parseHtml(json["items_html"].to(string)) + thread = parseThread(html) + vidsFut = getVideos(thread) + pollFut = getPolls(thread) - result.tweets = parseTweets(html) - - let vidsFut = getVideos(result.tweets) - let pollFut = getPolls(result.tweets) await all(vidsFut, pollFut) + result.tweets = thread.tweets proc getTweet*(username: string; id: string): Future[Conversation] {.async.} = let headers = newHttpHeaders({ diff --git a/src/parser.nim b/src/parser.nim index e6a17bf..591eb1d 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -82,19 +82,21 @@ proc parseTweet*(node: XmlNode): Tweet = if quote != nil: result.quote = some(parseQuote(quote)) -proc parseTweets*(nodes: XmlNode): Tweets = +proc parseThread*(nodes: XmlNode): Thread = if nodes == nil: return for n in nodes.filterIt(it.kind != xnText): let class = n.attr("class").toLower() if "tombstone" in class or "unavailable" in class: - result.add Tweet() - elif "morereplies" notin class: - result.add parseTweet(n) + result.tweets.add Tweet() + elif "morereplies" in class: + result.more = getMoreReplies(n) + else: + result.tweets.add parseTweet(n) proc parseConversation*(node: XmlNode): Conversation = result = Conversation( tweet: parseTweet(node.select(".permalink-tweet-container")), - before: parseTweets(node.select(".in-reply-to .stream-items")) + before: parseThread(node.select(".in-reply-to .stream-items")) ) let replies = node.select(".replies-to .stream-items") @@ -105,11 +107,11 @@ proc parseConversation*(node: XmlNode): Conversation = let thread = reply.select(".stream-items") if "self" in class: - result.after = parseTweets(thread) + result.after = parseThread(thread) elif "lone" in class: - result.replies.add parseTweets(reply) + result.replies.add parseThread(reply) else: - result.replies.add parseTweets(thread) + result.replies.add parseThread(thread) proc parseVideo*(node: JsonNode): Video = let diff --git a/src/parserutils.nim b/src/parserutils.nim index b2aabb2..f9fa80a 100644 --- a/src/parserutils.nim +++ b/src/parserutils.nim @@ -162,3 +162,10 @@ proc getTweetCards*(tweet: Tweet; node: XmlNode) = if node.attr("data-has-cards") == "false": return if "poll" in node.attr("data-card2-type"): tweet.poll = some(Poll()) + +proc getMoreReplies*(node: XmlNode): int = + let text = node.innerText().strip() + try: + result = parseInt(text.split(" ")[0]) + except: + result = -1 diff --git a/src/types.nim b/src/types.nim index cf6774d..a1e267b 100644 --- a/src/types.nim +++ b/src/types.nim @@ -83,19 +83,21 @@ type poll*: Option[Poll] available*: bool - Tweets* = seq[Tweet] + Thread* = object + tweets*: seq[Tweet] + more*: int Conversation* = ref object tweet*: Tweet - before*: Tweets - after*: Tweets - replies*: seq[Tweets] + before*: Thread + after*: Thread + replies*: seq[Thread] Timeline* = ref object - tweets*: Tweets + tweets*: seq[Tweet] minId*: string maxId*: string hasMore*: bool -proc contains*(thread: Tweets; tweet: Tweet): bool = - thread.anyIt(it.id == tweet.id) +proc contains*(thread: Thread; tweet: Tweet): bool = + thread.tweets.anyIt(it.id == tweet.id) diff --git a/src/views/user.nimf b/src/views/user.nimf index f16425b..270dcb4 100644 --- a/src/views/user.nimf +++ b/src/views/user.nimf @@ -51,7 +51,7 @@ #end proc # #proc renderTimeline*(timeline: Timeline; profile: Profile; beginning: bool): string = -#var retweets: Tweets +#var retweets: seq[Tweet]
#if not beginning:
@@ -104,21 +104,21 @@ #proc renderConversation*(conversation: Conversation): string =
- #if conversation.before.len > 0: + #if conversation.before.tweets.len > 0:
- #for tweet in conversation.before: + #for tweet in conversation.before.tweets: ${renderTweet(tweet)} #end for
#end if
- #let afterClass = if conversation.after.len > 0: "thread thread-line" else: "" + #let afterClass = if conversation.after.tweets.len > 0: "thread thread-line" else: "" ${renderTweet(conversation.tweet, class=afterClass)}
- #if conversation.after.len > 0: + #if conversation.after.tweets.len > 0:
- #for i, tweet in conversation.after: - ${renderTweet(tweet, last=(i == conversation.after.high))} + #for i, tweet in conversation.after.tweets: + ${renderTweet(tweet, last=(i == conversation.after.tweets.high))} #end for
#end if @@ -127,9 +127,15 @@
#for thread in conversation.replies:
- #for i, tweet in thread: - ${renderTweet(tweet, last=(i == thread.high))} + #for i, tweet in thread.tweets: + ${renderTweet(tweet, last=(i == thread.tweets.high and thread.more == 0))} #end for + #if thread.more != 0: + #let num = if thread.more != -1: $thread.more & " " else: "" + + #end if
#end for