Merge pull request #515 from LainLayer/embedded

Implement tweet embeds
This commit is contained in:
Zed 2022-01-14 19:50:16 +01:00 committed by GitHub
commit 875e6c2cd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 23 deletions

View file

@ -32,23 +32,25 @@ proc getUrlPrefix*(cfg: Config): string =
if cfg.useHttps: https & cfg.hostname if cfg.useHttps: https & cfg.hostname
else: "http://" & cfg.hostname else: "http://" & cfg.hostname
proc stripHtml*(text: string): string = proc shortLink*(text: string; length=28): string =
result = text.replace(wwwRegex, "")
if result.len > length:
result = result[0 ..< length] & ""
proc stripHtml*(text: string; shorten=false): string =
var html = parseHtml(text) var html = parseHtml(text)
for el in html.findAll("a"): for el in html.findAll("a"):
let link = el.attr("href") let link = el.attr("href")
if "http" in link: if "http" in link:
if el.len == 0: continue if el.len == 0: continue
el[0].text = link el[0].text =
if shorten: link.shortLink
else: link
html.innerText() html.innerText()
proc sanitizeXml*(text: string): string = proc sanitizeXml*(text: string): string =
text.replace(illegalXmlRegex, "") text.replace(illegalXmlRegex, "")
proc shortLink*(text: string; length=28): string =
result = text.replace(wwwRegex, "")
if result.len > length:
result = result[0 ..< length] & ""
proc replaceUrls*(body: string; prefs: Prefs; absolute=""): string = proc replaceUrls*(body: string; prefs: Prefs; absolute=""): string =
result = body result = body

View file

@ -1,9 +1,11 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
import asyncdispatch, strutils, options import asyncdispatch, strutils, options
import jester import jester, karax/vdom
import ".."/[types, api], ../views/embed import ".."/[types, api]
import ../views/[embed, tweet, general]
import router_utils
export api, embed export api, embed, vdom, tweet, general, router_utils
proc createEmbedRouter*(cfg: Config) = proc createEmbedRouter*(cfg: Config) =
router embed: router embed:
@ -12,4 +14,23 @@ proc createEmbedRouter*(cfg: Config) =
if convo == nil or convo.tweet == nil or convo.tweet.video.isNone: if convo == nil or convo.tweet == nil or convo.tweet.video.isNone:
resp Http404 resp Http404
resp renderVideoEmbed(cfg, convo.tweet) resp renderVideoEmbed(convo.tweet, cfg, request)
get "/@user/status/@id/embed":
let
convo = await getTweet(@"id")
prefs = cookiePrefs()
path = getPath()
if convo == nil or convo.tweet == nil:
resp Http404
resp $renderTweetEmbed(convo.tweet, path, prefs, cfg, request)
get "/embed/Tweet.html":
let id = @"id"
if id.len > 0:
redirect("/i/status/" & id & "/embed")
else:
resp Http404

View file

@ -4,12 +4,12 @@ from jester import Request, cookies
import ../views/general import ../views/general
import ".."/[utils, prefs, types] import ".."/[utils, prefs, types]
export utils, prefs, types export utils, prefs, types, uri
template savePref*(pref, value: string; req: Request; expire=false) = template savePref*(pref, value: string; req: Request; expire=false) =
if not expire or pref in cookies(req): if not expire or pref in cookies(req):
setCookie(pref, value, daysForward(when expire: -10 else: 360), setCookie(pref, value, daysForward(when expire: -10 else: 360),
httpOnly=true, secure=cfg.useHttps) httpOnly=true, secure=cfg.useHttps, sameSite=None)
template cookiePrefs*(): untyped {.dirty.} = template cookiePrefs*(): untyped {.dirty.} =
getPrefs(cookies(request)) getPrefs(cookies(request))

View file

@ -98,6 +98,8 @@
} }
.avatar { .avatar {
position: absolute;
&.round { &.round {
border-radius: 50%; border-radius: 50%;
} }
@ -110,6 +112,23 @@
} }
} }
.tweet-embed {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
.tweet-content {
font-size: 18px
}
.tweet-body {
display: flex;
flex-direction: column;
max-height: calc(100vh - 0.75em * 2);
}
}
.attribution { .attribution {
display: flex; display: flex;
pointer-events: all; pointer-events: all;

View file

@ -1,18 +1,19 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
import options import options
import karax/[karaxdsl, vdom] import karax/[karaxdsl, vdom]
from jester import Request
import ".."/[types, formatters] import ".."/[types, formatters]
import general, tweet import general, tweet
const doctype = "<!DOCTYPE html>\n" const doctype = "<!DOCTYPE html>\n"
proc renderVideoEmbed*(cfg: Config; tweet: Tweet): string = proc renderVideoEmbed*(tweet: Tweet; cfg: Config; req: Request): string =
let thumb = get(tweet.video).thumb let thumb = get(tweet.video).thumb
let vidUrl = getVideoEmbed(cfg, tweet.id) let vidUrl = getVideoEmbed(cfg, tweet.id)
let prefs = Prefs(hlsPlayback: true) let prefs = Prefs(hlsPlayback: true)
let node = buildHtml(html(lang="en")): let node = buildHtml(html(lang="en")):
renderHead(prefs, cfg, video=vidUrl, images=(@[thumb])) renderHead(prefs, cfg, req, video=vidUrl, images=(@[thumb]))
tdiv(class="embed-video"): tdiv(class="embed-video"):
renderVideo(get(tweet.video), prefs, "") renderVideo(get(tweet.video), prefs, "")

View file

@ -11,6 +11,9 @@ const
doctype = "<!DOCTYPE html>\n" doctype = "<!DOCTYPE html>\n"
lp = readFile("public/lp.svg") lp = readFile("public/lp.svg")
proc toTheme(theme: string): string =
theme.toLowerAscii.replace(" ", "_")
proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode = proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
var path = req.params.getOrDefault("referer") var path = req.params.getOrDefault("referer")
if path.len == 0: if path.len == 0:
@ -33,9 +36,13 @@ proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
icon "info", title="About", href="/about" icon "info", title="About", href="/about"
icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path)) icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video=""; proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
images: seq[string] = @[]; banner=""; ogTitle=""; theme=""; video=""; images: seq[string] = @[]; banner=""; ogTitle="";
rss=""; canonical=""): VNode = rss=""; canonical=""): VNode =
var theme = prefs.theme.toTheme
if "theme" in req.params:
theme = req.params["theme"].toTheme
let ogType = let ogType =
if video.len > 0: "video" if video.len > 0: "video"
elif rss.len > 0: "object" elif rss.len > 0: "object"
@ -45,7 +52,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
let opensearchUrl = getUrlPrefix(cfg) & "/opensearch" let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
buildHtml(head): buildHtml(head):
link(rel="stylesheet", type="text/css", href="/css/style.css?v=10") link(rel="stylesheet", type="text/css", href="/css/style.css?v=12")
link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2") link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2")
if theme.len > 0: if theme.len > 0:
@ -118,15 +125,12 @@ proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs; proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs;
titleText=""; desc=""; ogTitle=""; rss=""; video=""; titleText=""; desc=""; ogTitle=""; rss=""; video="";
images: seq[string] = @[]; banner=""): string = images: seq[string] = @[]; banner=""): string =
var theme = toLowerAscii(prefs.theme).replace(" ", "_")
if "theme" in req.params:
theme = toLowerAscii(req.params["theme"]).replace(" ", "_")
let canonical = getTwitterLink(req.path, req.params) let canonical = getTwitterLink(req.path, req.params)
let node = buildHtml(html(lang="en")): let node = buildHtml(html(lang="en")):
renderHead(prefs, cfg, titleText, desc, video, images, banner, ogTitle, renderHead(prefs, cfg, req, titleText, desc, video, images, banner, ogTitle,
theme, rss, canonical) rss, canonical)
body: body:
renderNavbar(cfg, req, rss, canonical) renderNavbar(cfg, req, rss, canonical)

View file

@ -1,9 +1,11 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
import strutils, sequtils, strformat, options import strutils, sequtils, strformat, options
import karax/[karaxdsl, vdom, vstyles] import karax/[karaxdsl, vdom, vstyles]
from jester import Request
import renderutils import renderutils
import ".."/[types, utils, formatters] import ".."/[types, utils, formatters]
import general
proc getSmallPic(url: string): string = proc getSmallPic(url: string): string =
result = url result = url
@ -353,3 +355,8 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0;
if showThread: if showThread:
a(class="show-thread", href=("/i/status/" & $tweet.threadId)): a(class="show-thread", href=("/i/status/" & $tweet.threadId)):
text "Show this thread" text "Show this thread"
proc renderTweetEmbed*(tweet: Tweet; path: string; prefs: Prefs; cfg: Config; req: Request): VNode =
buildHtml(tdiv(class="tweet-embed")):
renderHead(prefs, cfg, req)
renderTweet(tweet, prefs, path, mainTweet=true)