Add tweet embed and oEmbed API support

This commit is contained in:
Zed 2026-07-18 12:46:43 +02:00
commit 9be0b8f826
10 changed files with 389 additions and 31 deletions

View file

@ -1,18 +1,45 @@
# SPDX-License-Identifier: AGPL-3.0-only
import asyncdispatch, strutils, strformat, options
import asyncdispatch, strutils, strformat, json
import jester, karax/vdom
import ".."/[types, api]
import ".."/[types, api, formatters]
import ../views/[embed, tweet, general]
include "../views/oembed.nimf"
import router_utils
export api, embed, vdom, tweet, general, router_utils
proc parseTweetUrl*(url: string): tuple[username, id: string] =
var path = url
if path.startsWith("https://"):
path = path[8..^1]
elif path.startsWith("http://"):
path = path[7..^1]
const prefixes = ["twitter.com/", "x.com/", "mobile.twitter.com/",
"www.twitter.com/", "www.x.com/"]
for prefix in prefixes:
if path.startsWith(prefix):
path = path[prefix.len..^1]
let parts = path.split('/')
if parts.len >= 3 and parts[1] == "status":
let tweetId = parts[2].split('?')[0].split('#')[0]
if tweetId.len > 0 and tweetId.allCharsInSet(Digits):
return (parts[0], tweetId)
break
return ("", "")
proc createEmbedRouter*(cfg: Config) =
router embed:
get "/i/videos/tweet/@id":
let tweet = await getGraphTweetResult(@"id")
if tweet == nil or not tweet.hasVideos:
resp Http404
let
tweet = await getGraphTweetResult(@"id")
prefs = requestPrefs()
if tweet == nil:
resp renderErrorEmbed("Tweet not found", prefs, cfg, request)
if not tweet.hasVideos:
resp renderErrorEmbed("No video in tweet", prefs, cfg, request)
resp renderVideoEmbed(tweet, cfg, request)
@ -23,7 +50,7 @@ proc createEmbedRouter*(cfg: Config) =
path = getPath()
if tweet == nil:
resp Http404
resp renderErrorEmbed("Tweet not found", prefs, cfg, request)
resp renderTweetEmbed(tweet, path, prefs, cfg, request)
@ -34,3 +61,35 @@ proc createEmbedRouter*(cfg: Config) =
redirect(&"/i/status/{id}/embed")
else:
resp Http404
get "/api/oembed":
let url = @"url"
if url.len == 0:
resp Http400, "Missing url parameter"
let (username, tweetId) = parseTweetUrl(url)
if username.len == 0 or tweetId.len == 0:
resp Http400, "Invalid tweet URL"
let tweet = await getGraphTweetResult(tweetId)
if tweet == nil:
resp Http404
let
embedUrl = getUrlPrefix(cfg) & "/" & username & "/status/" & tweetId & "/embed"
authorUrl = getUrlPrefix(cfg) & "/" & tweet.user.username
responseHeaders().get.add(("Access-Control-Allow-Origin", "*"))
respJson %*{
"version": "1.0",
"type": "rich",
"provider_name": cfg.title,
"provider_url": getUrlPrefix(cfg),
"author_name": tweet.user.fullname,
"author_url": authorUrl,
"url": embedUrl,
"width": 550,
"height": nil,
"cache_age": "3153600000",
"html": renderOembedIframe(embedUrl)
}

View file

@ -4,7 +4,7 @@ from jester import Request, cookies
import ../views/general
import ".."/[utils, prefs, types]
export utils, prefs, types, uri
export utils, prefs, types, uri, json
template savePref*(pref, value: string; req: Request; expire=false) =
if not expire or pref in cookies(req):