Compare commits
No commits in common. "48b1d9e565a24a8800d608073b67b270a54290b0" and "c1534dc0576583247eb1b5cad4bf972fbc4e3f27" have entirely different histories.
48b1d9e565
...
c1534dc057
@ -10,16 +10,17 @@ RUN nimble install -y --depsOnly
|
||||
COPY . .
|
||||
RUN nimble build -d:danger -d:lto -d:strip
|
||||
RUN nimble scss
|
||||
RUN nimble md
|
||||
|
||||
FROM debian:unstable-slim
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk --no-cache add pcre ca-certificates
|
||||
RUN useradd -d /src -u 1001 nitter
|
||||
|
||||
WORKDIR /srv
|
||||
|
||||
COPY --from=build /src/nitter ./
|
||||
COPY --from=build /src/public ./public
|
||||
COPY --from=build /srv/nitter ./
|
||||
COPY --from=build /srv/public ./public
|
||||
|
||||
USER nitter
|
||||
CMD ./nitter
|
||||
|
@ -15,6 +15,7 @@ requires "jester#baca3f"
|
||||
requires "karax#5cf360c"
|
||||
requires "sass#7dfdd03"
|
||||
requires "nimcrypto#a079df9"
|
||||
requires "markdown#158efe3"
|
||||
requires "packedjson#9e6fbb6"
|
||||
requires "supersnappy#6c94198"
|
||||
requires "redpool#8b7c1db"
|
||||
@ -28,3 +29,6 @@ requires "oauth#b8c163b"
|
||||
|
||||
task scss, "Generate css":
|
||||
exec "nimble c --hint[Processing]:off -d:danger -r tools/gencss"
|
||||
|
||||
task md, "Render md":
|
||||
exec "nimble c --hint[Processing]:off -d:danger -r tools/rendermd"
|
||||
|
5
public/js/hls.light.min.js
vendored
Normal file
5
public/js/hls.light.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/hls.min.js
vendored
2
public/js/hls.min.js
vendored
File diff suppressed because one or more lines are too long
54
public/md/about.md
Normal file
54
public/md/about.md
Normal file
@ -0,0 +1,54 @@
|
||||
# About
|
||||
|
||||
Nitter is a free and open source alternative Twitter front-end focused on
|
||||
privacy and performance. The source is available on GitHub at
|
||||
<https://github.com/zedeus/nitter>
|
||||
|
||||
* No JavaScript or ads
|
||||
* All requests go through the backend, client never talks to Twitter
|
||||
* Prevents Twitter from tracking your IP or JavaScript fingerprint
|
||||
* Uses Twitter's unofficial API (no rate limits or developer account required)
|
||||
* Lightweight (for [@nim_lang](/nim_lang), 60KB vs 784KB from twitter.com)
|
||||
* RSS feeds
|
||||
* Themes
|
||||
* Mobile support (responsive design)
|
||||
* AGPLv3 licensed, no proprietary instances permitted
|
||||
|
||||
Nitter's GitHub wiki contains
|
||||
[instances](https://github.com/zedeus/nitter/wiki/Instances) and
|
||||
[browser extensions](https://github.com/zedeus/nitter/wiki/Extensions)
|
||||
maintained by the community.
|
||||
|
||||
## Why use Nitter?
|
||||
|
||||
It's impossible to use Twitter without JavaScript enabled. For privacy-minded
|
||||
folks, preventing JavaScript analytics and IP-based tracking is important, but
|
||||
apart from using a VPN and uBlock/uMatrix, it's impossible. Despite being behind
|
||||
a VPN and using heavy-duty adblockers, you can get accurately tracked with your
|
||||
[browser's fingerprint](https://restoreprivacy.com/browser-fingerprinting/),
|
||||
[no JavaScript required](https://noscriptfingerprint.com/). This all became
|
||||
particularly important after Twitter [removed the
|
||||
ability](https://www.eff.org/deeplinks/2020/04/twitter-removes-privacy-option-and-shows-why-we-need-strong-privacy-laws)
|
||||
for users to control whether their data gets sent to advertisers.
|
||||
|
||||
Using an instance of Nitter (hosted on a VPS for example), you can browse
|
||||
Twitter without JavaScript while retaining your privacy. In addition to
|
||||
respecting your privacy, Nitter is on average around 15 times lighter than
|
||||
Twitter, and in most cases serves pages faster (eg. timelines load 2-4x faster).
|
||||
|
||||
In the future a simple account system will be added that lets you follow Twitter
|
||||
users, allowing you to have a clean chronological timeline without needing a
|
||||
Twitter account.
|
||||
|
||||
## Donating
|
||||
|
||||
Liberapay: <https://liberapay.com/zedeus> \
|
||||
Patreon: <https://patreon.com/nitter> \
|
||||
BTC: bc1qp7q4qz0fgfvftm5hwz3vy284nue6jedt44kxya \
|
||||
ETH: 0x66d84bc3fd031b62857ad18c62f1ba072b011925 \
|
||||
LTC: ltc1qhsz5nxw6jw9rdtw9qssjeq2h8hqk2f85rdgpkr \
|
||||
XMR: 42hKayRoEAw4D6G6t8mQHPJHQcXqofjFuVfavqKeNMNUZfeJLJAcNU19i1bGdDvcdN6romiSscWGWJCczFLe9RFhM3d1zpL
|
||||
|
||||
## Contact
|
||||
|
||||
Feel free to join our [Matrix channel](https://matrix.to/#/#nitter:matrix.org).
|
@ -82,8 +82,6 @@ proc proxifyVideo*(manifest: string; proxy: bool): string =
|
||||
for line in manifest.splitLines:
|
||||
let url =
|
||||
if line.startsWith("#EXT-X-MAP:URI"): line[16 .. ^2]
|
||||
elif line.startsWith("#EXT-X-MEDIA") and "URI=" in line:
|
||||
line[line.find("URI=") + 5 .. -1 + line.find("\"", start= 5 + line.find("URI="))]
|
||||
else: line
|
||||
if url.startsWith('/'):
|
||||
let path = "https://video.twimg.com" & url
|
||||
|
@ -8,11 +8,14 @@ from os import getEnv
|
||||
import jester
|
||||
|
||||
import types, config, prefs, formatters, redis_cache, http_pool, auth
|
||||
import views/[general]
|
||||
import views/[general, about]
|
||||
import routes/[
|
||||
preferences, timeline, status, media, search, rss, list, debug,
|
||||
unsupported, embed, resolver, router_utils]
|
||||
|
||||
const instancesUrl = "https://github.com/zedeus/nitter/wiki/Instances"
|
||||
const issuesUrl = "https://github.com/zedeus/nitter/issues"
|
||||
|
||||
initAccountPool(cfg)
|
||||
|
||||
if not cfg.enableDebug:
|
||||
@ -29,6 +32,7 @@ setHmacKey(cfg.hmacKey)
|
||||
setProxyEncoding(cfg.base64Media)
|
||||
setMaxHttpConns(cfg.httpMaxConns)
|
||||
setHttpProxy(cfg.proxy, cfg.proxyAuth)
|
||||
initAboutPage(cfg.staticDir)
|
||||
|
||||
waitFor initRedisPool(cfg)
|
||||
stdout.write &"Connected to Redis at {cfg.redisHost}:{cfg.redisPort}\n"
|
||||
@ -56,6 +60,15 @@ routes:
|
||||
get "/":
|
||||
resp renderMain(renderSearch(), request, cfg, themePrefs())
|
||||
|
||||
get "/about":
|
||||
resp renderMain(renderAbout(), request, cfg, themePrefs())
|
||||
|
||||
get "/explore":
|
||||
redirect("/about")
|
||||
|
||||
get "/help":
|
||||
redirect("/about")
|
||||
|
||||
get "/i/redirect":
|
||||
let url = decodeUrl(@"url")
|
||||
if url.len == 0: resp Http404
|
||||
@ -66,17 +79,18 @@ routes:
|
||||
|
||||
error InternalError:
|
||||
echo error.exc.name, ": ", error.exc.msg
|
||||
const link = a("https://git.ngn.tf/ngn/nitter", href = "https://git.ngn.tf/ngn/nitter")
|
||||
const link = a("open a GitHub issue", href = issuesUrl)
|
||||
resp Http500, showError(
|
||||
&"An error occurred, please report to {link}", cfg)
|
||||
&"An error occurred, please {link} with the URL you tried to visit.", cfg)
|
||||
|
||||
error BadClientError:
|
||||
echo error.exc.name, ": ", error.exc.msg
|
||||
resp Http500, showError("Network error occurred, please try again.", cfg)
|
||||
|
||||
error RateLimitError:
|
||||
const link = a("another instance", href = instancesUrl)
|
||||
resp Http429, showError(
|
||||
&"Instance has been rate limited.", cfg)
|
||||
&"Instance has been rate limited.<br>Use {link} or try again later.", cfg)
|
||||
|
||||
extend rss, ""
|
||||
extend status, ""
|
||||
|
@ -12,6 +12,7 @@ proc createUnsupportedRouter*(cfg: Config) =
|
||||
template feature {.dirty.} =
|
||||
resp renderMain(renderFeature(), request, cfg, themePrefs())
|
||||
|
||||
get "/about/feature": feature()
|
||||
get "/login/?@i?": feature()
|
||||
get "/@name/lists/?": feature()
|
||||
|
||||
|
26
src/views/about.nim
Normal file
26
src/views/about.nim
Normal file
@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
import os, strformat
|
||||
import karax/[karaxdsl, vdom]
|
||||
|
||||
const
|
||||
date = staticExec("git show -s --format=\"%cd\" --date=format:\"%Y.%m.%d\"")
|
||||
hash = staticExec("git show -s --format=\"%h\"")
|
||||
link = "https://github.com/zedeus/nitter/commit/" & hash
|
||||
version = &"{date}-{hash}"
|
||||
|
||||
var aboutHtml: string
|
||||
|
||||
proc initAboutPage*(dir: string) =
|
||||
try:
|
||||
aboutHtml = readFile(dir/"md/about.html")
|
||||
except IOError:
|
||||
stderr.write (dir/"md/about.html") & " not found, please run `nimble md`\n"
|
||||
aboutHtml = "<h1>About page is missing</h1><br><br>"
|
||||
|
||||
proc renderAbout*(): VNode =
|
||||
buildHtml(tdiv(class="overlay-panel")):
|
||||
verbatim aboutHtml
|
||||
h2: text "Instance info"
|
||||
p:
|
||||
text "Version "
|
||||
a(href=link): text version
|
@ -6,3 +6,9 @@ proc renderFeature*(): VNode =
|
||||
h1: text "Unsupported feature"
|
||||
p:
|
||||
text "Nitter doesn't support this feature yet, but it might in the future. "
|
||||
text "You can check for an issue and open one if needed here: "
|
||||
a(href="https://github.com/zedeus/nitter/issues"):
|
||||
text "https://github.com/zedeus/nitter/issues"
|
||||
p:
|
||||
text "To find out more about the Nitter project, see the "
|
||||
a(href="/about"): text "About page"
|
||||
|
@ -31,7 +31,9 @@ proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
|
||||
icon "search", title="Search", href="/search"
|
||||
if cfg.enableRss and rss.len > 0:
|
||||
icon "rss-feed", title="RSS Feed", href=rss
|
||||
icon "bird", title="Open in Twitter", href=canonical
|
||||
a(href="https://liberapay.com/zedeus"): verbatim lp
|
||||
icon "info", title="About", href="/about"
|
||||
icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
|
||||
|
||||
proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
||||
@ -71,7 +73,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
||||
link(rel="alternate", type="application/rss+xml", href=rss, title="RSS feed")
|
||||
|
||||
if prefs.hlsPlayback:
|
||||
script(src="/js/hls.min.js", `defer`="")
|
||||
script(src="/js/hls.light.min.js", `defer`="")
|
||||
script(src="/js/hlsPlayback.js", `defer`="")
|
||||
|
||||
if prefs.infiniteScroll:
|
||||
|
Loading…
x
Reference in New Issue
Block a user