mirror of
https://github.com/zedeus/nitter.git
synced 2024-12-23 04:45:34 +00:00
commit
875e6c2cd6
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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, "")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue