# SPDX-License-Identifier: AGPL-3.0-only import strutils, strformat, options, json, sequtils, times import ".."/[types, formatters, utils] proc formatTweetForMastoAPI*(tweet: Tweet, cfg: Config, prefs: Prefs): string = var content = replaceUrls(tweet.text, prefs) if tweet.quote.isSome(): let quote = get(tweet.quote) quoteContent = replaceUrls(quote.text, prefs) quoteUrl = &"{getUrlPrefix(cfg)}/i/status/{quote.id}" content &= &"\n\n
ā†˜ {quote.user.fullName} (@{quote.user.username})\n{quoteContent}" if quote.video.isSome() or quote.gif.isSome(): content &= "\nšŸ“¹" if quote.gif.isSome(): content &= " (GIF)" elif quote.photos.len > 0: content &= "\nšŸ–¼ļø" if quote.photos.len > 1: content &= &" ({quote.photos.len})" content &= "
" if tweet.birdwatch.isSome(): let note = get(tweet.birdwatch) noteContent = replaceUrls(note.text, prefs) content &= &"\n
ā“˜ {note.title}\n{noteContent}
" result = content.replace("\n", "
") proc getActivityStream*(tweet: Tweet, cfg: Config, prefs: Prefs): JsonNode = let tweetUrl = &"{getUrlPrefix(cfg)}/i/status/{tweet.id}" tweetContent = formatTweetForMastoAPI(tweet, cfg, prefs) var media: seq[JsonNode] = @[] if tweet.photos.len > 0: for url in tweet.photos: let image = getUrlPrefix(cfg) & getPicUrl(url) var mediaObj = newJObject() mediaObj["type"] = %"Document" mediaObj["mediaType"] = %"image/png" mediaObj["url"] = %image mediaObj["name"] = newJNull() # FIXME a11y media.add(mediaObj) if tweet.video.isSome(): let videoObj = get(tweet.video) vars = videoObj.variants.filterIt(it.contentType == mp4) var mediaObj = newJObject() mediaObj["type"] = %"Document" mediaObj["mediaType"] = %"video/mp4" mediaObj["url"] = %vars[^1].url mediaObj["name"] = newJNull() # FIXME a11y media.add(mediaObj) elif tweet.gif.isSome(): let gif = get(tweet.gif) var mediaObj = newJObject() mediaObj["type"] = %"Document" mediaObj["mediaType"] = %"video/mp4" mediaObj["url"] = %(&"https://{gif.url}") mediaObj["name"] = newJNull() # FIXME a11y media.add(mediaObj) var context: seq[JsonNode] = @[] let contextUrl: JsonNode = %"https://www.w3.org/ns/activitystreams" context.add(contextUrl) let asProps: JsonNode = %*{ "ostatus": "http://ostatus.org#", "atomUri": "ostatus:atomUri", "inReplyToAtomUri": "ostatus:inReplyToAtomUri", "conversation": "ostatus:conversation", "sensitive": "as:sensitive", } context.add(asProps) var postJson = newJObject() postJson["@context"] = %context postJson["id"] = %tweetUrl postJson["type"] = %"Note" postJson["summary"] = newJNull() if tweet.replyId != 0: let replyUrl = &"{getUrlPrefix(cfg)}/i/status/{tweet.replyId}" postJson["inReplyTo"] = %replyUrl postJson["inReplyToAtomUri"] = %replyUrl else: postJson["inReplyTo"] = newJNull() postJson["inReplyToAtomUri"] = newJNull() postJson["published"] = %($tweet.time) postJson["url"] = %tweetUrl postJson["attributedTo"] = %(&"{getUrlPrefix(cfg)}/users/{tweet.user.username}") postJson["to"] = newJArray() postJson["cc"] = %(@["https://www.w3.org/ns/activitystreams#Public"]) postJson["sensitive"] = %false # FIXME postJson["atomUri"] = %tweetUrl postJson["conversation"] = %"" postJson["content"] = %tweetContent postJson["contentMap"] = %*{ "en": tweetContent } postJson["attachment"] = %media postJson["tag"] = newJArray() # TODO: parse? postJson["replies"] = newJObject() result = postJson proc getActivityStream*(user: User, cfg: Config, prefs: Prefs): JsonNode = let userUrl = &"{getUrlPrefix(cfg)}/{user.username}" var context: seq[JsonNode] = @[] let contextUrl: JsonNode = %"https://www.w3.org/ns/activitystreams" context.add(contextUrl) let contextUrl2: JsonNode = %"https://w3id.org/security/v1" context.add(contextUrl2) let contextAka: JsonNode = %*{ "@id": "as:alsoKnownAs", "@type": "@id" } let contextMovedTo = %*{ "@id": "as:movedTo", "@type": "@id" } var asProps: JsonNode = %*{ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "schema": "http://schema.org#", "PropertyValue": "schema:PropertyValue", "value": "schema:value", } asProps["alsoKnownAs"] = contextAka asProps["movedTo"] = contextMovedTo context.add(asProps) var userJson = newJObject() userJson["@context"] = %context userJson["id"] = %userUrl userJson["type"] = %"Person" userJson["following"] = %(userUrl & "/following") userJson["followers"] = %(userUrl & "/followers") userJson["inbox"] = newJNull() userJson["outbox"] = newJNull() userJson["featured"] = newJNull() userJson["featuredTags"] = newJNull() userJson["preferredUsername"] = %user.username userJson["name"] = %user.fullname userJson["summary"] = %user.bio userJson["url"] = %userUrl userJson["manuallyApprovesFollowers"] = %user.protected userJson["discoverable"] = %true userJson["indexable"] = %false userJson["published"] = %($user.joinDate) userJson["memorial"] = %false userJson["publicKey"] = newJNull() userJson["tag"] = newJArray() userJson["attachment"] = newJArray() userJson["endpoints"] = newJObject() userJson["icon"] = %*{ "type": "Image", "mediaType": "image/jpeg", "url": getUrlPrefix(cfg) & getPicUrl(user.userPic) } userJson["image"] = %*{ "type": "Image", "mediaType": "image/jpeg", "url": getUrlPrefix(cfg) & getPicUrl(user.banner) } result = userJson