Add photo rail support
This commit is contained in:
19
src/api.nim
19
src/api.nim
@@ -15,6 +15,7 @@ const
|
||||
|
||||
timelineUrl = "i/profiles/show/$1/timeline/tweets"
|
||||
timelineSearchUrl = "i/search/timeline"
|
||||
timelineMediaUrl = "i/profiles/show/$1/media_timeline"
|
||||
profilePopupUrl = "i/profiles/popup"
|
||||
profileIntentUrl = "intent/user"
|
||||
tweetUrl = "status"
|
||||
@@ -162,6 +163,24 @@ proc getConversationPolls*(convo: Conversation) {.async.} =
|
||||
futs.add convo.replies.map(getPolls)
|
||||
await all(futs)
|
||||
|
||||
proc getPhotoRail*(username: string): Future[seq[GalleryPhoto]] {.async.} =
|
||||
let headers = newHttpHeaders({
|
||||
"Accept": jsonAccept,
|
||||
"Referer": $(base / username),
|
||||
"User-Agent": agent,
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
})
|
||||
|
||||
let params = {
|
||||
"for_photo_rail": "true",
|
||||
"oldest_unread_id": "0"
|
||||
}
|
||||
|
||||
let url = base / (timelineMediaUrl % username) ? params
|
||||
let html = await fetchHtml(url, headers, jsonKey="items_html")
|
||||
|
||||
result = parsePhotoRail(html)
|
||||
|
||||
proc getProfileFallback(username: string; headers: HttpHeaders): Future[Profile] {.async.} =
|
||||
let url = base / profileIntentUrl ? {"screen_name": username}
|
||||
let html = await fetchHtml(url, headers)
|
||||
|
||||
@@ -12,10 +12,11 @@ proc showTimeline(name, after: string; query: Option[Query]): Future[string] {.a
|
||||
let
|
||||
username = name.strip(chars={'/'})
|
||||
profileFut = getCachedProfile(username)
|
||||
railFut = getPhotoRail(username)
|
||||
|
||||
var timelineFut: Future[Timeline]
|
||||
if query.isNone:
|
||||
timelineFut = getTimeline(username, after)
|
||||
timelineFut = getTimeline(username, after)
|
||||
else:
|
||||
timelineFut = getTimelineSearch(username, after, get(query))
|
||||
|
||||
@@ -23,7 +24,7 @@ proc showTimeline(name, after: string; query: Option[Query]): Future[string] {.a
|
||||
if profile.username.len == 0:
|
||||
return ""
|
||||
|
||||
let profileHtml = renderProfile(profile, await timelineFut, after.len == 0)
|
||||
let profileHtml = renderProfile(profile, await timelineFut, await railFut, after.len == 0)
|
||||
return renderMain(profileHtml, title=pageTitle(profile))
|
||||
|
||||
template respTimeline(timeline: typed) =
|
||||
|
||||
@@ -163,3 +163,11 @@ proc parsePoll*(node: XmlNode): Poll =
|
||||
if n > highest:
|
||||
highest = n
|
||||
result.leader = i
|
||||
|
||||
proc parsePhotoRail*(node: XmlNode): seq[GalleryPhoto] =
|
||||
for img in node.selectAll(".tweet-media-img-placeholder"):
|
||||
result.add GalleryPhoto(
|
||||
url: img.attr("data-image-url"),
|
||||
tweetId: img.attr("data-tweet-id"),
|
||||
color: img.attr("background-color").replace("style", "background-color")
|
||||
)
|
||||
|
||||
@@ -57,6 +57,11 @@ type
|
||||
url*: string
|
||||
thumb*: string
|
||||
|
||||
GalleryPhoto* = object
|
||||
url*: string
|
||||
tweetId*: string
|
||||
color*: string
|
||||
|
||||
Poll* = object
|
||||
options*: seq[string]
|
||||
values*: seq[int]
|
||||
|
||||
@@ -41,6 +41,23 @@
|
||||
</div>
|
||||
#end proc
|
||||
#
|
||||
#proc renderPhotoRail(username: string; photoRail: seq[GalleryPhoto]): string =
|
||||
<div class="photo-rail-card">
|
||||
<div class="photo-rail-heading">
|
||||
<a href="/${username}/media">🖼 Photos and videos</a>
|
||||
</div>
|
||||
<div class="photo-rail-grid">
|
||||
#for i, photo in photoRail:
|
||||
#if i == 20: break
|
||||
#end if
|
||||
<a href="/${username}/status/${photo.tweetId}" style="${photo.color}">
|
||||
<img src=${getSigUrl(photo.url & ":thumb", "pic")}></img>
|
||||
</a>
|
||||
#end for
|
||||
</div>
|
||||
</div>
|
||||
#end proc
|
||||
#
|
||||
#proc renderBanner(profile: Profile): string =
|
||||
#if "#" in profile.banner:
|
||||
<div style="${profile.banner}" class="profile-banner-color"></div>
|
||||
@@ -90,13 +107,17 @@
|
||||
</div>
|
||||
#end proc
|
||||
#
|
||||
#proc renderProfile*(profile: Profile; timeline: Timeline; beginning: bool): string =
|
||||
#proc renderProfile*(profile: Profile; timeline: Timeline;
|
||||
# photoRail: seq[GalleryPhoto]; beginning: bool): string =
|
||||
<div class="profile-tabs">
|
||||
<div class="profile-banner">
|
||||
${renderBanner(profile)}
|
||||
</div>
|
||||
<div class="profile-tab">
|
||||
${renderProfileCard(profile)}
|
||||
#if photoRail.len > 0:
|
||||
${renderPhotoRail(profile.username, photoRail)}
|
||||
#end if
|
||||
</div>
|
||||
<div class="timeline-tab">
|
||||
#let link = "/" & profile.username
|
||||
|
||||
Reference in New Issue
Block a user