91
src/experimental/parser/unifiedcard.nim
Normal file
91
src/experimental/parser/unifiedcard.nim
Normal file
@@ -0,0 +1,91 @@
|
||||
import std/[options, tables, strutils, strformat, sugar]
|
||||
import jsony
|
||||
import ../types/unifiedcard
|
||||
from ../../types import Card, CardKind, Video
|
||||
from ../../utils import twimg, https
|
||||
|
||||
proc getImageUrl(entity: MediaEntity): string =
|
||||
entity.mediaUrlHttps.dup(removePrefix(twimg), removePrefix(https))
|
||||
|
||||
proc parseDestination(id: string; card: UnifiedCard; result: var Card) =
|
||||
let destination = card.destinationObjects[id].data
|
||||
result.dest = destination.urlData.vanity
|
||||
result.url = destination.urlData.url
|
||||
|
||||
proc parseDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
||||
data.destination.parseDestination(card, result)
|
||||
|
||||
result.text = data.title
|
||||
if result.text.len == 0:
|
||||
result.text = data.name
|
||||
|
||||
proc parseMediaDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
||||
data.destination.parseDestination(card, result)
|
||||
|
||||
result.kind = summary
|
||||
result.image = card.mediaEntities[data.mediaId].getImageUrl
|
||||
result.text = data.topicDetail.title
|
||||
result.dest = "Topic"
|
||||
|
||||
proc parseAppDetails(data: ComponentData; card: UnifiedCard; result: var Card) =
|
||||
let app = card.appStoreData[data.appId][0]
|
||||
|
||||
case app.kind
|
||||
of androidApp:
|
||||
result.url = "http://play.google.com/store/apps/details?id=" & app.id
|
||||
of iPhoneApp, iPadApp:
|
||||
result.url = "https://itunes.apple.com/app/id" & app.id
|
||||
|
||||
result.text = app.title
|
||||
result.dest = app.category
|
||||
|
||||
proc parseListDetails(data: ComponentData; result: var Card) =
|
||||
result.dest = &"List · {data.memberCount} Members"
|
||||
|
||||
proc parseCommunityDetails(data: ComponentData; result: var Card) =
|
||||
result.dest = &"Community · {data.memberCount} Members"
|
||||
|
||||
proc parseMedia(component: Component; card: UnifiedCard; result: var Card) =
|
||||
let mediaId =
|
||||
if component.kind == swipeableMedia:
|
||||
component.data.mediaList[0].id
|
||||
else:
|
||||
component.data.id
|
||||
|
||||
let rMedia = card.mediaEntities[mediaId]
|
||||
case rMedia.kind:
|
||||
of photo:
|
||||
result.kind = summaryLarge
|
||||
result.image = rMedia.getImageUrl
|
||||
of video:
|
||||
let videoInfo = rMedia.videoInfo.get
|
||||
result.kind = promoVideo
|
||||
result.video = some Video(
|
||||
available: true,
|
||||
thumb: rMedia.getImageUrl,
|
||||
durationMs: videoInfo.durationMillis,
|
||||
variants: videoInfo.variants
|
||||
)
|
||||
|
||||
proc parseUnifiedCard*(json: string): Card =
|
||||
let card = json.fromJson(UnifiedCard)
|
||||
|
||||
for component in card.componentObjects.values:
|
||||
case component.kind
|
||||
of details, communityDetails, twitterListDetails:
|
||||
component.data.parseDetails(card, result)
|
||||
of appStoreDetails:
|
||||
component.data.parseAppDetails(card, result)
|
||||
of mediaWithDetailsHorizontal:
|
||||
component.data.parseMediaDetails(card, result)
|
||||
of media, swipeableMedia:
|
||||
component.parseMedia(card, result)
|
||||
of buttonGroup:
|
||||
discard
|
||||
|
||||
case component.kind
|
||||
of twitterListDetails:
|
||||
component.data.parseListDetails(result)
|
||||
of communityDetails:
|
||||
component.data.parseCommunityDetails(result)
|
||||
else: discard
|
||||
79
src/experimental/types/unifiedcard.nim
Normal file
79
src/experimental/types/unifiedcard.nim
Normal file
@@ -0,0 +1,79 @@
|
||||
import options, tables
|
||||
from ../../types import VideoType, VideoVariant
|
||||
|
||||
type
|
||||
UnifiedCard* = object
|
||||
componentObjects*: Table[string, Component]
|
||||
destinationObjects*: Table[string, Destination]
|
||||
mediaEntities*: Table[string, MediaEntity]
|
||||
appStoreData*: Table[string, seq[AppStoreData]]
|
||||
|
||||
ComponentType* = enum
|
||||
details
|
||||
media
|
||||
swipeableMedia
|
||||
buttonGroup
|
||||
appStoreDetails
|
||||
twitterListDetails
|
||||
communityDetails
|
||||
mediaWithDetailsHorizontal
|
||||
|
||||
Component* = object
|
||||
kind*: ComponentType
|
||||
data*: ComponentData
|
||||
|
||||
ComponentData* = object
|
||||
id*: string
|
||||
appId*: string
|
||||
mediaId*: string
|
||||
destination*: string
|
||||
title*: Text
|
||||
subtitle*: Text
|
||||
name*: Text
|
||||
memberCount*: int
|
||||
mediaList*: seq[MediaItem]
|
||||
topicDetail*: tuple[title: Text]
|
||||
|
||||
MediaItem* = object
|
||||
id*: string
|
||||
destination*: string
|
||||
|
||||
Destination* = object
|
||||
kind*: string
|
||||
data*: tuple[urlData: UrlData]
|
||||
|
||||
UrlData* = object
|
||||
url*: string
|
||||
vanity*: string
|
||||
|
||||
MediaType* = enum
|
||||
photo, video
|
||||
|
||||
MediaEntity* = object
|
||||
kind*: MediaType
|
||||
mediaUrlHttps*: string
|
||||
videoInfo*: Option[VideoInfo]
|
||||
|
||||
VideoInfo* = object
|
||||
durationMillis*: int
|
||||
variants*: seq[VideoVariant]
|
||||
|
||||
AppType* = enum
|
||||
androidApp, iPhoneApp, iPadApp
|
||||
|
||||
AppStoreData* = object
|
||||
kind*: AppType
|
||||
id*: string
|
||||
title*: Text
|
||||
category*: Text
|
||||
|
||||
Text = object
|
||||
content: string
|
||||
|
||||
HasTypeField = Component | Destination | MediaEntity | AppStoreData
|
||||
|
||||
converter fromText*(text: Text): string = text.content
|
||||
|
||||
proc renameHook*(v: var HasTypeField; fieldName: var string) =
|
||||
if fieldName == "type":
|
||||
fieldName = "kind"
|
||||
Reference in New Issue
Block a user