Refactor hostname to be a runtime option
Add a `hostname` field under Server in your conf file, see the updated nitter.conf in the repo for an example. The compile-time option (-d:hostname) is no longer used.
This commit is contained in:
		
							parent
							
								
									3218cc4069
								
							
						
					
					
						commit
						de62eedea5
					
				
							
								
								
									
										17
									
								
								README.md
								
								
								
								
							
							
						
						
									
										17
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -52,24 +52,27 @@ Twitter account.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To compile Nitter you need a Nim installation, see [nim-lang.org](https://nim-lang.org/install.html) for details. It is possible to install it system-wide or in the user directory you create below.
 | 
					To compile Nitter you need a Nim installation, see
 | 
				
			||||||
 | 
					[nim-lang.org](https://nim-lang.org/install.html) for details. It is possible to
 | 
				
			||||||
 | 
					install it system-wide or in the user directory you create below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You also need to install `libsass` to compile the scss files. On Ubuntu and Debian, you can use `libsass-dev`.
 | 
					You also need to install `libsass` to compile the scss files. On Ubuntu and
 | 
				
			||||||
 | 
					Debian, you can use `libsass-dev`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# useradd -m nitter
 | 
					# useradd -m nitter
 | 
				
			||||||
# su nitter
 | 
					# su nitter
 | 
				
			||||||
$ git clone https://github.com/zedeus/nitter
 | 
					$ git clone https://github.com/zedeus/nitter
 | 
				
			||||||
$ cd nitter
 | 
					$ cd nitter
 | 
				
			||||||
$ nimble build -d:release -d:hostname="..."
 | 
					$ nimble build -d:release
 | 
				
			||||||
$ nimble scss
 | 
					$ nimble scss
 | 
				
			||||||
$ mkdir ./tmp
 | 
					$ mkdir ./tmp
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Change `-d:hostname="..."` to your instance's domain, eg. `-d:hostname:"nitter.net"`.
 | 
					Set your hostname, port and page title in `nitter.conf`, then run Nitter by
 | 
				
			||||||
Set your port and page title in `nitter.conf`, then run Nitter by executing `./nitter`.
 | 
					executing `./nitter`. You should run Nitter behind a reverse proxy such as
 | 
				
			||||||
You should run Nitter behind a reverse proxy such as
 | 
					[Nginx](https://github.com/zedeus/nitter/wiki/Nginx) or Apache for better
 | 
				
			||||||
[Nginx](https://github.com/zedeus/nitter/wiki/Nginx) or Apache for better security.
 | 
					security.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To build and run Nitter in Docker:
 | 
					To build and run Nitter in Docker:
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,9 @@
 | 
				
			||||||
address = "0.0.0.0"
 | 
					address = "0.0.0.0"
 | 
				
			||||||
port = 8080
 | 
					port = 8080
 | 
				
			||||||
https = true  # disable to enable cookies when not using https
 | 
					https = true  # disable to enable cookies when not using https
 | 
				
			||||||
title = "nitter"
 | 
					 | 
				
			||||||
staticDir = "./public"
 | 
					staticDir = "./public"
 | 
				
			||||||
 | 
					title = "nitter"
 | 
				
			||||||
 | 
					hostname = "nitter.net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Cache]
 | 
					[Cache]
 | 
				
			||||||
directory = "./tmp"
 | 
					directory = "./tmp"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,9 @@ proc getConfig*(path: string): 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),
 | 
				
			||||||
    title: cfg.get("Server", "title", "Nitter"),
 | 
					 | 
				
			||||||
    staticDir: cfg.get("Server", "staticDir", "./public"),
 | 
					    staticDir: cfg.get("Server", "staticDir", "./public"),
 | 
				
			||||||
 | 
					    title: cfg.get("Server", "title", "Nitter"),
 | 
				
			||||||
 | 
					    hostname: cfg.get("Server", "hostname", "nitter.net"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,8 +11,6 @@ const
 | 
				
			||||||
  twRegex = re"(www.|mobile.)?twitter.com"
 | 
					  twRegex = re"(www.|mobile.)?twitter.com"
 | 
				
			||||||
  nbsp = $Rune(0x000A0)
 | 
					  nbsp = $Rune(0x000A0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const hostname {.strdefine.} = "nitter.net"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc stripText*(text: string): string =
 | 
					proc stripText*(text: string): string =
 | 
				
			||||||
  text.replace(nbsp, " ").strip()
 | 
					  text.replace(nbsp, " ").strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,14 +27,14 @@ proc shortLink*(text: string; length=28): string =
 | 
				
			||||||
  if result.len > length:
 | 
					  if result.len > length:
 | 
				
			||||||
    result = result[0 ..< length] & "…"
 | 
					    result = result[0 ..< length] & "…"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc replaceUrl*(url: string; prefs: Prefs; rss=false): string =
 | 
					proc replaceUrl*(url: string; prefs: Prefs; absolute=""): string =
 | 
				
			||||||
  result = url
 | 
					  result = url
 | 
				
			||||||
  if prefs.replaceYouTube.len > 0:
 | 
					  if prefs.replaceYouTube.len > 0:
 | 
				
			||||||
    result = result.replace(ytRegex, prefs.replaceYouTube)
 | 
					    result = result.replace(ytRegex, prefs.replaceYouTube)
 | 
				
			||||||
  if prefs.replaceTwitter.len > 0:
 | 
					  if prefs.replaceTwitter.len > 0:
 | 
				
			||||||
    result = result.replace(twRegex, prefs.replaceTwitter)
 | 
					    result = result.replace(twRegex, prefs.replaceTwitter)
 | 
				
			||||||
  if rss:
 | 
					  if absolute.len > 0:
 | 
				
			||||||
    result = result.replace("href=\"/", "href=\"https://" & hostname & "/")
 | 
					    result = result.replace("href=\"/", "href=\"https://" & absolute & "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc proxifyVideo*(manifest: string; proxy: bool): string =
 | 
					proc proxifyVideo*(manifest: string; proxy: bool): string =
 | 
				
			||||||
  proc cb(m: RegexMatch; s: string): string =
 | 
					  proc cb(m: RegexMatch; s: string): string =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,10 +27,10 @@ settings:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
routes:
 | 
					routes:
 | 
				
			||||||
  get "/":
 | 
					  get "/":
 | 
				
			||||||
    resp renderMain(renderSearch(), request, cfg.title)
 | 
					    resp renderMain(renderSearch(), request, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get "/about":
 | 
					  get "/about":
 | 
				
			||||||
    resp renderMain(renderAbout(), request, cfg.title)
 | 
					    resp renderMain(renderAbout(), request, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get "/explore":
 | 
					  get "/explore":
 | 
				
			||||||
    redirect("/about")
 | 
					    redirect("/about")
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ routes:
 | 
				
			||||||
    redirect(replaceUrl(url, cookiePrefs()))
 | 
					    redirect(replaceUrl(url, cookiePrefs()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  error Http404:
 | 
					  error Http404:
 | 
				
			||||||
    resp showError("Page not found", cfg.title)
 | 
					    resp showError("Page not found", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  extend unsupported, ""
 | 
					  extend unsupported, ""
 | 
				
			||||||
  extend preferences, ""
 | 
					  extend preferences, ""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,10 @@ withDb:
 | 
				
			||||||
  except DbError:
 | 
					  except DbError:
 | 
				
			||||||
    discard
 | 
					    discard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc getDefaultPrefs(hostname: string): Prefs =
 | 
				
			||||||
 | 
					  result = genDefaultPrefs()
 | 
				
			||||||
 | 
					  result.replaceTwitter = hostname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc cache*(prefs: var Prefs) =
 | 
					proc cache*(prefs: var Prefs) =
 | 
				
			||||||
  withDb:
 | 
					  withDb:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
| 
						 | 
					@ -31,17 +35,18 @@ proc cache*(prefs: var Prefs) =
 | 
				
			||||||
    except AssertionError, KeyError:
 | 
					    except AssertionError, KeyError:
 | 
				
			||||||
      prefs.insert()
 | 
					      prefs.insert()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc getPrefs*(id: string): Prefs =
 | 
					proc getPrefs*(id, hostname: string): Prefs =
 | 
				
			||||||
  if id.len == 0: return genDefaultPrefs()
 | 
					  if id.len == 0:
 | 
				
			||||||
 | 
					    return getDefaultPrefs(hostname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  withDb:
 | 
					  withDb:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
      result.getOne("id = ?", id)
 | 
					      result.getOne("id = ?", id)
 | 
				
			||||||
    except KeyError:
 | 
					    except KeyError:
 | 
				
			||||||
      result = genDefaultPrefs()
 | 
					      result = getDefaultPrefs(hostname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc resetPrefs*(prefs: var Prefs) =
 | 
					proc resetPrefs*(prefs: var Prefs; hostname: string) =
 | 
				
			||||||
  var defPrefs = genDefaultPrefs()
 | 
					  var defPrefs = getDefaultPrefs(hostname)
 | 
				
			||||||
  defPrefs.id = prefs.id
 | 
					  defPrefs.id = prefs.id
 | 
				
			||||||
  cache(defPrefs)
 | 
					  cache(defPrefs)
 | 
				
			||||||
  prefs = defPrefs
 | 
					  prefs = defPrefs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,5 @@
 | 
				
			||||||
import macros, tables, strutils, xmltree
 | 
					import macros, tables, strutils, xmltree
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const hostname {.strdefine.} = "nitter.net"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type
 | 
					type
 | 
				
			||||||
  PrefKind* = enum
 | 
					  PrefKind* = enum
 | 
				
			||||||
    checkbox, select, input
 | 
					    checkbox, select, input
 | 
				
			||||||
| 
						 | 
					@ -24,7 +22,7 @@ const prefList*: OrderedTable[string, seq[Pref]] = {
 | 
				
			||||||
  "Privacy": @[
 | 
					  "Privacy": @[
 | 
				
			||||||
    Pref(kind: input, name: "replaceTwitter",
 | 
					    Pref(kind: input, name: "replaceTwitter",
 | 
				
			||||||
         label: "Replace Twitter links with Nitter (blank to disable)",
 | 
					         label: "Replace Twitter links with Nitter (blank to disable)",
 | 
				
			||||||
         defaultInput: hostname, placeholder: "Nitter hostname"),
 | 
					         defaultInput: "nitter.net", placeholder: "Nitter hostname"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Pref(kind: input, name: "replaceYouTube",
 | 
					    Pref(kind: input, name: "replaceYouTube",
 | 
				
			||||||
         label: "Replace YouTube links with Invidious (blank to disable)",
 | 
					         label: "Replace YouTube links with Invidious (blank to disable)",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,10 @@ import ../views/[general, timeline, list]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template respList*(list, timeline: typed) =
 | 
					template respList*(list, timeline: typed) =
 | 
				
			||||||
  if list.minId.len == 0:
 | 
					  if list.minId.len == 0:
 | 
				
			||||||
    halt Http404, showError("List \"" & @"list" & "\" not found", cfg.title)
 | 
					    halt Http404, showError("List \"" & @"list" & "\" not found", cfg)
 | 
				
			||||||
  let html = renderList(timeline, list.query, @"name", @"list")
 | 
					  let html = renderList(timeline, list.query, @"name", @"list")
 | 
				
			||||||
  let rss = "/$1/lists/$2/rss" % [@"name", @"list"]
 | 
					  let rss = "/$1/lists/$2/rss" % [@"name", @"list"]
 | 
				
			||||||
  resp renderMain(html, request, cfg.title, rss=rss)
 | 
					  resp renderMain(html, request, cfg, rss=rss)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc createListRouter*(cfg: Config) =
 | 
					proc createListRouter*(cfg: Config) =
 | 
				
			||||||
  router list:
 | 
					  router list:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,7 @@ proc createMediaRouter*(cfg: Config) =
 | 
				
			||||||
      let prefs = cookiePrefs()
 | 
					      let prefs = cookiePrefs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if getHmac(url) != @"sig":
 | 
					      if getHmac(url) != @"sig":
 | 
				
			||||||
        resp showError("Failed to verify signature", cfg.title)
 | 
					        resp showError("Failed to verify signature", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let client = newAsyncHttpClient()
 | 
					      let client = newAsyncHttpClient()
 | 
				
			||||||
      var content = await client.getContent(url)
 | 
					      var content = await client.getContent(url)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ proc createPrefRouter*(cfg: Config) =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/settings":
 | 
					    get "/settings":
 | 
				
			||||||
      let html = renderPreferences(cookiePrefs(), refPath())
 | 
					      let html = renderPreferences(cookiePrefs(), refPath())
 | 
				
			||||||
      resp renderMain(html, request, cfg.title, "Preferences")
 | 
					      resp renderMain(html, request, cfg, "Preferences")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/settings/@i?":
 | 
					    get "/settings/@i?":
 | 
				
			||||||
      redirect("/settings")
 | 
					      redirect("/settings")
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ proc createPrefRouter*(cfg: Config) =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    post "/resetprefs":
 | 
					    post "/resetprefs":
 | 
				
			||||||
      var prefs = cookiePrefs()
 | 
					      var prefs = cookiePrefs()
 | 
				
			||||||
      resetPrefs(prefs)
 | 
					      resetPrefs(prefs, cfg.hostname)
 | 
				
			||||||
      savePrefs()
 | 
					      savePrefs()
 | 
				
			||||||
      redirect($(parseUri("/settings") ? filterParams(request.params)))
 | 
					      redirect($(parseUri("/settings") ? filterParams(request.params)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import ../utils, ../prefs
 | 
				
			||||||
export utils, prefs
 | 
					export utils, prefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template cookiePrefs*(): untyped {.dirty.} =
 | 
					template cookiePrefs*(): untyped {.dirty.} =
 | 
				
			||||||
  getPrefs(request.cookies.getOrDefault("preferences"))
 | 
					  getPrefs(request.cookies.getOrDefault("preferences"), cfg.hostname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template getPath*(): untyped {.dirty.} =
 | 
					template getPath*(): untyped {.dirty.} =
 | 
				
			||||||
  $(parseUri(request.path) ? filterParams(request.params))
 | 
					  $(parseUri(request.path) ? filterParams(request.params))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,46 +8,46 @@ import ../views/general
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include "../views/rss.nimf"
 | 
					include "../views/rss.nimf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc showRss*(name: string; query: Query): Future[string] {.async.} =
 | 
					proc showRss*(name, hostname: string; query: Query): Future[string] {.async.} =
 | 
				
			||||||
  let (profile, timeline, _) = await fetchSingleTimeline(name, "", getAgent(), query)
 | 
					  let (profile, timeline, _) = await fetchSingleTimeline(name, "", getAgent(), query)
 | 
				
			||||||
  if timeline != nil:
 | 
					  if timeline != nil:
 | 
				
			||||||
    return renderTimelineRss(timeline, profile)
 | 
					    return renderTimelineRss(timeline, profile, hostname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template respRss*(rss: typed) =
 | 
					template respRss*(rss: typed) =
 | 
				
			||||||
  if rss.len == 0:
 | 
					  if rss.len == 0:
 | 
				
			||||||
    halt Http404, showError("User \"" & @"name" & "\" not found", cfg.title)
 | 
					    halt Http404, showError("User \"" & @"name" & "\" not found", cfg)
 | 
				
			||||||
  resp rss, "application/rss+xml;charset=utf-8"
 | 
					  resp rss, "application/rss+xml;charset=utf-8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc createRssRouter*(cfg: Config) =
 | 
					proc createRssRouter*(cfg: Config) =
 | 
				
			||||||
  router rss:
 | 
					  router rss:
 | 
				
			||||||
    get "/search/rss":
 | 
					    get "/search/rss":
 | 
				
			||||||
      if @"q".len > 200:
 | 
					      if @"q".len > 200:
 | 
				
			||||||
        resp Http400, showError("Search input too long.", cfg.title)
 | 
					        resp Http400, showError("Search input too long.", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let query = initQuery(params(request))
 | 
					      let query = initQuery(params(request))
 | 
				
			||||||
      if query.kind != tweets:
 | 
					      if query.kind != tweets:
 | 
				
			||||||
        resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg.title)
 | 
					        resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let tweets = await getSearch[Tweet](query, "", getAgent())
 | 
					      let tweets = await getSearch[Tweet](query, "", getAgent())
 | 
				
			||||||
      respRss(renderSearchRss(tweets.content, query.text, genQueryUrl(query)))
 | 
					      respRss(renderSearchRss(tweets.content, query.text, genQueryUrl(query), cfg.hostname))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/rss":
 | 
					    get "/@name/rss":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      respRss(await showRss(@"name", Query()))
 | 
					      respRss(await showRss(@"name", cfg.hostname, Query()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/with_replies/rss":
 | 
					    get "/@name/with_replies/rss":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      respRss(await showRss(@"name", getReplyQuery(@"name")))
 | 
					      respRss(await showRss(@"name", cfg.hostname, getReplyQuery(@"name")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/media/rss":
 | 
					    get "/@name/media/rss":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      respRss(await showRss(@"name", getMediaQuery(@"name")))
 | 
					      respRss(await showRss(@"name", cfg.hostname, getMediaQuery(@"name")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/search/rss":
 | 
					    get "/@name/search/rss":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      respRss(await showRss(@"name", initQuery(params(request), name=(@"name"))))
 | 
					      respRss(await showRss(@"name", cfg.hostname, initQuery(params(request), name=(@"name"))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/lists/@list/rss":
 | 
					    get "/@name/lists/@list/rss":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      let list = await getListTimeline(@"name", @"list", getAgent(), "")
 | 
					      let list = await getListTimeline(@"name", @"list", getAgent(), "")
 | 
				
			||||||
      respRss(renderListRss(list.content, @"name", @"list"))
 | 
					      respRss(renderListRss(list.content, @"name", @"list", cfg.hostname))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ proc createSearchRouter*(cfg: Config) =
 | 
				
			||||||
  router search:
 | 
					  router search:
 | 
				
			||||||
    get "/search/?":
 | 
					    get "/search/?":
 | 
				
			||||||
      if @"q".len > 200:
 | 
					      if @"q".len > 200:
 | 
				
			||||||
        resp Http400, showError("Search input too long.", cfg.title)
 | 
					        resp Http400, showError("Search input too long.", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let prefs = cookiePrefs()
 | 
					      let prefs = cookiePrefs()
 | 
				
			||||||
      let query = initQuery(params(request))
 | 
					      let query = initQuery(params(request))
 | 
				
			||||||
| 
						 | 
					@ -22,14 +22,14 @@ proc createSearchRouter*(cfg: Config) =
 | 
				
			||||||
        if "," in @"q":
 | 
					        if "," in @"q":
 | 
				
			||||||
          redirect("/" & @"q")
 | 
					          redirect("/" & @"q")
 | 
				
			||||||
        let users = await getSearch[Profile](query, @"max_position", getAgent())
 | 
					        let users = await getSearch[Profile](query, @"max_position", getAgent())
 | 
				
			||||||
        resp renderMain(renderUserSearch(users, prefs), request, cfg.title)
 | 
					        resp renderMain(renderUserSearch(users, prefs), request, cfg)
 | 
				
			||||||
      of tweets:
 | 
					      of tweets:
 | 
				
			||||||
        let tweets = await getSearch[Tweet](query, @"max_position", getAgent())
 | 
					        let tweets = await getSearch[Tweet](query, @"max_position", getAgent())
 | 
				
			||||||
        let rss = "/search/rss?" & genQueryUrl(query)
 | 
					        let rss = "/search/rss?" & genQueryUrl(query)
 | 
				
			||||||
        resp renderMain(renderTweetSearch(tweets, prefs, getPath()), request,
 | 
					        resp renderMain(renderTweetSearch(tweets, prefs, getPath()),
 | 
				
			||||||
                        cfg.title, rss=rss)
 | 
					                        request, cfg, rss=rss)
 | 
				
			||||||
      else:
 | 
					      else:
 | 
				
			||||||
        halt Http404, showError("Invalid search", cfg.title)
 | 
					        halt Http404, showError("Invalid search", cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/hashtag/@hash":
 | 
					    get "/hashtag/@hash":
 | 
				
			||||||
      redirect("/search?q=" & encodeUrl("#" & @"hash"))
 | 
					      redirect("/search?q=" & encodeUrl("#" & @"hash"))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ proc createStatusRouter*(cfg: Config) =
 | 
				
			||||||
        var error = "Tweet not found"
 | 
					        var error = "Tweet not found"
 | 
				
			||||||
        if conversation != nil and conversation.tweet.tombstone.len > 0:
 | 
					        if conversation != nil and conversation.tweet.tombstone.len > 0:
 | 
				
			||||||
          error = conversation.tweet.tombstone
 | 
					          error = conversation.tweet.tombstone
 | 
				
			||||||
        halt Http404, showError(error, cfg.title)
 | 
					        halt Http404, showError(error, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let
 | 
					      let
 | 
				
			||||||
        title = pageTitle(conversation.tweet.profile)
 | 
					        title = pageTitle(conversation.tweet.profile)
 | 
				
			||||||
| 
						 | 
					@ -32,15 +32,15 @@ proc createStatusRouter*(cfg: Config) =
 | 
				
			||||||
      if conversation.tweet.video.isSome():
 | 
					      if conversation.tweet.video.isSome():
 | 
				
			||||||
        let thumb = get(conversation.tweet.video).thumb
 | 
					        let thumb = get(conversation.tweet.video).thumb
 | 
				
			||||||
        let vidUrl = getVideoEmbed(conversation.tweet.id)
 | 
					        let vidUrl = getVideoEmbed(conversation.tweet.id)
 | 
				
			||||||
        resp renderMain(html, request, cfg.title, title, desc, images = @[thumb],
 | 
					        resp renderMain(html, request, cfg, title, desc, images = @[thumb],
 | 
				
			||||||
                        `type`="video", video=vidUrl)
 | 
					                        `type`="video", video=vidUrl)
 | 
				
			||||||
      elif conversation.tweet.gif.isSome():
 | 
					      elif conversation.tweet.gif.isSome():
 | 
				
			||||||
        let thumb = get(conversation.tweet.gif).thumb
 | 
					        let thumb = get(conversation.tweet.gif).thumb
 | 
				
			||||||
        let vidUrl = getVideoEmbed(conversation.tweet.id)
 | 
					        let vidUrl = getVideoEmbed(conversation.tweet.id)
 | 
				
			||||||
        resp renderMain(html, request, cfg.title, title, desc, images = @[thumb],
 | 
					        resp renderMain(html, request, cfg, title, desc, images = @[thumb],
 | 
				
			||||||
                        `type`="video", video=vidUrl)
 | 
					                        `type`="video", video=vidUrl)
 | 
				
			||||||
      else:
 | 
					      else:
 | 
				
			||||||
        resp renderMain(html, request, cfg.title, title, desc,
 | 
					        resp renderMain(html, request, cfg, title, desc,
 | 
				
			||||||
                        images=conversation.tweet.photos, `type`="photo")
 | 
					                        images=conversation.tweet.photos, `type`="photo")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/status/@id/photo/@i":
 | 
					    get "/@name/status/@id/photo/@i":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ proc get*(req: Request; key: string): string =
 | 
				
			||||||
  if key in params(req): params(req)[key]
 | 
					  if key in params(req): params(req)[key]
 | 
				
			||||||
  else: ""
 | 
					  else: ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc showTimeline*(request: Request; query: Query; title, rss: string): Future[string] {.async.} =
 | 
					proc showTimeline*(request: Request; query: Query; cfg: Config; rss: string): Future[string] {.async.} =
 | 
				
			||||||
  let
 | 
					  let
 | 
				
			||||||
    agent = getAgent()
 | 
					    agent = getAgent()
 | 
				
			||||||
    prefs = cookiePrefs()
 | 
					    prefs = cookiePrefs()
 | 
				
			||||||
| 
						 | 
					@ -63,16 +63,16 @@ proc showTimeline*(request: Request; query: Query; title, rss: string): Future[s
 | 
				
			||||||
    let (p, t, r) = await fetchSingleTimeline(names[0], after, agent, query)
 | 
					    let (p, t, r) = await fetchSingleTimeline(names[0], after, agent, query)
 | 
				
			||||||
    if p.username.len == 0: return
 | 
					    if p.username.len == 0: return
 | 
				
			||||||
    let pHtml = renderProfile(p, t, r, prefs, getPath())
 | 
					    let pHtml = renderProfile(p, t, r, prefs, getPath())
 | 
				
			||||||
    return renderMain(pHtml, request, title, pageTitle(p), pageDesc(p), rss=rss)
 | 
					    return renderMain(pHtml, request, cfg, pageTitle(p), pageDesc(p), rss=rss)
 | 
				
			||||||
  else:
 | 
					  else:
 | 
				
			||||||
    let
 | 
					    let
 | 
				
			||||||
      timeline = await fetchMultiTimeline(names, after, agent, query)
 | 
					      timeline = await fetchMultiTimeline(names, after, agent, query)
 | 
				
			||||||
      html = renderTweetSearch(timeline, prefs, getPath())
 | 
					      html = renderTweetSearch(timeline, prefs, getPath())
 | 
				
			||||||
    return renderMain(html, request, title, "Multi")
 | 
					    return renderMain(html, request, cfg, "Multi")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template respTimeline*(timeline: typed) =
 | 
					template respTimeline*(timeline: typed) =
 | 
				
			||||||
  if timeline.len == 0:
 | 
					  if timeline.len == 0:
 | 
				
			||||||
    halt Http404, showError("User \"" & @"name" & "\" not found", cfg.title)
 | 
					    halt Http404, showError("User \"" & @"name" & "\" not found", cfg)
 | 
				
			||||||
  resp timeline
 | 
					  resp timeline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc createTimelineRouter*(cfg: Config) =
 | 
					proc createTimelineRouter*(cfg: Config) =
 | 
				
			||||||
| 
						 | 
					@ -82,20 +82,20 @@ proc createTimelineRouter*(cfg: Config) =
 | 
				
			||||||
    get "/@name/?":
 | 
					    get "/@name/?":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      let rss = "/$1/rss" % @"name"
 | 
					      let rss = "/$1/rss" % @"name"
 | 
				
			||||||
      respTimeline(await showTimeline(request, Query(), cfg.title, rss))
 | 
					      respTimeline(await showTimeline(request, Query(), cfg, rss))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/with_replies":
 | 
					    get "/@name/with_replies":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      let rss = "/$1/with_replies/rss" % @"name"
 | 
					      let rss = "/$1/with_replies/rss" % @"name"
 | 
				
			||||||
      respTimeline(await showTimeline(request, getReplyQuery(@"name"), cfg.title, rss))
 | 
					      respTimeline(await showTimeline(request, getReplyQuery(@"name"), cfg, rss))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/media":
 | 
					    get "/@name/media":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      let rss = "/$1/media/rss" % @"name"
 | 
					      let rss = "/$1/media/rss" % @"name"
 | 
				
			||||||
      respTimeline(await showTimeline(request, getMediaQuery(@"name"), cfg.title, rss))
 | 
					      respTimeline(await showTimeline(request, getMediaQuery(@"name"), cfg, rss))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/@name/search":
 | 
					    get "/@name/search":
 | 
				
			||||||
      cond '.' notin @"name"
 | 
					      cond '.' notin @"name"
 | 
				
			||||||
      let query = initQuery(params(request), name=(@"name"))
 | 
					      let query = initQuery(params(request), name=(@"name"))
 | 
				
			||||||
      let rss = "/$1/search/rss?$2" % [@"name", genQueryUrl(query)]
 | 
					      let rss = "/$1/search/rss?$2" % [@"name", genQueryUrl(query)]
 | 
				
			||||||
      respTimeline(await showTimeline(request, query, cfg.title, rss))
 | 
					      respTimeline(await showTimeline(request, query, cfg, rss))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,14 +7,14 @@ import ../views/[general, about]
 | 
				
			||||||
proc createUnsupportedRouter*(cfg: Config) =
 | 
					proc createUnsupportedRouter*(cfg: Config) =
 | 
				
			||||||
  router unsupported:
 | 
					  router unsupported:
 | 
				
			||||||
    get "/about/feature":
 | 
					    get "/about/feature":
 | 
				
			||||||
      resp renderMain(renderFeature(), request, cfg.title)
 | 
					      resp renderMain(renderFeature(), request, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/intent/?@i?":
 | 
					    get "/intent/?@i?":
 | 
				
			||||||
      resp renderMain(renderFeature(), request, cfg.title)
 | 
					      resp renderMain(renderFeature(), request, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/login/?@i?":
 | 
					    get "/login/?@i?":
 | 
				
			||||||
      resp renderMain(renderFeature(), request, cfg.title)
 | 
					      resp renderMain(renderFeature(), request, cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get "/i/@i?/?@j?":
 | 
					    get "/i/@i?/?@j?":
 | 
				
			||||||
      cond @"i" != "status"
 | 
					      cond @"i" != "status"
 | 
				
			||||||
      resp renderMain(renderFeature(), request, cfg.title)
 | 
					      resp renderMain(renderFeature(), request, cfg)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -172,8 +172,9 @@ type
 | 
				
			||||||
    address*: string
 | 
					    address*: string
 | 
				
			||||||
    port*: int
 | 
					    port*: int
 | 
				
			||||||
    useHttps*: bool
 | 
					    useHttps*: bool
 | 
				
			||||||
    title*: string
 | 
					 | 
				
			||||||
    staticDir*: string
 | 
					    staticDir*: string
 | 
				
			||||||
 | 
					    title*: string
 | 
				
			||||||
 | 
					    hostname*: string
 | 
				
			||||||
    cacheDir*: string
 | 
					    cacheDir*: string
 | 
				
			||||||
    profileCacheTime*: int
 | 
					    profileCacheTime*: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,9 @@ proc renderNavbar*(title, rss: string; req: Request): VNode =
 | 
				
			||||||
        icon "info-circled", title="About", href="/about"
 | 
					        icon "info-circled", title="About", href="/about"
 | 
				
			||||||
        iconReferer "cog", "/settings", path, title="Preferences"
 | 
					        iconReferer "cog", "/settings", path, title="Preferences"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc renderMain*(body: VNode; req: Request; title="Nitter"; titleText=""; desc="";
 | 
					proc renderMain*(body: VNode; req: Request; cfg: Config; titleText=""; desc="";
 | 
				
			||||||
                 rss=""; `type`="article"; video=""; images: seq[string] = @[]): string =
 | 
					                 rss=""; `type`="article"; video=""; images: seq[string] = @[]): string =
 | 
				
			||||||
  let prefs = getPrefs(req.cookies.getOrDefault("preferences"))
 | 
					  let prefs = getPrefs(req.cookies.getOrDefault("preferences"), cfg.hostname)
 | 
				
			||||||
  let node = buildHtml(html(lang="en")):
 | 
					  let node = buildHtml(html(lang="en")):
 | 
				
			||||||
    head:
 | 
					    head:
 | 
				
			||||||
      link(rel="stylesheet", `type`="text/css", href="/css/style.css")
 | 
					      link(rel="stylesheet", `type`="text/css", href="/css/style.css")
 | 
				
			||||||
| 
						 | 
					@ -50,9 +50,9 @@ proc renderMain*(body: VNode; req: Request; title="Nitter"; titleText=""; desc="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      title:
 | 
					      title:
 | 
				
			||||||
        if titleText.len > 0:
 | 
					        if titleText.len > 0:
 | 
				
			||||||
          text titleText & " | " & title
 | 
					          text titleText & " | " & cfg.title
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
          text title
 | 
					          text cfg.title
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      meta(name="viewport", content="width=device-width, initial-scale=1.0")
 | 
					      meta(name="viewport", content="width=device-width, initial-scale=1.0")
 | 
				
			||||||
      meta(property="og:type", content=`type`)
 | 
					      meta(property="og:type", content=`type`)
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,7 @@ proc renderMain*(body: VNode; req: Request; title="Nitter"; titleText=""; desc="
 | 
				
			||||||
        meta(property="og:video:secure_url", content=video)
 | 
					        meta(property="og:video:secure_url", content=video)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    body:
 | 
					    body:
 | 
				
			||||||
      renderNavbar(title, rss, req)
 | 
					      renderNavbar(cfg.title, rss, req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tdiv(class="container"):
 | 
					      tdiv(class="container"):
 | 
				
			||||||
        body
 | 
					        body
 | 
				
			||||||
| 
						 | 
					@ -80,5 +80,5 @@ proc renderError*(error: string): VNode =
 | 
				
			||||||
    tdiv(class="error-panel"):
 | 
					    tdiv(class="error-panel"):
 | 
				
			||||||
      span: text error
 | 
					      span: text error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template showError*(error, title: string): string =
 | 
					template showError*(error: string; cfg: Config): string =
 | 
				
			||||||
  renderMain(renderError(error), request, title, "Error")
 | 
					  renderMain(renderError(error), request, cfg, "Error")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,12 @@
 | 
				
			||||||
#? stdtmpl(subsChar = '$', metaChad = '#')
 | 
					#? stdtmpl(subsChar = '$', metaChad = '#')
 | 
				
			||||||
#import strutils, xmltree, strformat
 | 
					#import strutils, xmltree, strformat
 | 
				
			||||||
#import ../types, ../utils, ../formatters
 | 
					#import ../types, ../utils, ../formatters
 | 
				
			||||||
#const hostname {.strdefine.} = "nitter.net"
 | 
					 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc getTitle(tweet: Tweet; prefs: Prefs): string =
 | 
					#proc getTitle(tweet: Tweet; prefs: Prefs; hostname: string): string =
 | 
				
			||||||
#if tweet.pinned: result = "Pinned: "
 | 
					#if tweet.pinned: result = "Pinned: "
 | 
				
			||||||
#elif tweet.retweet.isSome: result = "RT: "
 | 
					#elif tweet.retweet.isSome: result = "RT: "
 | 
				
			||||||
#end if
 | 
					#end if
 | 
				
			||||||
#result &= xmltree.escape(replaceUrl(tweet.text, prefs, rss=true))
 | 
					#result &= xmltree.escape(replaceUrl(tweet.text, prefs, absolute=hostname))
 | 
				
			||||||
#if result.len > 0: return
 | 
					#if result.len > 0: return
 | 
				
			||||||
#end if
 | 
					#end if
 | 
				
			||||||
#if tweet.photos.len > 0:
 | 
					#if tweet.photos.len > 0:
 | 
				
			||||||
| 
						 | 
					@ -19,8 +18,8 @@
 | 
				
			||||||
#end if
 | 
					#end if
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc renderRssTweet(tweet: Tweet; prefs: Prefs): string =
 | 
					#proc renderRssTweet(tweet: Tweet; prefs: Prefs; hostname: string): string =
 | 
				
			||||||
#let text = replaceUrl(tweet.text, prefs, rss=true)
 | 
					#let text = replaceUrl(tweet.text, prefs, absolute=hostname)
 | 
				
			||||||
#if tweet.quote.isSome and get(tweet.quote).available:
 | 
					#if tweet.quote.isSome and get(tweet.quote).available:
 | 
				
			||||||
#let quoteLink = hostname & getLink(get(tweet.quote))
 | 
					#let quoteLink = hostname & getLink(get(tweet.quote))
 | 
				
			||||||
<p>${text}<br><a href="https://${quoteLink}">${quoteLink}</a></p>
 | 
					<p>${text}<br><a href="https://${quoteLink}">${quoteLink}</a></p>
 | 
				
			||||||
| 
						 | 
					@ -39,7 +38,7 @@
 | 
				
			||||||
#end if
 | 
					#end if
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc renderRssTweets(tweets: seq[Tweet]; prefs: Prefs): string =
 | 
					#proc renderRssTweets(tweets: seq[Tweet]; prefs: Prefs; hostname: string): string =
 | 
				
			||||||
#var links: seq[string]
 | 
					#var links: seq[string]
 | 
				
			||||||
#for tweet in tweets:
 | 
					#for tweet in tweets:
 | 
				
			||||||
#let link = getLink(tweet)
 | 
					#let link = getLink(tweet)
 | 
				
			||||||
| 
						 | 
					@ -47,9 +46,9 @@
 | 
				
			||||||
#end if
 | 
					#end if
 | 
				
			||||||
#links.add link
 | 
					#links.add link
 | 
				
			||||||
<item>
 | 
					<item>
 | 
				
			||||||
  <title>${getTitle(tweet, prefs)}</title>
 | 
					  <title>${getTitle(tweet, prefs, hostname)}</title>
 | 
				
			||||||
  <dc:creator>@${tweet.profile.username}</dc:creator>
 | 
					  <dc:creator>@${tweet.profile.username}</dc:creator>
 | 
				
			||||||
  <description><![CDATA[${renderRssTweet(tweet, prefs).strip(chars={'\n'})}]]></description>
 | 
					  <description><![CDATA[${renderRssTweet(tweet, prefs, hostname).strip(chars={'\n'})}]]></description>
 | 
				
			||||||
  <pubDate>${getRfc822Time(tweet)}</pubDate>
 | 
					  <pubDate>${getRfc822Time(tweet)}</pubDate>
 | 
				
			||||||
  <guid>https://${hostname & link}</guid>
 | 
					  <guid>https://${hostname & link}</guid>
 | 
				
			||||||
  <link>https://${hostname & link}</link>
 | 
					  <link>https://${hostname & link}</link>
 | 
				
			||||||
| 
						 | 
					@ -57,7 +56,7 @@
 | 
				
			||||||
#end for
 | 
					#end for
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc renderTimelineRss*(timeline: Timeline; profile: Profile): string =
 | 
					#proc renderTimelineRss*(timeline: Timeline; profile: Profile; hostname: string): string =
 | 
				
			||||||
#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
					#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
				
			||||||
#result = ""
 | 
					#result = ""
 | 
				
			||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
| 
						 | 
					@ -77,13 +76,13 @@
 | 
				
			||||||
      <height>128</height>
 | 
					      <height>128</height>
 | 
				
			||||||
    </image>
 | 
					    </image>
 | 
				
			||||||
    #if timeline != nil:
 | 
					    #if timeline != nil:
 | 
				
			||||||
    ${renderRssTweets(timeline.content, prefs)}
 | 
					    ${renderRssTweets(timeline.content, prefs, hostname)}
 | 
				
			||||||
    #end if
 | 
					    #end if
 | 
				
			||||||
  </channel>
 | 
					  </channel>
 | 
				
			||||||
</rss>
 | 
					</rss>
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc renderListRss*(tweets: seq[Tweet]; name, list: string): string =
 | 
					#proc renderListRss*(tweets: seq[Tweet]; name, list, hostname: string): string =
 | 
				
			||||||
#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
					#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
				
			||||||
#let link = &"https://{hostname}/{name}/lists/{list}"
 | 
					#let link = &"https://{hostname}/{name}/lists/{list}"
 | 
				
			||||||
#result = ""
 | 
					#result = ""
 | 
				
			||||||
| 
						 | 
					@ -96,12 +95,12 @@
 | 
				
			||||||
    <description>Twitter feed for: ${list} by @${name}. Generated by ${hostname}</description>
 | 
					    <description>Twitter feed for: ${list} by @${name}. Generated by ${hostname}</description>
 | 
				
			||||||
    <language>en-us</language>
 | 
					    <language>en-us</language>
 | 
				
			||||||
    <ttl>40</ttl>
 | 
					    <ttl>40</ttl>
 | 
				
			||||||
    ${renderRssTweets(tweets, prefs)}
 | 
					    ${renderRssTweets(tweets, prefs, hostname)}
 | 
				
			||||||
 </channel>
 | 
					 </channel>
 | 
				
			||||||
</rss>
 | 
					</rss>
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#proc renderSearchRss*(tweets: seq[Tweet]; name, param: string): string =
 | 
					#proc renderSearchRss*(tweets: seq[Tweet]; name, param, hostname: string): string =
 | 
				
			||||||
#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
					#let prefs = Prefs(replaceTwitter: hostname, replaceYoutube: "invidio.us")
 | 
				
			||||||
#let link = &"https://{hostname}/search"
 | 
					#let link = &"https://{hostname}/search"
 | 
				
			||||||
#result = ""
 | 
					#result = ""
 | 
				
			||||||
| 
						 | 
					@ -114,7 +113,7 @@
 | 
				
			||||||
    <description>Twitter feed for search "${name}". Generated by ${hostname}</description>
 | 
					    <description>Twitter feed for search "${name}". Generated by ${hostname}</description>
 | 
				
			||||||
    <language>en-us</language>
 | 
					    <language>en-us</language>
 | 
				
			||||||
    <ttl>40</ttl>
 | 
					    <ttl>40</ttl>
 | 
				
			||||||
    ${renderRssTweets(tweets, prefs)}
 | 
					    ${renderRssTweets(tweets, prefs, hostname)}
 | 
				
			||||||
  </channel>
 | 
					  </channel>
 | 
				
			||||||
</rss>
 | 
					</rss>
 | 
				
			||||||
#end proc
 | 
					#end proc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue