diff --git a/src/parser.nim b/src/parser.nim index 30f70d2..0b3352c 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -710,10 +710,26 @@ proc parseGraphTweet*(js: JsonNode): Tweet = with birdwatch, js{"birdwatch_pivot"}: result.note = parseCommunityNote(birdwatch) +proc getConvSection(js: JsonNode): string = + let details = select( + js{"item", "client_event_info", "details"}, + js{"item", "clientEventInfo", "details"} + ) + select( + details{"conversation_details", "conversation_section"}, + details{"conversationDetails", "conversationSection"} + ).getStr + proc parseGraphThread(js: JsonNode): tuple[thread: Chain; self: bool] = + var checkedSection = false for t in ? js{"content", "items"}: let entryId = t.getEntryId if "tweet-" in entryId and "promoted" notin entryId: + if not checkedSection: + checkedSection = true + if getConvSection(t) == "RelatedTweet": + result.thread.related = true + let tweet = t.getTweetResult("item") if tweet.notNull: result.thread.content.add parseGraphTweet(tweet) @@ -774,7 +790,8 @@ proc parseGraphConversation*(js: JsonNode; tweetId: string): Conversation = result.before.content.add tweet elif not entryId.endsWith(tweetId): result.before.content.add Tweet(id: entryId.getId) - elif entryId.startsWith("conversationthread"): + elif entryId.startsWith("conversationthread") or + entryId.startsWith("tweetdetailrelatedtweets"): let (thread, self) = parseGraphThread(e) if self: result.after = thread diff --git a/src/prefs_impl.nim b/src/prefs_impl.nim index 699ec4c..8519bd5 100644 --- a/src/prefs_impl.nim +++ b/src/prefs_impl.nim @@ -78,6 +78,9 @@ genPrefs: hideReplies(checkbox, false): "Hide tweet replies" + hideRelated(checkbox, true): + "Hide related tweets under replies" + hideCommunityNotes(checkbox, false): "Hide community notes" diff --git a/src/sass/tweet/thread.scss b/src/sass/tweet/thread.scss index c7b50ba..134e375 100644 --- a/src/sass/tweet/thread.scss +++ b/src/sass/tweet/thread.scss @@ -185,3 +185,12 @@ } } } + +.related-header { + padding: 8px 12px; + margin-top: 10px; + background-color: var(--bg_panel); + color: var(--fg_faded); + font-size: 14px; + border-bottom: 1px solid var(--border_grey); +} diff --git a/src/types.nim b/src/types.nim index d19a10d..bb521c7 100644 --- a/src/types.nim +++ b/src/types.nim @@ -359,6 +359,7 @@ type content*: Tweets hasMore*: bool cursor*: string + related*: bool Conversation* = ref object tweet*: Tweet diff --git a/src/views/general.nim b/src/views/general.nim index afdda9f..f223251 100644 --- a/src/views/general.nim +++ b/src/views/general.nim @@ -50,7 +50,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc=""; let opensearchUrl = getUrlPrefix(cfg) & "/opensearch" buildHtml(head): - link(rel="stylesheet", type="text/css", href="/css/style.css?v=50") + link(rel="stylesheet", type="text/css", href="/css/style.css?v=51") link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=7") if theme.len > 0: diff --git a/src/views/status.nim b/src/views/status.nim index 39af8fa..b16c211 100644 --- a/src/views/status.nim +++ b/src/views/status.nim @@ -1,4 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-only +import sequtils import karax/[karaxdsl, vdom] import ".."/[types, formatters] @@ -48,7 +49,7 @@ proc renderReplies*(replies: Result[Chain]; prefs: Prefs; path: string; var hasReplies = false var replyCount = 0 for thread in replies.content: - if thread.content.len == 0: continue + if thread.content.len == 0 or thread.related: continue hasReplies = true replyCount += thread.content.len renderReplyThread(thread, prefs, path) @@ -58,6 +59,14 @@ proc renderReplies*(replies: Result[Chain]; prefs: Prefs; path: string; let extra = if sort == Relevance: "" else: "sort=" & $sort & "&" renderMore(Query(), replies.bottom, focus="#r", extra=extra) +proc renderRelated(replies: Result[Chain]; prefs: Prefs; path: string): VNode = + buildHtml(tdiv(class="related-tweets")): + tdiv(class="related-header"): + text "Related tweets" + for thread in replies.content: + if thread.content.len == 0 or not thread.related: continue + renderReplyThread(thread, prefs, path) + proc renderConversation*(conv: Conversation; prefs: Prefs; path: string; sort = Relevance): VNode = let hasAfter = conv.after.content.len > 0 @@ -95,6 +104,10 @@ proc renderConversation*(conv: Conversation; prefs: Prefs; path: string; renderReplySort(sort) renderReplies(conv.replies, prefs, path, conv.tweet, sort) + if not prefs.hideRelated: + if conv.replies.content.anyIt(it.related and it.content.len > 0): + renderRelated(conv.replies, prefs, path) + renderToTop(focus="#m") proc renderEditHistory*(edits: EditHistory; prefs: Prefs; path: string): VNode =