From 90b664ffb7c3b74de4475078b5e6e4c77cce7806 Mon Sep 17 00:00:00 2001 From: Zed Date: Sat, 14 Feb 2026 02:19:53 +0100 Subject: [PATCH] Make "Tweet unavailable" clickable and consistent --- src/parser.nim | 32 ++++++++++++++++++++------------ src/parserutils.nim | 1 - src/sass/tweet/quote.scss | 1 + src/views/timeline.nim | 8 +++----- src/views/tweet.nim | 10 +++------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/parser.nim b/src/parser.nim index f6b2ee7..c4e25a6 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -417,21 +417,21 @@ proc parseGraphTweet(js: JsonNode): Tweet = parseMediaEntities(js, result) - if result.quote.isSome: - result.quote = some(parseGraphTweet(js{"quoted_status_result", "result"})) - - with quoted, js{"quotedPostResults", "result"}: + with quoted, js{"quoted_status_result", "result"}: result.quote = some(parseGraphTweet(quoted)) + with quoted, js{"quotedPostResults"}: + if "result" in quoted: + result.quote = some(parseGraphTweet(quoted{"result"})) + else: + result.quote = some Tweet(id: js{"legacy", "quoted_status_id_str"}.getId) + proc parseGraphThread(js: JsonNode): tuple[thread: Chain; self: bool] = for t in ? js{"content", "items"}: let entryId = t.getEntryId - if "cursor-showmore" in entryId: - let cursor = t{"item", "content", "value"} - result.thread.cursor = cursor.getStr - result.thread.hasMore = true - elif "tweet" in entryId and "promoted" notin entryId: - with tweet, t.getTweetResult("item"): + if "tweet-" in entryId and "promoted" notin entryId: + let tweet = t.getTweetResult("item") + if not tweet.isNull: result.thread.content.add parseGraphTweet(tweet) let tweetDisplayType = select( @@ -440,6 +440,12 @@ proc parseGraphThread(js: JsonNode): tuple[thread: Chain; self: bool] = ) if tweetDisplayType.getStr == "SelfThread": result.self = true + else: + result.thread.content.add Tweet(id: entryId.getId) + elif "cursor-showmore" in entryId: + let cursor = t{"item", "content", "value"} + result.thread.cursor = cursor.getStr + result.thread.hasMore = true proc parseGraphTweetResult*(js: JsonNode): Tweet = with tweet, js{"data", "tweet_result", "result"}: @@ -460,7 +466,7 @@ proc parseGraphConversation*(js: JsonNode; tweetId: string): Conversation = if i.getTypeName == "TimelineAddEntries": for e in i{"entries"}: let entryId = e.getEntryId - if entryId.startsWith("tweet"): + if entryId.startsWith("tweet-"): let tweetResult = getTweetResult(e) if tweetResult.notNull: let tweet = parseGraphTweet(tweetResult) @@ -468,10 +474,12 @@ proc parseGraphConversation*(js: JsonNode; tweetId: string): Conversation = if not tweet.available: tweet.id = entryId.getId - if $tweet.id == tweetId: + if entryId.endsWith(tweetId): result.tweet = tweet else: result.before.content.add tweet + elif not entryId.endsWith(tweetId): + result.before.content.add Tweet(id: entryId.getId) elif entryId.startsWith("conversationthread"): let (thread, self) = parseGraphThread(e) if self: diff --git a/src/parserutils.nim b/src/parserutils.nim index 426d025..08b3cf8 100644 --- a/src/parserutils.nim +++ b/src/parserutils.nim @@ -72,7 +72,6 @@ template getTypeName*(js: JsonNode): string = template getEntryId*(e: JsonNode): string = e{"entryId"}.getStr(e{"entry_id"}.getStr) - template parseTime(time: string; f: static string; flen: int): DateTime = if time.len != flen: return parse(time, f, utc()) diff --git a/src/sass/tweet/quote.scss b/src/sass/tweet/quote.scss index 1db4f7e..5894735 100644 --- a/src/sass/tweet/quote.scss +++ b/src/sass/tweet/quote.scss @@ -43,6 +43,7 @@ .unavailable-quote { padding: 12px; + display: block; } .quote-link { diff --git a/src/views/timeline.nim b/src/views/timeline.nim index fee45bc..317b7e3 100644 --- a/src/views/timeline.nim +++ b/src/views/timeline.nim @@ -53,7 +53,7 @@ proc renderThread(thread: Tweets; prefs: Prefs; path: string): VNode = let show = i == thread.high and sortedThread[0].id != tweet.threadId let header = if tweet.pinned or tweet.retweet.isSome: "with-header " else: "" renderTweet(tweet, prefs, path, class=(header & "thread"), - index=i, last=(i == thread.high), showThread=show) + index=i, last=(i == thread.high)) proc renderUser(user: User; prefs: Prefs): VNode = buildHtml(tdiv(class="timeline-item", data-username=user.username)): @@ -96,7 +96,7 @@ proc renderTimelineTweets*(results: Timeline; prefs: Prefs; path: string; if not prefs.hidePins and pinned.isSome: let tweet = get pinned - renderTweet(tweet, prefs, path, showThread=tweet.hasThread) + renderTweet(tweet, prefs, path) if results.content.len == 0: if not results.beginning: @@ -116,11 +116,9 @@ proc renderTimelineTweets*(results: Timeline; prefs: Prefs; path: string; tweet.pinned and prefs.hidePins: continue - var hasThread = tweet.hasThread if retweetId != 0 and tweet.retweet.isSome: retweets &= retweetId - hasThread = get(tweet.retweet).hasThread - renderTweet(tweet, prefs, path, showThread=hasThread) + renderTweet(tweet, prefs, path) else: renderThread(thread, prefs, path) diff --git a/src/views/tweet.nim b/src/views/tweet.nim index 9263539..0c6c6a1 100644 --- a/src/views/tweet.nim +++ b/src/views/tweet.nim @@ -223,7 +223,7 @@ proc renderQuoteMedia(quote: Tweet; prefs: Prefs; path: string): VNode = proc renderQuote(quote: Tweet; prefs: Prefs; path: string): VNode = if not quote.available: return buildHtml(tdiv(class="quote unavailable")): - tdiv(class="unavailable-quote"): + a(class="unavailable-quote", href=getLink(quote, focus=false)): if quote.tombstone.len > 0: text quote.tombstone elif quote.text.len > 0: @@ -271,14 +271,14 @@ proc renderLocation*(tweet: Tweet): string = return $node proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0; - last=false; showThread=false; mainTweet=false; afterTweet=false): VNode = + last=false; mainTweet=false; afterTweet=false): VNode = var divClass = class if index == -1 or last: divClass = "thread-last " & class if not tweet.available: return buildHtml(tdiv(class=divClass & "unavailable timeline-item", data-username=tweet.user.username)): - tdiv(class="unavailable-box"): + a(class="unavailable-box", href=getLink(tweet)): if tweet.tombstone.len > 0: text tweet.tombstone elif tweet.text.len > 0: @@ -345,10 +345,6 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0; if not prefs.hideTweetStats: renderStats(tweet.stats) - if showThread: - a(class="show-thread", href=("/i/status/" & $tweet.threadId)): - text "Show this thread" - proc renderTweetEmbed*(tweet: Tweet; path: string; prefs: Prefs; cfg: Config; req: Request): string = let node = buildHtml(html(lang="en")): renderHead(prefs, cfg, req)