Add server config file

This commit is contained in:
Zed 2019-07-31 02:15:43 +02:00
parent b10d894a11
commit 6a9d182249
8 changed files with 53 additions and 23 deletions

View file

@ -28,7 +28,6 @@ is on implementing missing features.
- Search (images/videos, hashtags, etc.)
- Custom timeline filter
- Nitter link previews
- Server configuration
- More caching (waiting for [moigagoo/norm#19](https://github.com/moigagoo/norm/pull/19))
- Simple account system with customizable feed
- Video support with hls.js

9
nitter.conf Normal file
View file

@ -0,0 +1,9 @@
[Server]
address = "0.0.0.0"
port = 8080
title = "nitter"
staticDir = "./public"
[Cache]
directory = "/tmp/niter"
profileMinutes = 10 # how long to cache profiles

View file

@ -450,6 +450,7 @@ video {
text-overflow: ellipsis;
max-width: 100%;
font-weight: bold;
overflow-wrap: break-word;
}
.profile-card-username {

View file

@ -26,3 +26,6 @@ proc getCachedProfile*(username: string; force=false): Future[Profile] {.async.}
result = await getProfile(username)
if result.username.len > 0:
result.insert()
proc setProfileCacheTime*(minutes: int) =
profileCacheTime = initDuration(minutes=minutes)

View file

@ -69,10 +69,7 @@ proc getUserpic*(profile: Profile; style=""): string =
getUserPic(profile.userpic, style)
proc pageTitle*(profile: Profile): string =
&"{profile.fullname} (@{profile.username}) | Nitter"
proc pageTitle*(page: string): string =
&"{page} | Nitter"
&"{profile.fullname} (@{profile.username})"
proc getTime*(tweet: Tweet): string =
tweet.time.format("d/M/yyyy', ' HH:mm:ss")

View file

@ -1,11 +1,13 @@
import asyncdispatch, asyncfile, httpclient, strutils, strformat, uri, os
from net import Port
import jester, regex
import api, utils, types, cache, formatters, search
import api, utils, types, cache, formatters, search, config
import views/[general, profile, status]
const cacheDir {.strdefine.} = "/tmp/nitter"
const configPath {.strdefine.} = "./nitter.conf"
let cfg = getConfig(configPath)
proc showTimeline(name, after: string; query: Option[Query]): Future[string] {.async.} =
let
@ -24,20 +26,27 @@ proc showTimeline(name, after: string; query: Option[Query]): Future[string] {.a
return ""
let profileHtml = renderProfile(profile, await timelineFut, await railFut)
return renderMain(profileHtml, title=pageTitle(profile))
return renderMain(profileHtml, title=cfg.title, titleText=pageTitle(profile))
template respTimeline(timeline: typed) =
if timeline.len == 0:
resp Http404, showError("User \"" & @"name" & "\" not found")
resp Http404, showError("User \"" & @"name" & "\" not found", cfg.title)
resp timeline
setProfileCacheTime(cfg.profileCacheTime)
settings:
port = Port(cfg.port)
staticDir = cfg.staticDir
bindAddr = cfg.address
routes:
get "/":
resp renderMain(renderSearch(), title=pageTitle("Search"))
resp renderMain(renderSearch(), title=cfg.title, titleText="Search")
post "/search":
if @"query".len == 0:
resp Http404, showError("Please enter a username.")
resp Http404, showError("Please enter a username.", cfg.title)
redirect("/" & @"query")
get "/@name/?":
@ -62,7 +71,7 @@ routes:
let conversation = await getTweet(@"name", @"id")
if conversation == nil or conversation.tweet.id.len == 0:
resp Http404, showError("Tweet not found")
resp Http404, showError("Tweet not found", cfg.title)
let title = pageTitle(conversation.tweet.profile)
resp renderMain(renderConversation(conversation), title=title)
@ -74,13 +83,13 @@ routes:
let
uri = parseUri(decodeUrl(@"url"))
path = uri.path.split("/")[2 .. ^1].join("/")
filename = cacheDir / cleanFilename(path & uri.query)
filename = cfg.cacheDir / cleanFilename(path & uri.query)
if getHmac($uri) != @"sig":
resp showError("Failed to verify signature")
resp showError("Failed to verify signature", cfg.title)
if not existsDir(cacheDir):
createDir(cacheDir)
if not existsDir(cfg.cacheDir):
createDir(cfg.cacheDir)
if not existsFile(filename):
let client = newAsyncHttpClient()
@ -92,6 +101,7 @@ routes:
let file = openAsync(filename)
defer: file.close()
resp await readAll(file), mimetype(filename)
get "/video/@sig/@url":
@ -100,7 +110,7 @@ routes:
let url = decodeUrl(@"url")
if getHmac(url) != @"sig":
resp showError("Failed to verify signature")
resp showError("Failed to verify signature", cfg.title)
let
client = newAsyncHttpClient()

View file

@ -147,5 +147,13 @@ type
beginning*: bool
query*: Option[Query]
Config* = ref object
address*: string
port*: int
title*: string
staticDir*: string
cacheDir*: string
profileCacheTime*: int
proc contains*(thread: Thread; tweet: Tweet): bool =
thread.tweets.anyIt(it.id == tweet.id)

View file

@ -2,17 +2,20 @@ import karax/[karaxdsl, vdom]
const doctype = "<!DOCTYPE html>\n"
proc renderMain*(body: VNode; title="Nitter"): string =
proc renderMain*(body: VNode; title="Nitter"; titleText=""): string =
let node = buildHtml(html(lang="en")):
head:
title: text title
if titleText.len > 0:
title: text titleText & " | " & title
else:
title: text title
link(rel="stylesheet", `type`="text/css", href="/style.css")
body:
nav(id="nav", class="nav-bar container"):
tdiv(class="inner-nav"):
tdiv(class="item"):
a(href="/", class="site-name"): text "nitter"
a(href="/", class="site-name"): text title
tdiv(id="content", class="container"):
body
@ -31,5 +34,5 @@ proc renderError*(error: string): VNode =
tdiv(class="error-panel"):
span: text error
proc showError*(error: string): string =
renderMain(renderError(error), title = "Error | Nitter")
proc showError*(error: string; title: string): string =
renderMain(renderError(error), title=title, titleText="Error")