+21
-7
@@ -1,5 +1,5 @@
|
|||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import strutils, options, times, math, tables
|
import strutils, options, times, math, tables, uri
|
||||||
import packedjson, packedjson/deserialiser
|
import packedjson, packedjson/deserialiser
|
||||||
import types, parserutils, utils
|
import types, parserutils, utils
|
||||||
import experimental/parser/unifiedcard
|
import experimental/parser/unifiedcard
|
||||||
@@ -229,6 +229,10 @@ proc parseLegacyMediaEntities(js: JsonNode; result: var Tweet) =
|
|||||||
result.attribution = some(parseUser(user))
|
result.attribution = some(parseUser(user))
|
||||||
else:
|
else:
|
||||||
result.attribution = some(parseGraphUser(user))
|
result.attribution = some(parseGraphUser(user))
|
||||||
|
# Set attribution link from expanded_url (strip /video/N suffix)
|
||||||
|
let expanded = m{"expanded_url"}.getStr
|
||||||
|
if expanded.len > 0:
|
||||||
|
result.attributionLink = expanded.parseUri.path.replace("/video/1", "")
|
||||||
of "animated_gif":
|
of "animated_gif":
|
||||||
result.media.addMedia(Gif(
|
result.media.addMedia(Gif(
|
||||||
url: m{"video_info", "variants"}[0]{"url"}.getImageStr,
|
url: m{"video_info", "variants"}[0]{"url"}.getImageStr,
|
||||||
@@ -266,11 +270,9 @@ proc parseMediaEntities(js: JsonNode; result: var Tweet) =
|
|||||||
# Parse source user for video attribution
|
# Parse source user for video attribution
|
||||||
with sourceUser, mediaEntity{"source_user_results", "result"}:
|
with sourceUser, mediaEntity{"source_user_results", "result"}:
|
||||||
if result.attribution.isNone:
|
if result.attribution.isNone:
|
||||||
let
|
let expanded = mediaEntity{"expanded_url"}.getStr
|
||||||
expanded = mediaEntity{"expanded_url"}.getStr
|
if expanded.len > 0:
|
||||||
pathStart = expanded.find('/', expanded.find("://") + 3)
|
result.attributionLink = expanded.parseUri.path.replace("/video/1", "")
|
||||||
if pathStart >= 0:
|
|
||||||
result.attributionLink = expanded[pathStart .. ^1].replace("/video/1", "")
|
|
||||||
result.attribution = some(User(
|
result.attribution = some(User(
|
||||||
id: sourceUser{"rest_id"}.getStr,
|
id: sourceUser{"rest_id"}.getStr,
|
||||||
fullname: sourceUser{"core", "name"}.getStr,
|
fullname: sourceUser{"core", "name"}.getStr,
|
||||||
@@ -467,8 +469,8 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull();
|
|||||||
elif name.len > 0 and jsCard{"binding_values"}.notNull:
|
elif name.len > 0 and jsCard{"binding_values"}.notNull:
|
||||||
result.card = some parseCard(jsCard, js{"entities", "urls"})
|
result.card = some parseCard(jsCard, js{"entities", "urls"})
|
||||||
|
|
||||||
result.expandTweetEntities(js)
|
|
||||||
parseLegacyMediaEntities(js, result)
|
parseLegacyMediaEntities(js, result)
|
||||||
|
result.expandTweetEntities(js)
|
||||||
|
|
||||||
with jsWithheld, js{"withheld_in_countries"}:
|
with jsWithheld, js{"withheld_in_countries"}:
|
||||||
let withheldInCountries: seq[string] =
|
let withheldInCountries: seq[string] =
|
||||||
@@ -555,6 +557,10 @@ proc parseGraphTweet*(js: JsonNode): Tweet =
|
|||||||
elif name.len > 0 and jsCard{"binding_values"}.notNull:
|
elif name.len > 0 and jsCard{"binding_values"}.notNull:
|
||||||
result.card = some parseCard(jsCard, js{"url_entities"})
|
result.card = some parseCard(jsCard, js{"url_entities"})
|
||||||
|
|
||||||
|
parseMediaEntities(js, result)
|
||||||
|
if result.attribution.isNone:
|
||||||
|
parseLegacyMediaEntities(js{"legacy"}, result)
|
||||||
|
|
||||||
result.expandTweetEntitiesV2(js)
|
result.expandTweetEntitiesV2(js)
|
||||||
|
|
||||||
# Strip video source URL from text (for videos from other tweets)
|
# Strip video source URL from text (for videos from other tweets)
|
||||||
@@ -585,6 +591,14 @@ proc parseGraphTweet*(js: JsonNode): Tweet =
|
|||||||
|
|
||||||
parseMediaEntities(js, result)
|
parseMediaEntities(js, result)
|
||||||
|
|
||||||
|
# Hide card if it's redundant with attribution (same video shown via embed)
|
||||||
|
if result.attribution.isSome and result.card.isSome:
|
||||||
|
let cardUri = get(result.card).url.parseUri
|
||||||
|
if cardUri.isTwitterUrl:
|
||||||
|
let cardPath = cardUri.path.replace("/video/1", "")
|
||||||
|
if cardPath.len > 0 and cardPath == result.attributionLink:
|
||||||
|
get(result.card).kind = hidden
|
||||||
|
|
||||||
# Handle retweets - check both legacy and top-level paths
|
# Handle retweets - check both legacy and top-level paths
|
||||||
with reposts, js{"legacy", "repostedStatusResults"}:
|
with reposts, js{"legacy", "repostedStatusResults"}:
|
||||||
with rt, reposts{"result"}:
|
with rt, reposts{"result"}:
|
||||||
|
|||||||
+8
-3
@@ -319,6 +319,7 @@ proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
|||||||
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
||||||
hasQuote = js{"is_quote_status"}.getBool
|
hasQuote = js{"is_quote_status"}.getBool
|
||||||
hasJobCard = tweet.card.isSome and get(tweet.card).kind == jobDetails
|
hasJobCard = tweet.card.isSome and get(tweet.card).kind == jobDetails
|
||||||
|
hasAttribution = tweet.attribution.isSome
|
||||||
|
|
||||||
var replyTo = ""
|
var replyTo = ""
|
||||||
if tweet.replyId != 0:
|
if tweet.replyId != 0:
|
||||||
@@ -326,7 +327,8 @@ 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 or hasJobCard)
|
tweet.expandTextEntities(entities, tweet.text, textSlice, replyTo,
|
||||||
|
hasQuote or hasJobCard or hasAttribution)
|
||||||
|
|
||||||
proc expandTextEntitiesV2(tweet: Tweet; js: JsonNode; text: string; textSlice: Slice[int];
|
proc expandTextEntitiesV2(tweet: Tweet; js: JsonNode; text: string; textSlice: Slice[int];
|
||||||
hasRedundantLink=false) =
|
hasRedundantLink=false) =
|
||||||
@@ -377,16 +379,19 @@ proc expandTweetEntitiesV2*(tweet: Tweet; js: JsonNode) =
|
|||||||
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
textSlice = textRange{0}.getInt .. textRange{1}.getInt
|
||||||
hasQuote = "quoted_tweet_results" in js
|
hasQuote = "quoted_tweet_results" in js
|
||||||
hasJobCard = tweet.card.isSome and get(tweet.card).kind == jobDetails
|
hasJobCard = tweet.card.isSome and get(tweet.card).kind == jobDetails
|
||||||
|
hasAttribution = tweet.attribution.isSome
|
||||||
|
|
||||||
tweet.expandTextEntitiesV2(js, tweet.text, textSlice, hasQuote or hasJobCard)
|
tweet.expandTextEntitiesV2(js, tweet.text, textSlice,
|
||||||
|
hasQuote or hasJobCard or hasAttribution)
|
||||||
|
|
||||||
proc expandNoteTweetEntities*(tweet: Tweet; js: JsonNode) =
|
proc expandNoteTweetEntities*(tweet: Tweet; js: JsonNode) =
|
||||||
let
|
let
|
||||||
entities = ? js{"entity_set"}
|
entities = ? js{"entity_set"}
|
||||||
text = js{"text"}.getStr.multiReplace(("<", unicodeOpen), (">", unicodeClose))
|
text = js{"text"}.getStr.multiReplace(("<", unicodeOpen), (">", unicodeClose))
|
||||||
textSlice = 0..text.runeLen
|
textSlice = 0..text.runeLen
|
||||||
|
hasAttribution = tweet.attribution.isSome
|
||||||
|
|
||||||
tweet.expandTextEntities(entities, text, textSlice)
|
tweet.expandTextEntities(entities, text, textSlice, hasRedundantLink=hasAttribution)
|
||||||
|
|
||||||
tweet.text = tweet.text.multiReplace((unicodeOpen, xmlOpen), (unicodeClose, xmlClose))
|
tweet.text = tweet.text.multiReplace((unicodeOpen, xmlOpen), (unicodeClose, xmlClose))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user