Add simple job_details card support
This commit is contained in:
parent
06ab1ea2e7
commit
4dac9f0798
|
@ -12,7 +12,7 @@ proc parseGraphUser*(json: string): User =
|
||||||
if raw.data.userResult.result.unavailableReason.get("") == "Suspended":
|
if raw.data.userResult.result.unavailableReason.get("") == "Suspended":
|
||||||
return User(suspended: true)
|
return User(suspended: true)
|
||||||
|
|
||||||
result = toUser raw.data.userResult.result.legacy
|
result = raw.data.userResult.result.legacy
|
||||||
result.id = raw.data.userResult.result.restId
|
result.id = raw.data.userResult.result.restId
|
||||||
result.verified = result.verified or raw.data.userResult.result.isBlueVerified
|
result.verified = result.verified or raw.data.userResult.result.isBlueVerified
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ proc parseGraphListMembers*(json, cursor: string): Result[User] =
|
||||||
of TimelineTimelineItem:
|
of TimelineTimelineItem:
|
||||||
let userResult = entry.content.itemContent.userResults.result
|
let userResult = entry.content.itemContent.userResults.result
|
||||||
if userResult.restId.len > 0:
|
if userResult.restId.len > 0:
|
||||||
result.content.add toUser userResult.legacy
|
result.content.add userResult.legacy
|
||||||
of TimelineTimelineCursor:
|
of TimelineTimelineCursor:
|
||||||
if entry.content.cursorType == "Bottom":
|
if entry.content.cursorType == "Bottom":
|
||||||
result.bottom = entry.content.value
|
result.bottom = entry.content.value
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import std/[options, tables, strutils, strformat, sugar]
|
import std/[options, tables, strutils, strformat, sugar]
|
||||||
import jsony
|
import jsony
|
||||||
|
import user
|
||||||
import ../types/unifiedcard
|
import ../types/unifiedcard
|
||||||
from ../../types import Card, CardKind, Video
|
from ../../types import Card, CardKind, Video
|
||||||
from ../../utils import twimg, https
|
from ../../utils import twimg, https
|
||||||
|
@ -27,6 +28,14 @@ proc parseMediaDetails(data: ComponentData; card: UnifiedCard; result: var Card)
|
||||||
result.text = data.topicDetail.title
|
result.text = data.topicDetail.title
|
||||||
result.dest = "Topic"
|
result.dest = "Topic"
|
||||||
|
|
||||||
|
proc parseJobDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
||||||
|
data.destination.parseDestination(card, result)
|
||||||
|
|
||||||
|
result.kind = jobDetails
|
||||||
|
result.title = data.title
|
||||||
|
result.text = data.shortDescriptionText
|
||||||
|
result.dest = &"@{data.profileUser.username} · {data.location}"
|
||||||
|
|
||||||
proc parseAppDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
proc parseAppDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
||||||
let app = card.appStoreData[data.appId][0]
|
let app = card.appStoreData[data.appId][0]
|
||||||
|
|
||||||
|
@ -84,6 +93,8 @@ proc parseUnifiedCard*(json: string): Card =
|
||||||
component.parseMedia(card, result)
|
component.parseMedia(card, result)
|
||||||
of buttonGroup:
|
of buttonGroup:
|
||||||
discard
|
discard
|
||||||
|
of jobDetails:
|
||||||
|
component.data.parseJobDetails(card, result)
|
||||||
of ComponentType.hidden:
|
of ComponentType.hidden:
|
||||||
result.kind = CardKind.hidden
|
result.kind = CardKind.hidden
|
||||||
of ComponentType.unknown:
|
of ComponentType.unknown:
|
||||||
|
|
|
@ -68,6 +68,11 @@ proc toUser*(raw: RawUser): User =
|
||||||
|
|
||||||
result.expandUserEntities(raw)
|
result.expandUserEntities(raw)
|
||||||
|
|
||||||
|
proc parseHook*(s: string; i: var int; v: var User) =
|
||||||
|
var u: RawUser
|
||||||
|
parseHook(s, i, u)
|
||||||
|
v = toUser u
|
||||||
|
|
||||||
proc parseUser*(json: string; username=""): User =
|
proc parseUser*(json: string; username=""): User =
|
||||||
handleErrors:
|
handleErrors:
|
||||||
case error.code
|
case error.code
|
||||||
|
@ -75,7 +80,7 @@ proc parseUser*(json: string; username=""): User =
|
||||||
of userNotFound: return
|
of userNotFound: return
|
||||||
else: echo "[error - parseUser]: ", error
|
else: echo "[error - parseUser]: ", error
|
||||||
|
|
||||||
result = toUser json.fromJson(RawUser)
|
result = json.fromJson(User)
|
||||||
|
|
||||||
proc parseUsers*(json: string; after=""): Result[User] =
|
proc parseUsers*(json: string; after=""): Result[User] =
|
||||||
result = Result[User](beginning: after.len == 0)
|
result = Result[User](beginning: after.len == 0)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import options
|
import options
|
||||||
import user
|
from ../../types import User
|
||||||
|
|
||||||
type
|
type
|
||||||
GraphUser* = object
|
GraphUser* = object
|
||||||
|
@ -9,7 +9,7 @@ type
|
||||||
result*: UserResult
|
result*: UserResult
|
||||||
|
|
||||||
UserResult = object
|
UserResult = object
|
||||||
legacy*: RawUser
|
legacy*: User
|
||||||
restId*: string
|
restId*: string
|
||||||
isBlueVerified*: bool
|
isBlueVerified*: bool
|
||||||
unavailableReason*: Option[string]
|
unavailableReason*: Option[string]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import std/tables
|
import std/tables
|
||||||
import user
|
from ../../types import User
|
||||||
|
|
||||||
type
|
type
|
||||||
Search* = object
|
Search* = object
|
||||||
|
@ -7,7 +7,7 @@ type
|
||||||
timeline*: Timeline
|
timeline*: Timeline
|
||||||
|
|
||||||
GlobalObjects = object
|
GlobalObjects = object
|
||||||
users*: Table[string, RawUser]
|
users*: Table[string, User]
|
||||||
|
|
||||||
Timeline = object
|
Timeline = object
|
||||||
instructions*: seq[Instructions]
|
instructions*: seq[Instructions]
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import options, tables
|
import std/[options, tables, times]
|
||||||
from ../../types import VideoType, VideoVariant
|
import jsony
|
||||||
|
from ../../types import VideoType, VideoVariant, User
|
||||||
|
|
||||||
type
|
type
|
||||||
|
Text* = distinct string
|
||||||
|
|
||||||
UnifiedCard* = object
|
UnifiedCard* = object
|
||||||
componentObjects*: Table[string, Component]
|
componentObjects*: Table[string, Component]
|
||||||
destinationObjects*: Table[string, Destination]
|
destinationObjects*: Table[string, Destination]
|
||||||
|
@ -13,6 +16,7 @@ type
|
||||||
media
|
media
|
||||||
swipeableMedia
|
swipeableMedia
|
||||||
buttonGroup
|
buttonGroup
|
||||||
|
jobDetails
|
||||||
appStoreDetails
|
appStoreDetails
|
||||||
twitterListDetails
|
twitterListDetails
|
||||||
communityDetails
|
communityDetails
|
||||||
|
@ -29,12 +33,15 @@ type
|
||||||
appId*: string
|
appId*: string
|
||||||
mediaId*: string
|
mediaId*: string
|
||||||
destination*: string
|
destination*: string
|
||||||
|
location*: string
|
||||||
title*: Text
|
title*: Text
|
||||||
subtitle*: Text
|
subtitle*: Text
|
||||||
name*: Text
|
name*: Text
|
||||||
memberCount*: int
|
memberCount*: int
|
||||||
mediaList*: seq[MediaItem]
|
mediaList*: seq[MediaItem]
|
||||||
topicDetail*: tuple[title: Text]
|
topicDetail*: tuple[title: Text]
|
||||||
|
profileUser*: User
|
||||||
|
shortDescriptionText*: string
|
||||||
|
|
||||||
MediaItem* = object
|
MediaItem* = object
|
||||||
id*: string
|
id*: string
|
||||||
|
@ -69,12 +76,9 @@ type
|
||||||
title*: Text
|
title*: Text
|
||||||
category*: Text
|
category*: Text
|
||||||
|
|
||||||
Text = object
|
|
||||||
content: string
|
|
||||||
|
|
||||||
TypeField = Component | Destination | MediaEntity | AppStoreData
|
TypeField = Component | Destination | MediaEntity | AppStoreData
|
||||||
|
|
||||||
converter fromText*(text: Text): string = text.content
|
converter fromText*(text: Text): string = string(text)
|
||||||
|
|
||||||
proc renameHook*(v: var TypeField; fieldName: var string) =
|
proc renameHook*(v: var TypeField; fieldName: var string) =
|
||||||
if fieldName == "type":
|
if fieldName == "type":
|
||||||
|
@ -86,6 +90,7 @@ proc enumHook*(s: string; v: var ComponentType) =
|
||||||
of "media": media
|
of "media": media
|
||||||
of "swipeable_media": swipeableMedia
|
of "swipeable_media": swipeableMedia
|
||||||
of "button_group": buttonGroup
|
of "button_group": buttonGroup
|
||||||
|
of "job_details": jobDetails
|
||||||
of "app_store_details": appStoreDetails
|
of "app_store_details": appStoreDetails
|
||||||
of "twitter_list_details": twitterListDetails
|
of "twitter_list_details": twitterListDetails
|
||||||
of "community_details": communityDetails
|
of "community_details": communityDetails
|
||||||
|
@ -106,3 +111,18 @@ proc enumHook*(s: string; v: var MediaType) =
|
||||||
of "photo": photo
|
of "photo": photo
|
||||||
of "model3d": model3d
|
of "model3d": model3d
|
||||||
else: echo "ERROR: Unknown enum value (MediaType): ", s; photo
|
else: echo "ERROR: Unknown enum value (MediaType): ", s; photo
|
||||||
|
|
||||||
|
proc parseHook*(s: string; i: var int; v: var DateTime) =
|
||||||
|
var str: string
|
||||||
|
parseHook(s, i, str)
|
||||||
|
v = parse(str, "yyyy-MM-dd hh:mm:ss")
|
||||||
|
|
||||||
|
proc parseHook*(s: string; i: var int; v: var Text) =
|
||||||
|
if s[i] == '"':
|
||||||
|
var str: string
|
||||||
|
parseHook(s, i, str)
|
||||||
|
v = Text(str)
|
||||||
|
else:
|
||||||
|
var t: tuple[content: string]
|
||||||
|
parseHook(s, i, t)
|
||||||
|
v = Text(t.content)
|
||||||
|
|
|
@ -219,8 +219,6 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet =
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
result.expandTweetEntities(js)
|
|
||||||
|
|
||||||
# fix for pinned threads
|
# fix for pinned threads
|
||||||
if result.hasThread and result.threadId == 0:
|
if result.hasThread and result.threadId == 0:
|
||||||
result.threadId = js{"self_thread", "id_str"}.getId
|
result.threadId = js{"self_thread", "id_str"}.getId
|
||||||
|
@ -254,6 +252,8 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet =
|
||||||
else:
|
else:
|
||||||
result.card = some parseCard(jsCard, js{"entities", "urls"})
|
result.card = some parseCard(jsCard, js{"entities", "urls"})
|
||||||
|
|
||||||
|
result.expandTweetEntities(js)
|
||||||
|
|
||||||
with jsMedia, js{"extended_entities", "media"}:
|
with jsMedia, js{"extended_entities", "media"}:
|
||||||
for m in jsMedia:
|
for m in jsMedia:
|
||||||
case m{"type"}.getStr
|
case m{"type"}.getStr
|
||||||
|
|
|
@ -246,7 +246,7 @@ proc expandUserEntities*(user: var User; js: JsonNode) =
|
||||||
.replacef(htRegex, htReplace)
|
.replacef(htRegex, htReplace)
|
||||||
|
|
||||||
proc expandTextEntities(tweet: Tweet; entities: JsonNode; text: string; textSlice: Slice[int];
|
proc expandTextEntities(tweet: Tweet; entities: JsonNode; text: string; textSlice: Slice[int];
|
||||||
replyTo=""; hasQuote=false) =
|
replyTo=""; hasRedundantLink=false) =
|
||||||
let hasCard = tweet.card.isSome
|
let hasCard = tweet.card.isSome
|
||||||
|
|
||||||
var replacements = newSeq[ReplaceSlice]()
|
var replacements = newSeq[ReplaceSlice]()
|
||||||
|
@ -257,7 +257,7 @@ proc expandTextEntities(tweet: Tweet; entities: JsonNode; text: string; textSlic
|
||||||
if urlStr.len == 0 or urlStr notin text:
|
if urlStr.len == 0 or urlStr notin text:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
replacements.extractUrls(u, textSlice.b, hideTwitter = hasQuote)
|
replacements.extractUrls(u, textSlice.b, hideTwitter = hasRedundantLink)
|
||||||
|
|
||||||
if hasCard and u{"url"}.getStr == get(tweet.card).url:
|
if hasCard and u{"url"}.getStr == get(tweet.card).url:
|
||||||
get(tweet.card).url = u{"expanded_url"}.getStr
|
get(tweet.card).url = u{"expanded_url"}.getStr
|
||||||
|
@ -297,9 +297,10 @@ proc expandTextEntities(tweet: Tweet; entities: JsonNode; text: string; textSlic
|
||||||
proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
||||||
let
|
let
|
||||||
entities = ? js{"entities"}
|
entities = ? js{"entities"}
|
||||||
hasQuote = js{"is_quote_status"}.getBool
|
|
||||||
textRange = js{"display_text_range"}
|
textRange = js{"display_text_range"}
|
||||||
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
||||||
|
hasQuote = js{"is_quote_status"}.getBool
|
||||||
|
hasJobCard = tweet.card.isSome and get(tweet.card).kind == jobDetails
|
||||||
|
|
||||||
var replyTo = ""
|
var replyTo = ""
|
||||||
if tweet.replyId != 0:
|
if tweet.replyId != 0:
|
||||||
|
@ -307,7 +308,7 @@ proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
||||||
replyTo = reply.getStr
|
replyTo = reply.getStr
|
||||||
tweet.reply.add replyTo
|
tweet.reply.add replyTo
|
||||||
|
|
||||||
tweet.expandTextEntities(entities, tweet.text, textSlice, replyTo, hasQuote)
|
tweet.expandTextEntities(entities, tweet.text, textSlice, replyTo, hasQuote or hasJobCard)
|
||||||
|
|
||||||
proc expandNoteTweetEntities*(tweet: Tweet; js: JsonNode) =
|
proc expandNoteTweetEntities*(tweet: Tweet; js: JsonNode) =
|
||||||
let
|
let
|
||||||
|
|
|
@ -162,6 +162,7 @@ type
|
||||||
imageDirectMessage = "image_direct_message"
|
imageDirectMessage = "image_direct_message"
|
||||||
audiospace = "audiospace"
|
audiospace = "audiospace"
|
||||||
newsletterPublication = "newsletter_publication"
|
newsletterPublication = "newsletter_publication"
|
||||||
|
jobDetails = "job_details"
|
||||||
hidden
|
hidden
|
||||||
unknown
|
unknown
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ const
|
||||||
"twimg.com",
|
"twimg.com",
|
||||||
"abs.twimg.com",
|
"abs.twimg.com",
|
||||||
"pbs.twimg.com",
|
"pbs.twimg.com",
|
||||||
"video.twimg.com"
|
"video.twimg.com",
|
||||||
|
"x.com"
|
||||||
]
|
]
|
||||||
|
|
||||||
proc setHmacKey*(key: string) =
|
proc setHmacKey*(key: string) =
|
||||||
|
@ -57,4 +58,4 @@ proc isTwitterUrl*(uri: Uri): bool =
|
||||||
uri.hostname in twitterDomains
|
uri.hostname in twitterDomains
|
||||||
|
|
||||||
proc isTwitterUrl*(url: string): bool =
|
proc isTwitterUrl*(url: string): bool =
|
||||||
parseUri(url).hostname in twitterDomains
|
isTwitterUrl(parseUri(url))
|
||||||
|
|
Loading…
Reference in New Issue