Store preferences in cookies, add config defaults
This commit is contained in:
		
							parent
							
								
									517d9144f6
								
							
						
					
					
						commit
						312ff78628
					
				
							
								
								
									
										11
									
								
								nitter.conf
								
								
								
								
							
							
						
						
									
										11
									
								
								nitter.conf
								
								
								
								
							| 
						 | 
					@ -11,5 +11,14 @@ directory = "./tmp"
 | 
				
			||||||
profileMinutes = 10  # how long to cache profiles
 | 
					profileMinutes = 10  # how long to cache profiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Config]
 | 
					[Config]
 | 
				
			||||||
defaultTheme = "Nitter"
 | 
					 | 
				
			||||||
hmacKey = "secretkey" # for signing video urls
 | 
					hmacKey = "secretkey" # for signing video urls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Change default preferences here, see src/prefs_impl.nim for a complete list
 | 
				
			||||||
 | 
					[Preferences]
 | 
				
			||||||
 | 
					theme = "Nitter"
 | 
				
			||||||
 | 
					replaceTwitter = "nitter.net"
 | 
				
			||||||
 | 
					replaceYouTube = "invidio.us"
 | 
				
			||||||
 | 
					replaceInstagram = ""
 | 
				
			||||||
 | 
					proxyVideos = true
 | 
				
			||||||
 | 
					hlsPlayback = false
 | 
				
			||||||
 | 
					infiniteScroll = false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
import parsecfg except Config
 | 
					import parsecfg except Config
 | 
				
			||||||
import net, types, strutils
 | 
					import types, strutils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc get[T](config: parseCfg.Config; s, v: string; default: T): T =
 | 
					proc get*[T](config: parseCfg.Config; s, v: string; default: T): T =
 | 
				
			||||||
  let val = config.getSectionValue(s, v)
 | 
					  let val = config.getSectionValue(s, v)
 | 
				
			||||||
  if val.len == 0: return default
 | 
					  if val.len == 0: return default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,10 +9,10 @@ proc get[T](config: parseCfg.Config; s, v: string; default: T): T =
 | 
				
			||||||
  elif T is bool: parseBool(val)
 | 
					  elif T is bool: parseBool(val)
 | 
				
			||||||
  elif T is string: val
 | 
					  elif T is string: val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc getConfig*(path: string): Config =
 | 
					proc getConfig*(path: string): (Config, parseCfg.Config) =
 | 
				
			||||||
  var cfg = loadConfig(path)
 | 
					  var cfg = loadConfig(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Config(
 | 
					  let conf = Config(
 | 
				
			||||||
    address: cfg.get("Server", "address", "0.0.0.0"),
 | 
					    address: cfg.get("Server", "address", "0.0.0.0"),
 | 
				
			||||||
    port: cfg.get("Server", "port", 8080),
 | 
					    port: cfg.get("Server", "port", 8080),
 | 
				
			||||||
    useHttps: cfg.get("Server", "https", true),
 | 
					    useHttps: cfg.get("Server", "https", true),
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ proc getConfig*(path: string): Config =
 | 
				
			||||||
    cacheDir: cfg.get("Cache", "directory", "/tmp/nitter"),
 | 
					    cacheDir: cfg.get("Cache", "directory", "/tmp/nitter"),
 | 
				
			||||||
    profileCacheTime: cfg.get("Cache", "profileMinutes", 10),
 | 
					    profileCacheTime: cfg.get("Cache", "profileMinutes", 10),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    defaultTheme: cfg.get("Config", "defaultTheme", "Nitter"),
 | 
					 | 
				
			||||||
    hmacKey: cfg.get("Config", "hmacKey", "secretkey")
 | 
					    hmacKey: cfg.get("Config", "hmacKey", "secretkey")
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (conf, cfg)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,9 @@ import routes/[
 | 
				
			||||||
  unsupported, embed, resolver]
 | 
					  unsupported, embed, resolver]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const configPath {.strdefine.} = "./nitter.conf"
 | 
					const configPath {.strdefine.} = "./nitter.conf"
 | 
				
			||||||
let cfg = getConfig(configPath)
 | 
					let (cfg, fullCfg) = getConfig(configPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					updateDefaultPrefs(fullCfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setHmacKey(cfg.hmacKey)
 | 
					setHmacKey(cfg.hmacKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,54 +1,15 @@
 | 
				
			||||||
import strutils, sequtils, macros
 | 
					import tables
 | 
				
			||||||
import norm/sqlite
 | 
					import types, prefs_impl
 | 
				
			||||||
 | 
					from config import get
 | 
				
			||||||
 | 
					from parsecfg import nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prefs_impl, types
 | 
					export genUpdatePrefs, genResetPrefs
 | 
				
			||||||
export genUpdatePrefs
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template safeAddColumn(field: typedesc): untyped =
 | 
					var defaultPrefs*: Prefs
 | 
				
			||||||
  try: field.addColumn
 | 
					 | 
				
			||||||
  except DbError: discard
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
dbFromTypes("prefs.db", "", "", "", [Prefs])
 | 
					proc updateDefaultPrefs*(cfg: parsecfg.Config) =
 | 
				
			||||||
 | 
					  genDefaultPrefs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
withDb:
 | 
					proc getPrefs*(cookies: Table[string, string]): Prefs =
 | 
				
			||||||
  try:
 | 
					  result = defaultPrefs
 | 
				
			||||||
    createTables()
 | 
					  genCookiePrefs()
 | 
				
			||||||
  except DbError:
 | 
					 | 
				
			||||||
    discard
 | 
					 | 
				
			||||||
  safeAddColumn Prefs.theme
 | 
					 | 
				
			||||||
  safeAddColumn Prefs.hidePins
 | 
					 | 
				
			||||||
  safeAddColumn Prefs.hideReplies
 | 
					 | 
				
			||||||
  safeAddColumn Prefs.infiniteScroll
 | 
					 | 
				
			||||||
  safeAddColumn Prefs.replaceInstagram
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc getDefaultPrefs(cfg: Config): Prefs =
 | 
					 | 
				
			||||||
  result = genDefaultPrefs()
 | 
					 | 
				
			||||||
  result.replaceTwitter = cfg.hostname
 | 
					 | 
				
			||||||
  result.theme = cfg.defaultTheme
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc cache*(prefs: var Prefs) =
 | 
					 | 
				
			||||||
  withDb:
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
      doAssert prefs.id != 0
 | 
					 | 
				
			||||||
      discard Prefs.getOne("id = ?", prefs.id)
 | 
					 | 
				
			||||||
      prefs.update()
 | 
					 | 
				
			||||||
    except AssertionError, KeyError:
 | 
					 | 
				
			||||||
      prefs.insert()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc getPrefs*(id: string; cfg: Config): Prefs =
 | 
					 | 
				
			||||||
  if id.len == 0:
 | 
					 | 
				
			||||||
    return getDefaultPrefs(cfg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  withDb:
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
      result.getOne("id = ?", id)
 | 
					 | 
				
			||||||
      if result.theme.len == 0:
 | 
					 | 
				
			||||||
        result.theme = cfg.defaultTheme
 | 
					 | 
				
			||||||
    except KeyError:
 | 
					 | 
				
			||||||
      result = getDefaultPrefs(cfg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc resetPrefs*(prefs: var Prefs; cfg: Config) =
 | 
					 | 
				
			||||||
  var defPrefs = getDefaultPrefs(cfg)
 | 
					 | 
				
			||||||
  defPrefs.id = prefs.id
 | 
					 | 
				
			||||||
  cache(defPrefs)
 | 
					 | 
				
			||||||
  prefs = defPrefs
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,9 @@ type
 | 
				
			||||||
    defaultOption*: string
 | 
					    defaultOption*: string
 | 
				
			||||||
    defaultInput*: string
 | 
					    defaultInput*: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro genPrefs(prefDsl: untyped) =
 | 
					  PrefList* = OrderedTable[string, seq[Pref]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro genPrefs*(prefDsl: untyped) =
 | 
				
			||||||
  var table = nnkTableConstr.newTree()
 | 
					  var table = nnkTableConstr.newTree()
 | 
				
			||||||
  for category in prefDsl:
 | 
					  for category in prefDsl:
 | 
				
			||||||
    table.add nnkExprColonExpr.newTree(newLit($category[0]))
 | 
					    table.add nnkExprColonExpr.newTree(newLit($category[0]))
 | 
				
			||||||
| 
						 | 
					@ -41,7 +43,7 @@ macro genPrefs(prefDsl: untyped) =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let name = ident("prefList")
 | 
					  let name = ident("prefList")
 | 
				
			||||||
  result = quote do:
 | 
					  result = quote do:
 | 
				
			||||||
    const `name`* = toOrderedTable(`table`)
 | 
					    const `name`*: PrefList = toOrderedTable(`table`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
genPrefs:
 | 
					genPrefs:
 | 
				
			||||||
  Privacy:
 | 
					  Privacy:
 | 
				
			||||||
| 
						 | 
					@ -101,46 +103,79 @@ iterator allPrefs*(): Pref =
 | 
				
			||||||
      yield pref
 | 
					      yield pref
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro genDefaultPrefs*(): untyped =
 | 
					macro genDefaultPrefs*(): untyped =
 | 
				
			||||||
  result = nnkObjConstr.newTree(ident("Prefs"))
 | 
					  result = nnkStmtList.newTree()
 | 
				
			||||||
 | 
					 | 
				
			||||||
  for pref in allPrefs():
 | 
					  for pref in allPrefs():
 | 
				
			||||||
    let default =
 | 
					    let
 | 
				
			||||||
      case pref.kind
 | 
					      ident = ident(pref.name)
 | 
				
			||||||
      of checkbox: newLit(pref.defaultState)
 | 
					      name = newLit(pref.name)
 | 
				
			||||||
      of select: newLit(pref.defaultOption)
 | 
					      default =
 | 
				
			||||||
      of input: newLit(pref.defaultInput)
 | 
					        case pref.kind
 | 
				
			||||||
 | 
					        of checkbox: newLit(pref.defaultState)
 | 
				
			||||||
 | 
					        of select: newLit(pref.defaultOption)
 | 
				
			||||||
 | 
					        of input: newLit(pref.defaultInput)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    result.add nnkExprColonExpr.newTree(ident(pref.name), default)
 | 
					    result.add quote do:
 | 
				
			||||||
 | 
					      defaultPrefs.`ident` = cfg.get("Preferences", `name`, `default`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro genCookiePrefs*(): untyped =
 | 
				
			||||||
 | 
					  result = nnkStmtList.newTree()
 | 
				
			||||||
 | 
					  let cookies = ident("cookies")
 | 
				
			||||||
 | 
					  for pref in allPrefs():
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      name = pref.name
 | 
				
			||||||
 | 
					      ident = ident(pref.name)
 | 
				
			||||||
 | 
					      kind = newLit(pref.kind)
 | 
				
			||||||
 | 
					      options = pref.options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    result.add quote do:
 | 
				
			||||||
 | 
					      if `name` in `cookies`:
 | 
				
			||||||
 | 
					        let value = `cookies`[`name`]
 | 
				
			||||||
 | 
					        when `kind` == input or `name` == "theme":
 | 
				
			||||||
 | 
					          result.`ident` = value
 | 
				
			||||||
 | 
					        elif `kind` == checkbox:
 | 
				
			||||||
 | 
					          result.`ident` = value == "on"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					          if value in `options`: result.`ident` = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro genUpdatePrefs*(): untyped =
 | 
					macro genUpdatePrefs*(): untyped =
 | 
				
			||||||
  result = nnkStmtList.newTree()
 | 
					  result = nnkStmtList.newTree()
 | 
				
			||||||
 | 
					  let req = ident("request")
 | 
				
			||||||
  for pref in allPrefs():
 | 
					  for pref in allPrefs():
 | 
				
			||||||
    let ident = ident(pref.name)
 | 
					    let
 | 
				
			||||||
    let value = nnkPrefix.newTree(ident("@"), newLit(pref.name))
 | 
					      name = newLit(pref.name)
 | 
				
			||||||
 | 
					      kind = newLit(pref.kind)
 | 
				
			||||||
 | 
					      options = newLit(pref.options)
 | 
				
			||||||
 | 
					      default = nnkDotExpr.newTree(ident("defaultPrefs"), ident(pref.name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case pref.kind
 | 
					    result.add quote do:
 | 
				
			||||||
    of checkbox:
 | 
					      let val = @`name`
 | 
				
			||||||
      result.add quote do: prefs.`ident` = `value` == "on"
 | 
					      let isDefault =
 | 
				
			||||||
    of input:
 | 
					        when `kind` == input or `name` == "theme":
 | 
				
			||||||
      result.add quote do: prefs.`ident` = xmltree.escape(strip(`value`))
 | 
					          if `default`.len != val.len: false
 | 
				
			||||||
    of select:
 | 
					          else: val == `default`
 | 
				
			||||||
      let name = pref.name
 | 
					        elif `kind` == checkbox:
 | 
				
			||||||
      let options = pref.options
 | 
					          (val == "on") == `default`
 | 
				
			||||||
      let default = pref.defaultOption
 | 
					        else:
 | 
				
			||||||
      result.add quote do:
 | 
					          val notin `options` or val == `default`
 | 
				
			||||||
        if `name` == "theme": prefs.`ident` = `value`
 | 
					 | 
				
			||||||
        elif `value` in `options`: prefs.`ident` = `value`
 | 
					 | 
				
			||||||
        else: prefs.`ident` = `default`
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  result.add quote do:
 | 
					      if isDefault:
 | 
				
			||||||
    cache(prefs)
 | 
					        savePref(`name`, "", `req`, expire=true)
 | 
				
			||||||
 | 
					      else:
 | 
				
			||||||
 | 
					        savePref(`name`, val, `req`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro genResetPrefs*(): untyped =
 | 
				
			||||||
 | 
					  result = nnkStmtList.newTree()
 | 
				
			||||||
 | 
					  let req = ident("request")
 | 
				
			||||||
 | 
					  for pref in allPrefs():
 | 
				
			||||||
 | 
					    let name = newLit(pref.name)
 | 
				
			||||||
 | 
					    result.add quote do:
 | 
				
			||||||
 | 
					      savePref(`name`, "", `req`, expire=true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro genPrefsType*(): untyped =
 | 
					macro genPrefsType*(): untyped =
 | 
				
			||||||
  let name = nnkPostfix.newTree(ident("*"), ident("Prefs"))
 | 
					  let name = nnkPostfix.newTree(ident("*"), ident("Prefs"))
 | 
				
			||||||
  result = quote do:
 | 
					  result = quote do:
 | 
				
			||||||
    type `name` = object
 | 
					    type `name` = object
 | 
				
			||||||
      id* {.pk, ro.}: int
 | 
					      discard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for pref in allPrefs():
 | 
					  for pref in allPrefs():
 | 
				
			||||||
    result[0][2][2].add nnkIdentDefs.newTree(
 | 
					    result[0][2][2].add nnkIdentDefs.newTree(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,9 +16,6 @@ proc findThemes*(dir: string): seq[string] =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc createPrefRouter*(cfg: Config) =
 | 
					proc createPrefRouter*(cfg: Config) =
 | 
				
			||||||
  router preferences:
 | 
					  router preferences:
 | 
				
			||||||
    template savePrefs(): untyped =
 | 
					 | 
				
			||||||
      setCookie("preferences", $prefs.id, daysForward(360), httpOnly=true, secure=cfg.useHttps)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get "/settings":
 | 
					    get "/settings":
 | 
				
			||||||
      let html = renderPreferences(cookiePrefs(), refPath(), findThemes(cfg.staticDir))
 | 
					      let html = renderPreferences(cookiePrefs(), refPath(), findThemes(cfg.staticDir))
 | 
				
			||||||
      resp renderMain(html, request, cfg, "Preferences")
 | 
					      resp renderMain(html, request, cfg, "Preferences")
 | 
				
			||||||
| 
						 | 
					@ -27,27 +24,14 @@ proc createPrefRouter*(cfg: Config) =
 | 
				
			||||||
      redirect("/settings")
 | 
					      redirect("/settings")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    post "/saveprefs":
 | 
					    post "/saveprefs":
 | 
				
			||||||
      var prefs = cookiePrefs()
 | 
					 | 
				
			||||||
      genUpdatePrefs()
 | 
					      genUpdatePrefs()
 | 
				
			||||||
      savePrefs()
 | 
					 | 
				
			||||||
      redirect(refPath())
 | 
					      redirect(refPath())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    post "/resetprefs":
 | 
					    post "/resetprefs":
 | 
				
			||||||
      var prefs = cookiePrefs()
 | 
					      genResetPrefs()
 | 
				
			||||||
      resetPrefs(prefs, cfg)
 | 
					 | 
				
			||||||
      savePrefs()
 | 
					 | 
				
			||||||
      redirect($(parseUri("/settings") ? filterParams(request.params)))
 | 
					      redirect($(parseUri("/settings") ? filterParams(request.params)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    post "/enablehls":
 | 
					    post "/enablehls":
 | 
				
			||||||
      var prefs = cookiePrefs()
 | 
					      savePref("hlsPlayback", "on", request)
 | 
				
			||||||
      prefs.hlsPlayback = true
 | 
					 | 
				
			||||||
      cache(prefs)
 | 
					 | 
				
			||||||
      savePrefs()
 | 
					 | 
				
			||||||
      redirect(refPath())
 | 
					      redirect(refPath())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    before:
 | 
					 | 
				
			||||||
      if @"theme".len > 0:
 | 
					 | 
				
			||||||
        var prefs = cookiePrefs()
 | 
					 | 
				
			||||||
        prefs.theme = @"theme".capitalizeAscii.replace("_", " ")
 | 
					 | 
				
			||||||
        cache(prefs)
 | 
					 | 
				
			||||||
        savePrefs()
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,15 @@
 | 
				
			||||||
import strutils, sequtils, asyncdispatch, httpclient
 | 
					import strutils, sequtils, asyncdispatch, httpclient
 | 
				
			||||||
 | 
					from jester import Request
 | 
				
			||||||
import ../utils, ../prefs
 | 
					import ../utils, ../prefs
 | 
				
			||||||
export utils, prefs
 | 
					export utils, prefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template savePref*(pref, value: string; req: Request; expire=false): typed =
 | 
				
			||||||
 | 
					  if not expire or pref in cookies(req):
 | 
				
			||||||
 | 
					    setCookie(pref, value, daysForward(when expire: -10 else: 360),
 | 
				
			||||||
 | 
					              httpOnly=true, secure=cfg.useHttps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template cookiePrefs*(): untyped {.dirty.} =
 | 
					template cookiePrefs*(): untyped {.dirty.} =
 | 
				
			||||||
  getPrefs(request.cookies.getOrDefault("preferences"), cfg)
 | 
					  getPrefs(cookies(request))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template getPath*(): untyped {.dirty.} =
 | 
					template getPath*(): untyped {.dirty.} =
 | 
				
			||||||
  $(parseUri(request.path) ? filterParams(request.params))
 | 
					  $(parseUri(request.path) ? filterParams(request.params))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@ import norm/sqlite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prefs_impl
 | 
					import prefs_impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					genPrefsType()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type
 | 
					type
 | 
				
			||||||
  VideoType* = enum
 | 
					  VideoType* = enum
 | 
				
			||||||
    vmap, m3u8, mp4
 | 
					    vmap, m3u8, mp4
 | 
				
			||||||
| 
						 | 
					@ -59,7 +61,6 @@ dbTypes:
 | 
				
			||||||
          formatIt: dbValue(getTime().toUnix())
 | 
					          formatIt: dbValue(getTime().toUnix())
 | 
				
			||||||
        .}: Time
 | 
					        .}: Time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
genPrefsType()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type
 | 
					type
 | 
				
			||||||
  QueryKind* = enum
 | 
					  QueryKind* = enum
 | 
				
			||||||
| 
						 | 
					@ -187,7 +188,6 @@ type
 | 
				
			||||||
    hostname*: string
 | 
					    hostname*: string
 | 
				
			||||||
    cacheDir*: string
 | 
					    cacheDir*: string
 | 
				
			||||||
    profileCacheTime*: int
 | 
					    profileCacheTime*: int
 | 
				
			||||||
    defaultTheme*: string
 | 
					 | 
				
			||||||
    hmacKey*: string
 | 
					    hmacKey*: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc contains*(thread: Chain; tweet: Tweet): bool =
 | 
					proc contains*(thread: Chain; tweet: Tweet): bool =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,8 +82,10 @@ proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc renderMain*(body: VNode; req: Request; cfg: Config; titleText=""; desc="";
 | 
					proc renderMain*(body: VNode; req: Request; cfg: Config; titleText=""; desc="";
 | 
				
			||||||
                 rss=""; video=""; images: seq[string] = @[]; ogTitle=""): string =
 | 
					                 rss=""; video=""; images: seq[string] = @[]; ogTitle=""): string =
 | 
				
			||||||
  let prefs = getPrefs(req.cookies.getOrDefault("preferences"), cfg)
 | 
					  let prefs = getPrefs(req.cookies)
 | 
				
			||||||
  let theme = toLowerAscii(prefs.theme).replace(" ", "_")
 | 
					  var theme = toLowerAscii(prefs.theme).replace(" ", "_")
 | 
				
			||||||
 | 
					  if "theme" in req.params:
 | 
				
			||||||
 | 
					    theme = toLowerAscii(req.params["theme"]).replace(" ", "_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let node = buildHtml(html(lang="en")):
 | 
					  let node = buildHtml(html(lang="en")):
 | 
				
			||||||
    renderHead(prefs, cfg, titleText, desc, video, images, ogTitle):
 | 
					    renderHead(prefs, cfg, titleText, desc, video, images, ogTitle):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue