mirror of
https://github.com/zedeus/nitter
synced 2026-09-05 14:49:32 +00:00
parent
4b3ad16cc8
commit
7f7092fbf5
7 changed files with 38 additions and 9 deletions
|
|
@ -61,6 +61,7 @@ proc parseGraphArticle*(json: string): Article =
|
||||||
of "MEDIA":
|
of "MEDIA":
|
||||||
for mi in entry.value.data.mediaItems:
|
for mi in entry.value.data.mediaItems:
|
||||||
entity.mediaIds.add mi.mediaId
|
entity.mediaIds.add mi.mediaId
|
||||||
|
entity.caption = entry.value.data.caption
|
||||||
of "TWEET": entity.tweetId = entry.value.data.tweetId
|
of "TWEET": entity.tweetId = entry.value.data.tweetId
|
||||||
of "MARKDOWN": entity.markdown = entry.value.data.markdown
|
of "MARKDOWN": entity.markdown = entry.value.data.markdown
|
||||||
else: discard
|
else: discard
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ type
|
||||||
mediaItems*: seq[tuple[mediaId: string]]
|
mediaItems*: seq[tuple[mediaId: string]]
|
||||||
tweetId*: string
|
tweetId*: string
|
||||||
markdown*: string
|
markdown*: string
|
||||||
|
caption*: string
|
||||||
|
|
||||||
RawMediaEntity* = object
|
RawMediaEntity* = object
|
||||||
mediaId*: string
|
mediaId*: string
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,12 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.article-media-caption {
|
||||||
|
color: var(--fg_faded);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> a,
|
> a,
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,7 @@ type
|
||||||
mediaIds*: seq[string]
|
mediaIds*: seq[string]
|
||||||
tweetId*: string
|
tweetId*: string
|
||||||
markdown*: string
|
markdown*: string
|
||||||
|
caption*: string
|
||||||
|
|
||||||
ArticleMedia* = object
|
ArticleMedia* = object
|
||||||
kind*: string
|
kind*: string
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,9 @@ proc renderAtomicParagraph(paragraph: ArticleParagraph; article: Article;
|
||||||
video(src=getVidUrl(media.url), controls="")
|
video(src=getVidUrl(media.url), controls="")
|
||||||
else:
|
else:
|
||||||
a(href=getOrigPicUrl(media.url), target="_blank"):
|
a(href=getOrigPicUrl(media.url), target="_blank"):
|
||||||
img(src=getSmallPic(media.url), alt="", loading="lazy")
|
img(src=getSmallPic(media.url), alt=entity.caption, loading="lazy")
|
||||||
|
if entity.caption.len > 0:
|
||||||
|
p(class="article-media-caption"): text entity.caption
|
||||||
of "TWEET":
|
of "TWEET":
|
||||||
let tweet = tweets.getOrDefault(
|
let tweet = tweets.getOrDefault(
|
||||||
try: parseBiggestInt(entity.tweetId)
|
try: parseBiggestInt(entity.tweetId)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
||||||
let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
|
let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
|
||||||
|
|
||||||
buildHtml(head):
|
buildHtml(head):
|
||||||
link(rel="stylesheet", type="text/css", href="/css/style.css?v=44")
|
link(rel="stylesheet", type="text/css", href="/css/style.css?v=45")
|
||||||
link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=7")
|
link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=7")
|
||||||
|
|
||||||
if theme.len > 0:
|
if theme.len > 0:
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class ArticleSelectors:
|
||||||
avatar = '.article-author img.avatar'
|
avatar = '.article-author img.avatar'
|
||||||
verified = '.article-author .verified-icon'
|
verified = '.article-author .verified-icon'
|
||||||
media = '.article-media'
|
media = '.article-media'
|
||||||
|
caption = '.article-media-caption'
|
||||||
divider = '.article-divider'
|
divider = '.article-divider'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,10 +31,6 @@ articles = [
|
||||||
'Consciousness and AI: The Problem of Inner Experience',
|
'Consciousness and AI: The Problem of Inner Experience',
|
||||||
'CosmicOrFun', 'Cosmic Orphan'],
|
'CosmicOrFun', 'Cosmic Orphan'],
|
||||||
|
|
||||||
['2064696491948777658',
|
|
||||||
'NC Push for Data Centers + Stablecoin Crypto= Data Centers are defacto BAILOUT OF Fed Reserve System',
|
|
||||||
'June_12_1776', 'June_12_1776'],
|
|
||||||
|
|
||||||
['2064755789391110154',
|
['2064755789391110154',
|
||||||
'DeFi Markets Update 2026-06-10',
|
'DeFi Markets Update 2026-06-10',
|
||||||
'SteakhouseFi', 'Steakhouse Financial'],
|
'SteakhouseFi', 'Steakhouse Financial'],
|
||||||
|
|
@ -126,11 +123,11 @@ class ArticleContentTest(BaseTestCase):
|
||||||
self.assertGreater(len(italic), 0)
|
self.assertGreater(len(italic), 0)
|
||||||
|
|
||||||
def test_article_has_blockquotes(self):
|
def test_article_has_blockquotes(self):
|
||||||
self.open_nitter('i/article/2064696491948777658')
|
self.open_nitter('i/article/2064166507438059759')
|
||||||
self.assert_element_visible('.article-body blockquote')
|
self.assert_element_visible('.article-body blockquote')
|
||||||
|
|
||||||
def test_article_has_lists(self):
|
def test_article_has_lists(self):
|
||||||
self.open_nitter('i/article/2064696491948777658')
|
self.open_nitter('i/article/2064166507438059759')
|
||||||
self.assert_element_visible('.article-body ul')
|
self.assert_element_visible('.article-body ul')
|
||||||
|
|
||||||
def test_article_has_emoji_text(self):
|
def test_article_has_emoji_text(self):
|
||||||
|
|
@ -186,6 +183,27 @@ class ArticleMediaTest(BaseTestCase):
|
||||||
tweets = self.find_elements('.article-body .timeline-item')
|
tweets = self.find_elements('.article-body .timeline-item')
|
||||||
self.assertGreaterEqual(len(tweets), 3)
|
self.assertGreaterEqual(len(tweets), 3)
|
||||||
|
|
||||||
|
def test_media_caption_displayed(self):
|
||||||
|
self.open_nitter('i/article/2064689664213041529')
|
||||||
|
self.assert_element_visible(ArticleSelectors.caption)
|
||||||
|
captions = self.find_elements(ArticleSelectors.caption)
|
||||||
|
self.assertGreaterEqual(len(captions), 5)
|
||||||
|
|
||||||
|
def test_media_caption_text(self):
|
||||||
|
self.open_nitter('i/article/2064689664213041529')
|
||||||
|
self.assert_text_visible('FIGURE 1', ArticleSelectors.caption)
|
||||||
|
|
||||||
|
def test_media_caption_alt_attribute(self):
|
||||||
|
self.open_nitter('i/article/2064689664213041529')
|
||||||
|
img = self.find_element(f'{ArticleSelectors.media} img')
|
||||||
|
alt = img.get_attribute('alt')
|
||||||
|
self.assertGreater(len(alt), 0)
|
||||||
|
|
||||||
|
def test_no_caption_when_absent(self):
|
||||||
|
self.open_nitter('i/article/2062858677149675788')
|
||||||
|
captions = self.find_elements(ArticleSelectors.caption)
|
||||||
|
self.assertEqual(len(captions), 0)
|
||||||
|
|
||||||
|
|
||||||
class ArticleMentionTest(BaseTestCase):
|
class ArticleMentionTest(BaseTestCase):
|
||||||
def test_mention_linkified(self):
|
def test_mention_linkified(self):
|
||||||
|
|
@ -209,7 +227,7 @@ class ArticleMentionTest(BaseTestCase):
|
||||||
|
|
||||||
def test_no_spurious_whitespace_in_styled_paragraph(self):
|
def test_no_spurious_whitespace_in_styled_paragraph(self):
|
||||||
"""Styled paragraphs should not have extra whitespace from VNode serialization."""
|
"""Styled paragraphs should not have extra whitespace from VNode serialization."""
|
||||||
self.open_nitter('i/article/2064696491948777658')
|
self.open_nitter('i/article/2064166507438059759')
|
||||||
source = self.get_page_source()
|
source = self.get_page_source()
|
||||||
self.assertNotIn('white-space: pre-wrap', source)
|
self.assertNotIn('white-space: pre-wrap', source)
|
||||||
self.assertNotIn('white-space:pre-wrap', source)
|
self.assertNotIn('white-space:pre-wrap', source)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue