Misc. fixes and refactorings
This commit is contained in:
parent
c736a98614
commit
5eec0bde3d
|
@ -169,13 +169,13 @@ proc getIntentStats*(profile: var Profile; node: XmlNode) =
|
||||||
of "following": profile.following = text
|
of "following": profile.following = text
|
||||||
|
|
||||||
proc parseTweetStats*(node: XmlNode): TweetStats =
|
proc parseTweetStats*(node: XmlNode): TweetStats =
|
||||||
result = TweetStats(replies: "0", retweets: "0", likes: "0")
|
result = TweetStats()
|
||||||
for action in node.selectAll(".ProfileTweet-actionCountForAria"):
|
for action in node.selectAll(".ProfileTweet-actionCountForAria"):
|
||||||
let text = action.innerText.split()
|
let text = action.innerText.split()
|
||||||
case text[1][0 .. 2]
|
case text[1][0 .. 2]
|
||||||
of "ret": result.retweets = text[0]
|
of "ret": result.retweets = text[0].parseInt
|
||||||
of "rep": result.replies = text[0]
|
of "rep": result.replies = text[0].parseInt
|
||||||
of "lik": result.likes = text[0]
|
of "lik": result.likes = text[0].parseInt
|
||||||
|
|
||||||
proc parseTweetReply*(node: XmlNode): seq[string] =
|
proc parseTweetReply*(node: XmlNode): seq[string] =
|
||||||
let reply = node.select(".ReplyingToContextBelowAuthor")
|
let reply = node.select(".ReplyingToContextBelowAuthor")
|
||||||
|
|
|
@ -5,6 +5,7 @@ import jester
|
||||||
import router_utils
|
import router_utils
|
||||||
import ".."/[api, types, agents]
|
import ".."/[api, types, agents]
|
||||||
import ../views/[embed]
|
import ../views/[embed]
|
||||||
|
export getVideo
|
||||||
|
|
||||||
export embed
|
export embed
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import jester
|
||||||
import router_utils
|
import router_utils
|
||||||
import ".."/[query, types, api, agents]
|
import ".."/[query, types, api, agents]
|
||||||
import ../views/[general, timeline, list]
|
import ../views/[general, timeline, list]
|
||||||
|
export getListTimeline, getListMembers
|
||||||
|
|
||||||
template respList*(list, timeline: typed) =
|
template respList*(list, timeline: typed) =
|
||||||
if list.minId.len == 0:
|
if list.minId.len == 0:
|
||||||
|
|
|
@ -13,6 +13,9 @@ const m3u8Regex* = re"""url="(.+.m3u8)""""
|
||||||
|
|
||||||
proc createMediaRouter*(cfg: Config) =
|
proc createMediaRouter*(cfg: Config) =
|
||||||
router media:
|
router media:
|
||||||
|
get "/pic/?":
|
||||||
|
resp Http404
|
||||||
|
|
||||||
get "/pic/@url":
|
get "/pic/@url":
|
||||||
cond "http" in @"url"
|
cond "http" in @"url"
|
||||||
cond "twimg" in @"url"
|
cond "twimg" in @"url"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import jester
|
||||||
import router_utils
|
import router_utils
|
||||||
import ".."/[query, types, api, agents]
|
import ".."/[query, types, api, agents]
|
||||||
import ../views/general
|
import ../views/general
|
||||||
|
export resolve
|
||||||
|
|
||||||
template respResolved*(url, kind: string): untyped =
|
template respResolved*(url, kind: string): untyped =
|
||||||
let u = url
|
let u = url
|
||||||
|
|
|
@ -87,8 +87,9 @@ proc createTimelineRouter*(cfg: Config) =
|
||||||
setProfileCacheTime(cfg.profileCacheTime)
|
setProfileCacheTime(cfg.profileCacheTime)
|
||||||
|
|
||||||
router timeline:
|
router timeline:
|
||||||
get "/@name/?@tab?":
|
get "/@name/?@tab?/?":
|
||||||
cond '.' notin @"name"
|
cond '.' notin @"name"
|
||||||
|
cond @"name" notin ["pic", "gif", "video"]
|
||||||
cond @"tab" in ["with_replies", "media", "search", ""]
|
cond @"tab" in ["with_replies", "media", "search", ""]
|
||||||
let
|
let
|
||||||
prefs = cookiePrefs()
|
prefs = cookiePrefs()
|
||||||
|
|
|
@ -87,6 +87,8 @@ type
|
||||||
tweetId*: string
|
tweetId*: string
|
||||||
color*: string
|
color*: string
|
||||||
|
|
||||||
|
PhotoRail* = seq[GalleryPhoto]
|
||||||
|
|
||||||
Poll* = object
|
Poll* = object
|
||||||
options*: seq[string]
|
options*: seq[string]
|
||||||
values*: seq[int]
|
values*: seq[int]
|
||||||
|
@ -131,9 +133,9 @@ type
|
||||||
id*: int64
|
id*: int64
|
||||||
|
|
||||||
TweetStats* = object
|
TweetStats* = object
|
||||||
replies*: string
|
replies*: int
|
||||||
retweets*: string
|
retweets*: int
|
||||||
likes*: string
|
likes*: int
|
||||||
|
|
||||||
Tweet* = ref object
|
Tweet* = ref object
|
||||||
id*: int64
|
id*: int64
|
||||||
|
|
|
@ -9,7 +9,7 @@ proc renderStat(num, class: string; text=""): VNode =
|
||||||
buildHtml(li(class=class)):
|
buildHtml(li(class=class)):
|
||||||
span(class="profile-stat-header"): text capitalizeAscii(t)
|
span(class="profile-stat-header"): text capitalizeAscii(t)
|
||||||
span(class="profile-stat-num"):
|
span(class="profile-stat-num"):
|
||||||
text if num.len == 0: "?" else: num
|
text if num.len == 0: "?" else: insertSep(num, ',')
|
||||||
|
|
||||||
proc renderProfileCard*(profile: Profile; prefs: Prefs): VNode =
|
proc renderProfileCard*(profile: Profile; prefs: Prefs): VNode =
|
||||||
buildHtml(tdiv(class="profile-card")):
|
buildHtml(tdiv(class="profile-card")):
|
||||||
|
@ -57,7 +57,7 @@ proc renderProfileCard*(profile: Profile; prefs: Prefs): VNode =
|
||||||
renderStat(profile.followers, "followers")
|
renderStat(profile.followers, "followers")
|
||||||
renderStat(profile.likes, "likes")
|
renderStat(profile.likes, "likes")
|
||||||
|
|
||||||
proc renderPhotoRail(profile: Profile; photoRail: seq[GalleryPhoto]): VNode =
|
proc renderPhotoRail(profile: Profile; photoRail: PhotoRail): VNode =
|
||||||
buildHtml(tdiv(class="photo-rail-card")):
|
buildHtml(tdiv(class="photo-rail-card")):
|
||||||
tdiv(class="photo-rail-header"):
|
tdiv(class="photo-rail-header"):
|
||||||
a(href=(&"/{profile.username}/media")):
|
a(href=(&"/{profile.username}/media")):
|
||||||
|
@ -90,7 +90,7 @@ proc renderProtected(username: string): VNode =
|
||||||
p: text &"Only confirmed followers have access to @{username}'s tweets."
|
p: text &"Only confirmed followers have access to @{username}'s tweets."
|
||||||
|
|
||||||
proc renderProfile*(profile: Profile; timeline: Timeline;
|
proc renderProfile*(profile: Profile; timeline: Timeline;
|
||||||
photoRail: seq[GalleryPhoto]; prefs: Prefs; path: string): VNode =
|
photoRail: PhotoRail; prefs: Prefs; path: string): VNode =
|
||||||
timeline.query.fromUser = @[profile.username]
|
timeline.query.fromUser = @[profile.username]
|
||||||
buildHtml(tdiv(class="profile-tabs")):
|
buildHtml(tdiv(class="profile-tabs")):
|
||||||
if not prefs.hideBanner:
|
if not prefs.hideBanner:
|
||||||
|
|
|
@ -110,7 +110,7 @@ proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode =
|
||||||
|
|
||||||
proc renderGif(gif: Gif; prefs: Prefs): VNode =
|
proc renderGif(gif: Gif; prefs: Prefs): VNode =
|
||||||
buildHtml(tdiv(class="attachments media-gif")):
|
buildHtml(tdiv(class="attachments media-gif")):
|
||||||
tdiv(class="gallery-gif", style=style(maxHeight, "unset")):
|
tdiv(class="gallery-gif", style={maxHeight: "unset"}):
|
||||||
tdiv(class="attachment"):
|
tdiv(class="attachment"):
|
||||||
let thumb = getPicUrl(gif.thumb)
|
let thumb = getPicUrl(gif.thumb)
|
||||||
let url = getGifUrl(gif.url)
|
let url = getGifUrl(gif.url)
|
||||||
|
@ -124,14 +124,16 @@ proc renderGif(gif: Gif; prefs: Prefs): VNode =
|
||||||
proc renderPoll(poll: Poll): VNode =
|
proc renderPoll(poll: Poll): VNode =
|
||||||
buildHtml(tdiv(class="poll")):
|
buildHtml(tdiv(class="poll")):
|
||||||
for i in 0 ..< poll.options.len:
|
for i in 0 ..< poll.options.len:
|
||||||
let leader = if poll.leader == i: " leader" else: ""
|
let
|
||||||
let perc = $poll.values[i] & "%"
|
leader = if poll.leader == i: " leader" else: ""
|
||||||
|
perc = poll.values[i] / poll.votes * 100
|
||||||
|
percStr = (&"{perc:>3.0f}").strip(chars={'.'}) & '%'
|
||||||
tdiv(class=("poll-meter" & leader)):
|
tdiv(class=("poll-meter" & leader)):
|
||||||
span(class="poll-choice-bar", style=style(width, perc))
|
span(class="poll-choice-bar", style={width: percStr})
|
||||||
span(class="poll-choice-value"): text perc
|
span(class="poll-choice-value"): text percStr
|
||||||
span(class="poll-choice-option"): text poll.options[i]
|
span(class="poll-choice-option"): text poll.options[i]
|
||||||
span(class="poll-info"):
|
span(class="poll-info"):
|
||||||
text $poll.votes & " votes • " & poll.status
|
text insertSep($poll.votes, ',') & " votes • " & poll.status
|
||||||
|
|
||||||
proc renderCardImage(card: Card): VNode =
|
proc renderCardImage(card: Card): VNode =
|
||||||
buildHtml(tdiv(class="card-image-container")):
|
buildHtml(tdiv(class="card-image-container")):
|
||||||
|
@ -169,11 +171,11 @@ proc renderCard(card: Card; prefs: Prefs; path: string): VNode =
|
||||||
|
|
||||||
proc renderStats(stats: TweetStats; views: string): VNode =
|
proc renderStats(stats: TweetStats; views: string): VNode =
|
||||||
buildHtml(tdiv(class="tweet-stats")):
|
buildHtml(tdiv(class="tweet-stats")):
|
||||||
span(class="tweet-stat"): icon "comment", $stats.replies
|
span(class="tweet-stat"): icon "comment", insertSep($stats.replies, ',')
|
||||||
span(class="tweet-stat"): icon "retweet", $stats.retweets
|
span(class="tweet-stat"): icon "retweet", insertSep($stats.retweets, ',')
|
||||||
span(class="tweet-stat"): icon "heart", $stats.likes
|
span(class="tweet-stat"): icon "heart", insertSep($stats.likes, ',')
|
||||||
if views.len > 0:
|
if views.len > 0:
|
||||||
span(class="tweet-stat"): icon "play", views
|
span(class="tweet-stat"): icon "play", insertSep(views, ',')
|
||||||
|
|
||||||
proc renderReply(tweet: Tweet): VNode =
|
proc renderReply(tweet: Tweet): VNode =
|
||||||
buildHtml(tdiv(class="replying-to")):
|
buildHtml(tdiv(class="replying-to")):
|
||||||
|
@ -279,7 +281,8 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
|
||||||
var views = ""
|
var views = ""
|
||||||
renderHeader(tweet)
|
renderHeader(tweet)
|
||||||
|
|
||||||
if index == 0 and tweet.reply.len > 0:
|
if index == 0 and tweet.reply.len > 0 and
|
||||||
|
(tweet.reply.len > 1 or tweet.reply[0] != tweet.profile.username):
|
||||||
renderReply(tweet)
|
renderReply(tweet)
|
||||||
|
|
||||||
tdiv(class="tweet-content media-body", dir="auto"):
|
tdiv(class="tweet-content media-body", dir="auto"):
|
||||||
|
@ -288,9 +291,6 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
|
||||||
if tweet.attribution.isSome:
|
if tweet.attribution.isSome:
|
||||||
renderAttribution(tweet.attribution.get())
|
renderAttribution(tweet.attribution.get())
|
||||||
|
|
||||||
if tweet.quote.isSome:
|
|
||||||
renderQuote(tweet.quote.get(), prefs)
|
|
||||||
|
|
||||||
if tweet.card.isSome:
|
if tweet.card.isSome:
|
||||||
renderCard(tweet.card.get(), prefs, path)
|
renderCard(tweet.card.get(), prefs, path)
|
||||||
elif tweet.photos.len > 0:
|
elif tweet.photos.len > 0:
|
||||||
|
@ -304,6 +304,9 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
|
||||||
elif tweet.poll.isSome:
|
elif tweet.poll.isSome:
|
||||||
renderPoll(tweet.poll.get())
|
renderPoll(tweet.poll.get())
|
||||||
|
|
||||||
|
if tweet.quote.isSome:
|
||||||
|
renderQuote(tweet.quote.get(), prefs)
|
||||||
|
|
||||||
if mainTweet:
|
if mainTweet:
|
||||||
p(class="tweet-published"): text getTweetTime(tweet)
|
p(class="tweet-published"): text getTweetTime(tweet)
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ class ProfileTest(BaseTestCase):
|
||||||
|
|
||||||
def test_suspended(self):
|
def test_suspended(self):
|
||||||
self.open_nitter('test')
|
self.open_nitter('test')
|
||||||
self.assert_text(f'User "test" has been suspended')
|
self.assert_text('User "test" has been suspended')
|
||||||
|
|
||||||
@parameterized.expand(banner_color)
|
@parameterized.expand(banner_color)
|
||||||
def test_banner_color(self, username, color):
|
def test_banner_color(self, username, color):
|
||||||
|
|
Loading…
Reference in New Issue