diff --git a/src/formatters.nim b/src/formatters.nim index 1105de5..06620d0 100644 --- a/src/formatters.nim +++ b/src/formatters.nim @@ -107,3 +107,6 @@ proc getTime*(tweet: Tweet): string = proc getLink*(tweet: Tweet | Quote): string = &"/{tweet.profile.username}/status/{tweet.id}" + +proc getTombstone*(text: string): string = + text.replace(re"\n* *Learn more", "").stripText().strip(chars={' ', '\n'}) diff --git a/src/parser.nim b/src/parser.nim index a137b9e..fa29be2 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -78,8 +78,11 @@ proc parseQuote*(quote: XmlNode): Quote = result.getQuoteMedia(quote) proc parseTweet*(node: XmlNode): Tweet = + if "withheld" in node.attr("class"): + return Tweet(tombstone: getTombstone(node.selectText(".Tombstone-label"))) + let tweet = node.select(".tweet") - if tweet == nil or "withheld-tweet" in tweet.attr("class"): + if tweet == nil: return Tweet() result = Tweet( @@ -113,7 +116,8 @@ proc parseTweet*(node: XmlNode): Tweet = let tombstone = tweet.select(".Tombstone") if tombstone != nil: if "unavailable" in tombstone.innerText(): - result.quote = some(Quote()) + let quote = Quote(tombstone: getTombstone(node.selectText(".Tombstone-label"))) + result.quote = some(quote) proc parseThread*(nodes: XmlNode): Thread = if nodes == nil: return @@ -128,8 +132,13 @@ proc parseThread*(nodes: XmlNode): Thread = result.content.add parseTweet(n) proc parseConversation*(node: XmlNode): Conversation = + let tweet = node.select(".permalink-tweet-container") + + if tweet == nil: + return Conversation(tweet: parseTweet(node.select(".permalink-tweet-withheld"))) + result = Conversation( - tweet: parseTweet(node.select(".permalink-tweet-container")), + tweet: parseTweet(tweet), before: parseThread(node.select(".in-reply-to .stream-items")) ) diff --git a/src/routes/timeline.nim b/src/routes/timeline.nim index c93509e..587b66e 100644 --- a/src/routes/timeline.nim +++ b/src/routes/timeline.nim @@ -100,7 +100,10 @@ proc createTimelineRouter*(cfg: Config) = let conversation = await getTweet(@"name", @"id", getAgent()) if conversation == nil or conversation.tweet.id.len == 0: - resp Http404, showError("Tweet not found", cfg.title) + if conversation.tweet.tombstone.len > 0: + resp Http404, showError(conversation.tweet.tombstone, cfg.title) + else: + resp Http404, showError("Tweet not found", cfg.title) let path = getPath() let title = pageTitle(conversation.tweet.profile) diff --git a/src/types.nim b/src/types.nim index d970cb7..cbdb213 100644 --- a/src/types.nim +++ b/src/types.nim @@ -118,6 +118,7 @@ type hasThread*: bool sensitive*: bool available*: bool + tombstone*: string thumb*: string badge*: string @@ -139,8 +140,9 @@ type shortTime*: string reply*: seq[string] pinned*: bool - available*: bool hasThread*: bool + available*: bool + tombstone*: string stats*: TweetStats retweet*: Option[Retweet] quote*: Option[Quote] diff --git a/src/views/tweet.nim b/src/views/tweet.nim index 8a8ef2a..b202005 100644 --- a/src/views/tweet.nim +++ b/src/views/tweet.nim @@ -191,7 +191,10 @@ proc renderQuote(quote: Quote; prefs: Prefs): VNode = if not quote.available: return buildHtml(tdiv(class="quote unavailable")): tdiv(class="unavailable-quote"): - text "This tweet is unavailable" + if quote.tombstone.len > 0: + text quote.tombstone + else: + text "This tweet is unavailable" buildHtml(tdiv(class="quote")): a(class="quote-link", href=getLink(quote)) @@ -223,7 +226,10 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; return buildHtml(tdiv(class=divClass)): tdiv(class="status-el unavailable"): tdiv(class="unavailable-box"): - text "This tweet is unavailable" + if tweet.tombstone.len > 0: + text tweet.tombstone + else: + text "This tweet is unavailable" buildHtml(tdiv(class=divClass)): tdiv(class="status-el"):