# SPDX-License-Identifier: AGPL-3.0-only import times, sequtils, options, tables import prefs_impl genPrefsType() type RateLimitError* = object of CatchableError NoSessionsError* = object of CatchableError InternalError* = object of CatchableError BadClientError* = object of CatchableError TimelineKind* {.pure.} = enum tweets, replies, media ApiUrl* = object endpoint*: string params*: seq[(string, string)] skipTid*: bool ApiReq* = object oauth*: ApiUrl cookie*: ApiUrl RateLimit* = object limit*: int remaining*: int reset*: int SessionKind* = enum oauth cookie Session* = ref object id*: int64 username*: string pending*: int limited*: bool limitedAt*: int apis*: Table[string, RateLimit] case kind*: SessionKind of oauth: oauthToken*: string oauthSecret*: string of cookie: authToken*: string ct0*: string Error* = enum null = 0 noUserMatches = 17 protectedUser = 22 missingParams = 25 timeout = 29 couldntAuth = 32 doesntExist = 34 unauthorized = 37 invalidParam = 47 userNotFound = 50 suspended = 63 rateLimited = 88 expiredToken = 89 listIdOrSlug = 112 tweetNotFound = 144 tweetNotAuthorized = 179 forbidden = 200 badRequest = 214 badToken = 239 locked = 326 noCsrf = 353 tweetUnavailable = 421 tweetCensored = 422 VerifiedType* = enum none = "None" blue = "Blue" business = "Business" government = "Government" User* = object id*: string username*: string fullname*: string location*: string website*: string bio*: string userPic*: string banner*: string pinnedTweet*: int64 following*: int followers*: int tweets*: int likes*: int media*: int verifiedType*: VerifiedType protected*: bool suspended*: bool joinDate*: DateTime AccountInfo* = object username*: string fullname*: string userPic*: string joinDate*: DateTime verifiedType*: VerifiedType suspended*: bool basedIn*: string source*: string usernameChanges*: int lastUsernameChange*: DateTime affiliateUsername*: string affiliateLabel*: string isIdentityVerified*: bool verifiedSince*: DateTime overrideVerifiedYear*: int Broadcast* = object id*: string title*: string state*: string thumb*: string mediaKey*: string m3u8Url*: string totalWatched*: int startTime*: DateTime endTime*: DateTime replayStart*: int availableForReplay*: bool user*: User VideoType* = enum m3u8 = "application/x-mpegURL" mp4 = "video/mp4" vmap = "video/vmap" VideoVariant* = object contentType*: VideoType url*: string bitrate*: int resolution*: int Video* = object durationMs*: int url*: string thumb*: string available*: bool reason*: string title*: string description*: string playbackType*: VideoType variants*: seq[VideoVariant] QueryKind* = enum posts, replies, media, users, tweets, userList Query* = object kind*: QueryKind view*: string text*: string filters*: seq[string] includes*: seq[string] excludes*: seq[string] fromUser*: seq[string] since*: string until*: string minLikes*: string sep*: string Gif* = object url*: string thumb*: string altText*: string Photo* = object url*: string altText*: string MediaKind* = enum photoMedia videoMedia gifMedia Media* = object case kind*: MediaKind of photoMedia: photo*: Photo of videoMedia: video*: Video of gifMedia: gif*: Gif MediaEntities* = seq[Media] GalleryPhoto* = object url*: string tweetId*: string color*: string PhotoRail* = seq[GalleryPhoto] Article* = ref object title*: string coverImage*: string user*: User time*: DateTime stats*: TweetStats paragraphs*: seq[ArticleParagraph] entities*: Table[int, ArticleEntity] media*: Table[string, ArticleMedia] ArticleParagraph* = object text*: string kind*: string inlineStyles*: seq[ArticleStyle] entityRanges*: seq[ArticleEntityRange] ArticleStyle* = object offset*: int length*: int style*: string ArticleEntityRange* = object offset*: int length*: int key*: int ArticleEntity* = object kind*: string url*: string mediaIds*: seq[string] tweetId*: string markdown*: string ArticleMedia* = object kind*: string url*: string Poll* = object options*: seq[string] values*: seq[int] votes*: int leader*: int status*: string CardKind* = enum amplify = "amplify" app = "app" appPlayer = "appplayer" player = "player" summary = "summary" summaryLarge = "summary_large_image" promoWebsite = "promo_website" promoVideo = "promo_video_website" promoVideoConvo = "promo_video_convo" promoImageConvo = "promo_image_convo" promoImageApp = "promo_image_app" storeLink = "direct_store_link_app" liveEvent = "live_event" broadcast = "broadcast" periscope = "periscope_broadcast" unified = "unified_card" moment = "moment" messageMe = "message_me" videoDirectMessage = "video_direct_message" imageDirectMessage = "image_direct_message" audiospace = "audiospace" newsletterPublication = "newsletter_publication" jobDetails = "job_details" hidden unknown Card* = object kind*: CardKind url*: string title*: string dest*: string text*: string image*: string video*: Option[Video] TweetStats* = object replies*: int retweets*: int likes*: int views*: int ArticlePreview* = object title*: string previewText*: string coverImage*: string tweetId*: int64 Tweet* = ref object id*: int64 threadId*: int64 replyId*: int64 user*: User text*: string time*: DateTime reply*: seq[string] pinned*: bool hasThread*: bool available*: bool tombstone*: string location*: string # Unused, needed for backwards compat source*: string stats*: TweetStats retweet*: Option[Tweet] attribution*: Option[User] attributionLink*: string mediaTags*: seq[User] quote*: Option[Tweet] card*: Option[Card] poll*: Option[Poll] media*: MediaEntities history*: seq[int64] note*: string isAd*: bool isAI*: bool articlePreview*: Option[ArticlePreview] Tweets* = seq[Tweet] Result*[T] = object content*: seq[T] top*, bottom*: string beginning*: bool query*: Query Chain* = object content*: Tweets hasMore*: bool cursor*: string Conversation* = ref object tweet*: Tweet before*: Chain after*: Chain replies*: Result[Chain] EditHistory* = object latest*: Tweet history*: Tweets Timeline* = Result[Tweets] Profile* = object user*: User photoRail*: PhotoRail pinned*: Option[Tweet] tweets*: Timeline accountInfo*: AccountInfo List* = object id*: string name*: string userId*: string username*: string description*: string members*: int banner*: string GlobalObjects* = ref object tweets*: Table[string, Tweet] users*: Table[string, User] Config* = ref object address*: string port*: int useHttps*: bool httpMaxConns*: int title*: string hostname*: string staticDir*: string hmacKey*: string base64Media*: bool minTokens*: int enableRSSUserTweets*: bool enableRSSUserReplies*: bool enableRSSUserMedia*: bool enableRSSSearch*: bool enableRSSList*: bool enableDebug*: bool proxy*: string proxyAuth*: string apiProxy*: string disableTid*: bool maxConcurrentReqs*: int maxRetries*: int retryDelayMs*: int rssCacheTime*: int listCacheTime*: int redisHost*: string redisPort*: int redisConns*: int redisMaxConns*: int redisPassword*: string Rss* = object feed*, cursor*: string proc contains*(thread: Chain; tweet: Tweet): bool = thread.content.anyIt(it.id == tweet.id) proc add*(timeline: var seq[Tweets]; tweet: Tweet) = timeline.add @[tweet] proc getPhotos*(tweet: Tweet): seq[Photo] = tweet.media.filterIt(it.kind == photoMedia).mapIt(it.photo) proc getVideos*(tweet: Tweet): seq[Video] = tweet.media.filterIt(it.kind == videoMedia).mapIt(it.video) proc hasPhotos*(tweet: Tweet): bool = tweet.media.anyIt(it.kind == photoMedia) proc hasVideos*(tweet: Tweet): bool = tweet.media.anyIt(it.kind == videoMedia) proc hasGifs*(tweet: Tweet): bool = tweet.media.anyIt(it.kind == gifMedia) proc getThumb*(media: Media): string = case media.kind of photoMedia: media.photo.url of videoMedia: media.video.thumb of gifMedia: media.gif.thumb