2019-06-23 23:34:30 +00:00
|
|
|
import xmltree, sequtils, strtabs, strutils, strformat
|
|
|
|
import nimquery
|
2019-06-20 14:16:20 +00:00
|
|
|
|
2019-06-23 23:34:30 +00:00
|
|
|
import ./types, ./parserutils
|
2019-06-20 14:16:20 +00:00
|
|
|
|
2019-06-21 00:15:46 +00:00
|
|
|
proc parsePopupProfile*(node: XmlNode): Profile =
|
2019-06-20 14:16:20 +00:00
|
|
|
let profile = node.querySelector(".profile-card")
|
2019-06-21 00:15:46 +00:00
|
|
|
if profile.isNil: return
|
|
|
|
|
|
|
|
result = Profile(
|
2019-06-23 23:34:30 +00:00
|
|
|
fullname: profile.getName(".fullname"),
|
|
|
|
username: profile.getUsername(".username"),
|
|
|
|
description: profile.getBio(".bio"),
|
|
|
|
userpic: profile.getAvatar(".ProfileCard-avatarImage"),
|
|
|
|
verified: isVerified(profile),
|
|
|
|
protected: isProtected(profile),
|
|
|
|
banner: getBanner(profile)
|
2019-06-21 00:15:46 +00:00
|
|
|
)
|
2019-06-23 23:34:30 +00:00
|
|
|
result.getPopupStats(profile)
|
2019-06-20 14:16:20 +00:00
|
|
|
|
2019-06-21 00:15:46 +00:00
|
|
|
proc parseIntentProfile*(profile: XmlNode): Profile =
|
|
|
|
result = Profile(
|
2019-06-23 23:34:30 +00:00
|
|
|
fullname: profile.getName("a.fn.url.alternate-context"),
|
|
|
|
username: profile.getUsername(".nickname"),
|
|
|
|
description: profile.getBio("p.note"),
|
|
|
|
userpic: profile.querySelector(".profile.summary").getAvatar("img.photo"),
|
|
|
|
verified: not profile.querySelector("li.verified").isNil,
|
|
|
|
protected: not profile.querySelector("li.protected").isNil,
|
|
|
|
banner: getBanner(profile)
|
2019-06-21 00:15:46 +00:00
|
|
|
)
|
2019-06-23 23:34:30 +00:00
|
|
|
result.getIntentStats(profile)
|
2019-06-21 00:15:46 +00:00
|
|
|
|
|
|
|
proc parseTweetProfile*(profile: XmlNode): Profile =
|
2019-06-20 14:16:20 +00:00
|
|
|
result = Profile(
|
2019-06-21 00:15:46 +00:00
|
|
|
fullname: profile.getAttr("data-name"),
|
|
|
|
username: profile.getAttr("data-screen-name"),
|
2019-06-23 23:34:30 +00:00
|
|
|
userpic: profile.getAvatar(".avatar"),
|
|
|
|
verified: isVerified(profile)
|
|
|
|
)
|
|
|
|
|
|
|
|
proc parseQuote*(tweet: XmlNode): Tweet =
|
|
|
|
let tweet = tweet.querySelector(".QuoteTweet-innerContainer")
|
|
|
|
|
|
|
|
result = Tweet(
|
|
|
|
id: tweet.getAttr("data-item-id"),
|
|
|
|
link: tweet.getAttr("href"),
|
|
|
|
text: tweet.selectText(".QuoteTweet-text")
|
|
|
|
)
|
|
|
|
|
|
|
|
result.profile = Profile(
|
|
|
|
fullname: tweet.getAttr("data-screen-name"),
|
|
|
|
username: tweet.selectText(".QuteTweet-fullname"),
|
|
|
|
verified: isVerified(tweet)
|
2019-06-20 14:16:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
proc parseTweet*(tweet: XmlNode): Tweet =
|
2019-06-21 00:30:57 +00:00
|
|
|
result = Tweet(
|
2019-06-23 23:34:30 +00:00
|
|
|
id: tweet.getAttr("data-item-id"),
|
|
|
|
link: tweet.getAttr("data-permalink-path"),
|
|
|
|
profile: parseTweetProfile(tweet),
|
|
|
|
text: getTweetText(tweet),
|
|
|
|
time: getTimestamp(tweet),
|
|
|
|
shortTime: getShortTime(tweet),
|
|
|
|
pinned: "pinned" in tweet.getAttr("class")
|
2019-06-21 00:30:57 +00:00
|
|
|
)
|
2019-06-20 14:16:20 +00:00
|
|
|
|
2019-06-23 23:34:30 +00:00
|
|
|
result.getTweetStats(tweet)
|
|
|
|
result.getTweetMedia(tweet)
|
2019-06-20 14:16:20 +00:00
|
|
|
|
2019-06-21 00:30:57 +00:00
|
|
|
let by = tweet.selectText(".js-retweet-text > a > b")
|
|
|
|
if by.len > 0:
|
|
|
|
result.retweetBy = some(by)
|
|
|
|
|
2019-06-20 14:16:20 +00:00
|
|
|
proc parseTweets*(node: XmlNode): Tweets =
|
|
|
|
if node.isNil: return
|
|
|
|
node.querySelectorAll(".tweet").map(parseTweet)
|
|
|
|
|
|
|
|
proc parseConversation*(node: XmlNode): Conversation =
|
|
|
|
result.tweet = parseTweet(node.querySelector(".permalink-tweet-container > .tweet"))
|
2019-06-21 00:30:57 +00:00
|
|
|
result.before = parseTweets(node.querySelector(".in-reply-to"))
|
2019-06-20 14:16:20 +00:00
|
|
|
|
|
|
|
let replies = node.querySelector(".replies-to")
|
|
|
|
if replies.isNil: return
|
|
|
|
|
2019-06-21 00:30:57 +00:00
|
|
|
result.after = parseTweets(replies.querySelector(".ThreadedConversation--selfThread"))
|
2019-06-20 14:16:20 +00:00
|
|
|
|
|
|
|
for reply in replies.querySelectorAll("li > .stream-items"):
|
|
|
|
let thread = parseTweets(reply)
|
|
|
|
if not thread.anyIt(it in result.after):
|
|
|
|
result.replies.add thread
|