Display "more replies"
This commit is contained in:
parent
160c28eda3
commit
a901e50df5
6 changed files with 77 additions and 33 deletions
|
@ -505,6 +505,18 @@ video {
|
||||||
margin-bottom: 10px;
|
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 {
|
.thread-line .status-el::before {
|
||||||
background: #8a3731;
|
background: #8a3731;
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -530,6 +542,20 @@ video {
|
||||||
margin: 0;
|
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 {
|
.panel {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
font-size: 130%;
|
font-size: 130%;
|
||||||
|
|
19
src/api.nim
19
src/api.nim
|
@ -110,14 +110,14 @@ proc getVideo*(tweet: Tweet; token: string) {.async.} =
|
||||||
tweet.video = some(parseVideo(json))
|
tweet.video = some(parseVideo(json))
|
||||||
tokenUses.inc
|
tokenUses.inc
|
||||||
|
|
||||||
proc getVideos*(tweets: Tweets; token="") {.async.} =
|
proc getVideos*(thread: Thread; token="") {.async.} =
|
||||||
var gToken = token
|
var gToken = token
|
||||||
var videoFuts: seq[Future[void]]
|
var videoFuts: seq[Future[void]]
|
||||||
|
|
||||||
if gToken.len == 0:
|
if gToken.len == 0:
|
||||||
gToken = await getGuestToken()
|
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)
|
videoFuts.add getVideo(tweet, token)
|
||||||
|
|
||||||
await all(videoFuts)
|
await all(videoFuts)
|
||||||
|
@ -150,8 +150,8 @@ proc getPoll*(tweet: Tweet) {.async.} =
|
||||||
|
|
||||||
tweet.poll = some(parsePoll(html))
|
tweet.poll = some(parsePoll(html))
|
||||||
|
|
||||||
proc getPolls*(tweets: Tweets) {.async.} =
|
proc getPolls*(thread: Thread) {.async.} =
|
||||||
var polls = tweets.filterIt(it.poll.isSome)
|
var polls = thread.tweets.filterIt(it.poll.isSome)
|
||||||
await all(polls.map(getPoll))
|
await all(polls.map(getPoll))
|
||||||
|
|
||||||
proc getConversationPolls*(convo: Conversation) {.async.} =
|
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 json["new_latent_count"].to(int) == 0: return
|
||||||
if not json.hasKey("items_html"): 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)
|
await all(vidsFut, pollFut)
|
||||||
|
result.tweets = thread.tweets
|
||||||
|
|
||||||
proc getTweet*(username: string; id: string): Future[Conversation] {.async.} =
|
proc getTweet*(username: string; id: string): Future[Conversation] {.async.} =
|
||||||
let headers = newHttpHeaders({
|
let headers = newHttpHeaders({
|
||||||
|
|
|
@ -82,19 +82,21 @@ proc parseTweet*(node: XmlNode): Tweet =
|
||||||
if quote != nil:
|
if quote != nil:
|
||||||
result.quote = some(parseQuote(quote))
|
result.quote = some(parseQuote(quote))
|
||||||
|
|
||||||
proc parseTweets*(nodes: XmlNode): Tweets =
|
proc parseThread*(nodes: XmlNode): Thread =
|
||||||
if nodes == nil: return
|
if nodes == nil: return
|
||||||
for n in nodes.filterIt(it.kind != xnText):
|
for n in nodes.filterIt(it.kind != xnText):
|
||||||
let class = n.attr("class").toLower()
|
let class = n.attr("class").toLower()
|
||||||
if "tombstone" in class or "unavailable" in class:
|
if "tombstone" in class or "unavailable" in class:
|
||||||
result.add Tweet()
|
result.tweets.add Tweet()
|
||||||
elif "morereplies" notin class:
|
elif "morereplies" in class:
|
||||||
result.add parseTweet(n)
|
result.more = getMoreReplies(n)
|
||||||
|
else:
|
||||||
|
result.tweets.add parseTweet(n)
|
||||||
|
|
||||||
proc parseConversation*(node: XmlNode): Conversation =
|
proc parseConversation*(node: XmlNode): Conversation =
|
||||||
result = Conversation(
|
result = Conversation(
|
||||||
tweet: parseTweet(node.select(".permalink-tweet-container")),
|
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")
|
let replies = node.select(".replies-to .stream-items")
|
||||||
|
@ -105,11 +107,11 @@ proc parseConversation*(node: XmlNode): Conversation =
|
||||||
let thread = reply.select(".stream-items")
|
let thread = reply.select(".stream-items")
|
||||||
|
|
||||||
if "self" in class:
|
if "self" in class:
|
||||||
result.after = parseTweets(thread)
|
result.after = parseThread(thread)
|
||||||
elif "lone" in class:
|
elif "lone" in class:
|
||||||
result.replies.add parseTweets(reply)
|
result.replies.add parseThread(reply)
|
||||||
else:
|
else:
|
||||||
result.replies.add parseTweets(thread)
|
result.replies.add parseThread(thread)
|
||||||
|
|
||||||
proc parseVideo*(node: JsonNode): Video =
|
proc parseVideo*(node: JsonNode): Video =
|
||||||
let
|
let
|
||||||
|
|
|
@ -162,3 +162,10 @@ proc getTweetCards*(tweet: Tweet; node: XmlNode) =
|
||||||
if node.attr("data-has-cards") == "false": return
|
if node.attr("data-has-cards") == "false": return
|
||||||
if "poll" in node.attr("data-card2-type"):
|
if "poll" in node.attr("data-card2-type"):
|
||||||
tweet.poll = some(Poll())
|
tweet.poll = some(Poll())
|
||||||
|
|
||||||
|
proc getMoreReplies*(node: XmlNode): int =
|
||||||
|
let text = node.innerText().strip()
|
||||||
|
try:
|
||||||
|
result = parseInt(text.split(" ")[0])
|
||||||
|
except:
|
||||||
|
result = -1
|
||||||
|
|
|
@ -83,19 +83,21 @@ type
|
||||||
poll*: Option[Poll]
|
poll*: Option[Poll]
|
||||||
available*: bool
|
available*: bool
|
||||||
|
|
||||||
Tweets* = seq[Tweet]
|
Thread* = object
|
||||||
|
tweets*: seq[Tweet]
|
||||||
|
more*: int
|
||||||
|
|
||||||
Conversation* = ref object
|
Conversation* = ref object
|
||||||
tweet*: Tweet
|
tweet*: Tweet
|
||||||
before*: Tweets
|
before*: Thread
|
||||||
after*: Tweets
|
after*: Thread
|
||||||
replies*: seq[Tweets]
|
replies*: seq[Thread]
|
||||||
|
|
||||||
Timeline* = ref object
|
Timeline* = ref object
|
||||||
tweets*: Tweets
|
tweets*: seq[Tweet]
|
||||||
minId*: string
|
minId*: string
|
||||||
maxId*: string
|
maxId*: string
|
||||||
hasMore*: bool
|
hasMore*: bool
|
||||||
|
|
||||||
proc contains*(thread: Tweets; tweet: Tweet): bool =
|
proc contains*(thread: Thread; tweet: Tweet): bool =
|
||||||
thread.anyIt(it.id == tweet.id)
|
thread.tweets.anyIt(it.id == tweet.id)
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
#end proc
|
#end proc
|
||||||
#
|
#
|
||||||
#proc renderTimeline*(timeline: Timeline; profile: Profile; beginning: bool): string =
|
#proc renderTimeline*(timeline: Timeline; profile: Profile; beginning: bool): string =
|
||||||
#var retweets: Tweets
|
#var retweets: seq[Tweet]
|
||||||
<div id="tweets">
|
<div id="tweets">
|
||||||
#if not beginning:
|
#if not beginning:
|
||||||
<div class="show-more status-el">
|
<div class="show-more status-el">
|
||||||
|
@ -104,21 +104,21 @@
|
||||||
#proc renderConversation*(conversation: Conversation): string =
|
#proc renderConversation*(conversation: Conversation): string =
|
||||||
<div class="conversation" id="tweets">
|
<div class="conversation" id="tweets">
|
||||||
<div class="main-thread">
|
<div class="main-thread">
|
||||||
#if conversation.before.len > 0:
|
#if conversation.before.tweets.len > 0:
|
||||||
<div class="before-tweet thread-line">
|
<div class="before-tweet thread-line">
|
||||||
#for tweet in conversation.before:
|
#for tweet in conversation.before.tweets:
|
||||||
${renderTweet(tweet)}
|
${renderTweet(tweet)}
|
||||||
#end for
|
#end for
|
||||||
</div>
|
</div>
|
||||||
#end if
|
#end if
|
||||||
<div class="main-tweet">
|
<div class="main-tweet">
|
||||||
#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)}
|
${renderTweet(conversation.tweet, class=afterClass)}
|
||||||
</div>
|
</div>
|
||||||
#if conversation.after.len > 0:
|
#if conversation.after.tweets.len > 0:
|
||||||
<div class="after-tweet thread-line">
|
<div class="after-tweet thread-line">
|
||||||
#for i, tweet in conversation.after:
|
#for i, tweet in conversation.after.tweets:
|
||||||
${renderTweet(tweet, last=(i == conversation.after.high))}
|
${renderTweet(tweet, last=(i == conversation.after.tweets.high))}
|
||||||
#end for
|
#end for
|
||||||
</div>
|
</div>
|
||||||
#end if
|
#end if
|
||||||
|
@ -127,9 +127,15 @@
|
||||||
<div class="replies">
|
<div class="replies">
|
||||||
#for thread in conversation.replies:
|
#for thread in conversation.replies:
|
||||||
<div class="reply thread thread-line">
|
<div class="reply thread thread-line">
|
||||||
#for i, tweet in thread:
|
#for i, tweet in thread.tweets:
|
||||||
${renderTweet(tweet, last=(i == thread.high))}
|
${renderTweet(tweet, last=(i == thread.tweets.high and thread.more == 0))}
|
||||||
#end for
|
#end for
|
||||||
|
#if thread.more != 0:
|
||||||
|
#let num = if thread.more != -1: $thread.more & " " else: ""
|
||||||
|
<div class="status-el more-replies">
|
||||||
|
<a class="more-replies-text" title="Not implemented yet">${num}more replies</a>
|
||||||
|
</div>
|
||||||
|
#end if
|
||||||
</div>
|
</div>
|
||||||
#end for
|
#end for
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue