Support more cards, even the undocumented ones

This commit is contained in:
Zed 2020-06-03 02:33:34 +02:00
parent b4fe3d1f6a
commit 4d650fd33e
4 changed files with 42 additions and 22 deletions

View File

@ -1,6 +1,6 @@
import strutils, options, tables, times, math import strutils, options, tables, times, math
import packedjson import packedjson
import types, parserutils import types, parserutils, utils
proc parseProfile(js: JsonNode; id=""): Profile = proc parseProfile(js: JsonNode; id=""): Profile =
if js.isNull: return if js.isNull: return
@ -124,25 +124,28 @@ proc parseVideo(js: JsonNode): Video =
proc parsePromoVideo(js: JsonNode): Video = proc parsePromoVideo(js: JsonNode): Video =
result = Video( result = Video(
videoId: js{"player_content_id"}.getStrVal(js{"card_id"}.getStrVal), thumb: js{"player_image_large"}.getImageVal,
thumb: js{"player_image_large", "image_value", "url"}.getStr,
available: true, available: true,
durationMs: js{"content_duration_seconds"}.getStrVal("0").parseInt * 1000, durationMs: js{"content_duration_seconds"}.getStrVal("0").parseInt * 1000,
playbackType: vmap,
videoId: js{"player_content_id"}.getStrVal(js{"card_id"}.getStrVal(
js{"amplify_content_id"}.getStrVal())),
) )
var variant = VideoVariant( var variant = VideoVariant(
videoType: m3u8, videoType: vmap,
url: js{"player_hls_url"}.getStrVal(js{"player_stream_url"}.getStrVal) url: js{"player_hls_url"}.getStrVal(js{"player_stream_url"}.getStrVal(
js{"amplify_url_vmap"}.getStrVal()))
) )
if "vmap" in variant.url: if "m3u8" in variant.url:
variant.videoType = vmap variant.videoType = m3u8
result.playbackType = m3u8
result.playbackType = vmap
result.variants.add variant result.variants.add variant
proc parseBroadcast(js: JsonNode): Card = proc parseBroadcast(js: JsonNode): Card =
let image = js{"broadcast_thumbnail_large", "image_value", "url"}.getStr let image = js{"broadcast_thumbnail_large"}.getImageVal
result = Card( result = Card(
kind: broadcast, kind: broadcast,
url: js{"broadcast_url"}.getStrVal, url: js{"broadcast_url"}.getStrVal,
@ -153,8 +156,9 @@ proc parseBroadcast(js: JsonNode): Card =
) )
proc parseCard(js: JsonNode; urls: JsonNode): Card = proc parseCard(js: JsonNode; urls: JsonNode): Card =
const imageTypes = ["photo_image_full_size", "summary_photo_image", const imageTypes = ["summary_photo_image", "player_image", "promo_image",
"thumbnail_image", "promo_image", "player_image"] "photo_image_full_size", "thumbnail_image", "thumbnail",
"event_thumbnail"]
let let
vals = ? js{"binding_values"} vals = ? js{"binding_values"}
name = js{"name"}.getStr name = js{"name"}.getStr
@ -172,19 +176,25 @@ proc parseCard(js: JsonNode; urls: JsonNode): Card =
result.url = js{"url"}.getStr result.url = js{"url"}.getStr
case kind case kind
of promoVideo, promoVideoConvo: of promoVideoConvo, appPlayer:
result.video = some parsePromoVideo(vals) result.video = some parsePromoVideo(vals)
if kind == appPlayer:
result.text = vals{"app_category"}.getStrVal(result.text)
of broadcast: of broadcast:
result = parseBroadcast(vals) result = parseBroadcast(vals)
of liveEvent:
result.text = vals{"event_title"}.getStrVal
of player: of player:
result.url = vals{"player_url"}.getStrVal result.url = vals{"player_url"}.getStrVal
if "youtube.com" in result.url: if "youtube.com" in result.url:
result.url = result.url.replace("/embed/", "/watch?v=") result.url = result.url.replace("/embed/", "/watch?v=")
of unified:
result.title = "This card type is not supported."
else: discard else: discard
for typ in imageTypes: for typ in imageTypes:
with img, vals{typ & "_large"}: with img, vals{typ & "_large"}:
result.image = img{"image_value", "url"}.getStr result.image = img.getImageVal
break break
for u in ? urls: for u in ? urls:
@ -192,6 +202,10 @@ proc parseCard(js: JsonNode; urls: JsonNode): Card =
result.url = u{"expanded_url"}.getStr result.url = u{"expanded_url"}.getStr
break break
if kind in {promoImageConvo, promoImageApp} and result.url.len == 0 or
result.url.startsWith("card://"):
result.url = getPicUrl(result.image)
proc parseTweet(js: JsonNode): Tweet = proc parseTweet(js: JsonNode): Tweet =
if js.isNull: return if js.isNull: return
result = Tweet( result = Tweet(
@ -223,9 +237,11 @@ proc parseTweet(js: JsonNode): Tweet =
let name = jsCard{"name"}.getStr let name = jsCard{"name"}.getStr
if "poll" in name: if "poll" in name:
if "image" in name: if "image" in name:
result.photos.add jsCard{"binding_values", "image_large", "image_value", "url"}.getStr result.photos.add jsCard{"binding_values", "image_large"}.getImageVal
result.poll = some parsePoll(jsCard) result.poll = some parsePoll(jsCard)
elif name == "amplify":
result.video = some(parsePromoVideo(jsCard{"binding_values"}))
else: else:
result.card = some parseCard(jsCard, js{"entities", "urls"}) result.card = some parseCard(jsCard, js{"entities", "urls"})

View File

@ -58,10 +58,15 @@ proc getId*(js: JsonNode): int64 {.inline.} =
template getStrVal*(js: JsonNode; default=""): string = template getStrVal*(js: JsonNode; default=""): string =
js{"string_value"}.getStr(default) js{"string_value"}.getStr(default)
template getImageVal*(js: JsonNode; default=""): string =
js{"image_value", "url"}.getStr(default)
proc getCardUrl*(js: JsonNode; kind: CardKind): string = proc getCardUrl*(js: JsonNode; kind: CardKind): string =
result = js{"website_url"}.getStrVal result = js{"website_url"}.getStrVal
if kind == promoVideoConvo: if kind == promoVideoConvo:
result = js{"thank_you_url"}.getStrVal(result) result = js{"thank_you_url"}.getStrVal(result)
if result.startsWith("card://"):
result = ""
proc getCardDomain*(js: JsonNode; kind: CardKind): string = proc getCardDomain*(js: JsonNode; kind: CardKind): string =
result = js{"vanity_url"}.getStrVal(js{"domain"}.getStr) result = js{"vanity_url"}.getStrVal(js{"domain"}.getStr)
@ -72,6 +77,8 @@ proc getCardTitle*(js: JsonNode; kind: CardKind): string =
result = js{"title"}.getStrVal result = js{"title"}.getStrVal
if kind == promoVideoConvo: if kind == promoVideoConvo:
result = js{"thank_you_text"}.getStrVal(result) result = js{"thank_you_text"}.getStrVal(result)
if kind == liveEvent:
result = js{"event_category"}.getStrVal
proc getBanner*(js: JsonNode): string = proc getBanner*(js: JsonNode): string =
let url = js{"profile_banner_url"}.getStr let url = js{"profile_banner_url"}.getStr

View File

@ -101,24 +101,21 @@ type
status*: string status*: string
CardKind* = enum CardKind* = enum
amplify = "amplify"
app = "app" app = "app"
appplayer = "appplayer" appPlayer = "appplayer"
player = "player" player = "player"
audio = "audio"
summary = "summary" summary = "summary"
summaryLarge = "summary_large_image" summaryLarge = "summary_large_image"
promoWebsite = "promo_website" promoWebsite = "promo_website"
promoVideo = "promo_video_website"
promoVideoConvo = "promo_video_convo" promoVideoConvo = "promo_video_convo"
promoImageConvo = "promo_image_convo" promoImageConvo = "promo_image_convo"
promoVideoApp = "promo_video_app"
promoImageApp = "promo_image_app" promoImageApp = "promo_image_app"
amplify = "amplify" storeLink = "direct_store_link_app"
unified = "unified_card"
liveEvent = "live_event" liveEvent = "live_event"
broadcast = "broadcast" broadcast = "broadcast"
periscope = "periscope_broadcast" periscope = "periscope_broadcast"
storeLink = "direct_store_link_app" unified = "unified_card"
moment = "moment" moment = "moment"
messageMe = "message_me" messageMe = "message_me"

View File

@ -145,7 +145,7 @@ proc renderCardContent(card: Card): VNode =
span(class="card-destination"): text card.dest span(class="card-destination"): text card.dest
proc renderCard(card: Card; prefs: Prefs; path: string): VNode = proc renderCard(card: Card; prefs: Prefs; path: string): VNode =
const smallCards = {player, summary} const smallCards = {app, player, summary, storeLink}
let large = if card.kind notin smallCards: " large" else: "" let large = if card.kind notin smallCards: " large" else: ""
let url = replaceUrl(card.url, prefs) let url = replaceUrl(card.url, prefs)