Skip to content

Commit

Permalink
Merge from upstream repo
Browse files Browse the repository at this point in the history
Highlights of this merge:
- Temporarily revert title truncation in RSS feeds
  (see zedeus/nitter#493)
- Make tweet timestamps more consistent and indicate UTC time zone
- Add description and verified badge to video cards
- List API improvements (includes adding RSS feed support)
  • Loading branch information
acarasimon96 committed Jan 4, 2022
2 parents 59b1b63 + 9a578b3 commit 34bc872
Show file tree
Hide file tree
Showing 26 changed files with 156 additions and 132 deletions.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.*
*.png
*.md
LICENSE
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ performance reasons.

### Docker

#### NOTE: For ARM64/ARM support, please use [unixfox's image](https://quay.io/repository/unixfox/nitter?tab=tags), more info [here](https://github.com/zedeus/nitter/issues/399#issuecomment-997263495)

To run Nitter with Docker, you'll need to install and run Redis separately
before you can run the container. See below for how to also run Redis using
Docker.
Expand Down
2 changes: 1 addition & 1 deletion src/agents.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ proc windows(): string =
trident = ["", "; Trident/5.0", "; Trident/6.0", "; Trident/7.0"]
"Windows " & sample(nt) & sample(enc) & sample(arch) & sample(trident)

let macs = toSeq(6..15).mapIt($it) & @["14_4", "10_1", "9_3"]
const macs = toSeq(6..15).mapIt($it) & @["14_4", "10_1", "9_3"]

proc mac(): string =
"Macintosh; Intel Mac OS X 10_" & sample(macs) & sample(enc)
Expand Down
4 changes: 2 additions & 2 deletions src/api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ proc getGraphProfile*(username: string): Future[Profile] {.async.} =
js = await fetch(graphUser ? {"variables": $variables})
result = parseGraphProfile(js, username)

proc getGraphList*(name, list: string): Future[List] {.async.} =
proc getGraphListBySlug*(name, list: string): Future[List] {.async.} =
let
variables = %*{"screenName": name, "listSlug": list, "withHighlightedLabel": false}
js = await fetch(graphList ? {"variables": $variables})
result = parseGraphList(js)

proc getGraphListById*(id: string): Future[List] {.async.} =
proc getGraphList*(id: string): Future[List] {.async.} =
let
variables = %*{"listId": id, "withHighlightedLabel": false}
js = await fetch(graphListId ? {"variables": $variables})
Expand Down
2 changes: 1 addition & 1 deletion src/apiutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import types, tokens, consts, parserutils, http_pool

const rl = "x-rate-limit-"

var pool {.threadvar.}: HttpPool
var pool: HttpPool

proc genParams*(pars: openarray[(string, string)] = @[]; cursor="";
count="20"; ext=true): seq[(string, string)] =
Expand Down
5 changes: 1 addition & 4 deletions src/formatters.nim
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,11 @@ proc getJoinDateFull*(profile: Profile): string =
profile.joinDate.format("h:mm tt - d MMM YYYY")

proc getTime*(tweet: Tweet): string =
tweet.time.format("d/M/yyyy', 'HH:mm:ss")
tweet.time.format("MMM d', 'YYYY' · 'h:mm tt' UTC'")

proc getRfc822Time*(tweet: Tweet): string =
tweet.time.format("ddd', 'dd MMM yyyy HH:mm:ss 'GMT'")

proc getTweetTime*(tweet: Tweet): string =
tweet.time.format("h:mm tt' · 'MMM d', 'YYYY")

proc getShortTime*(tweet: Tweet): string =
let now = now()
let since = now - tweet.time
Expand Down
4 changes: 2 additions & 2 deletions src/http_pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ type
HttpPool* = ref object
conns*: seq[AsyncHttpClient]

var maxConns {.threadvar.}: int
var proxy {.threadvar.}: Proxy
var maxConns: int
var proxy: Proxy

proc setMaxHttpConns*(n: int) =
maxConns = n
Expand Down
9 changes: 6 additions & 3 deletions src/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ proc parseGraphList*(js: JsonNode): List =

result = List(
id: list{"id_str"}.getStr,
name: list{"name"}.getStr.replace(' ', '-'),
name: list{"name"}.getStr,
username: list{"user", "legacy", "screen_name"}.getStr,
userId: list{"user", "legacy", "id_str"}.getStr,
userId: list{"user", "rest_id"}.getStr,
description: list{"description"}.getStr,
members: list{"member_count"}.getInt,
banner: list{"custom_banner_media", "media_info", "url"}.getImageStr
Expand Down Expand Up @@ -128,13 +128,16 @@ proc parseVideo(js: JsonNode): Video =
views: js{"ext", "mediaStats", "r", "ok", "viewCount"}.getStr,
available: js{"ext_media_availability", "status"}.getStr == "available",
title: js{"ext_alt_text"}.getStr,
durationMs: js{"duration_millis"}.getInt
durationMs: js{"video_info", "duration_millis"}.getInt
# playbackType: mp4
)

with title, js{"additional_media_info", "title"}:
result.title = title.getStr

with description, js{"additional_media_info", "description"}:
result.description = description.getStr

for v in js{"video_info", "variants"}:
result.variants.add VideoVariant(
videoType: parseEnum[VideoType](v{"content_type"}.getStr("summary")),
Expand Down
2 changes: 1 addition & 1 deletion src/parserutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ proc getBanner*(js: JsonNode): string =
if color.len > 0:
return '#' & color

# use primary color from profile picture color histrogram
# use primary color from profile picture color histogram
with p, js{"profile_image_extensions", "mediaColor", "r", "ok", "palette"}:
if p.len > 0:
let pal = p[0]{"rgb"}
Expand Down
2 changes: 1 addition & 1 deletion src/prefs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ from parsecfg import nil

export genUpdatePrefs, genResetPrefs

var defaultPrefs* {.threadvar.}: Prefs
var defaultPrefs*: Prefs

proc updateDefaultPrefs*(cfg: parsecfg.Config) =
genDefaultPrefs()
Expand Down
23 changes: 13 additions & 10 deletions src/redis_cache.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import redis, redpool, flatty, supersnappy

import types, api

const redisNil = "\0\0"
const
redisNil = "\0\0"
baseCacheTime = 60 * 60

var
pool {.threadvar.}: RedisPool
baseCacheTime = 60 * 60
pool: RedisPool
rssCacheTime: int
listCacheTime*: int

Expand All @@ -17,7 +18,9 @@ proc toFlatty*(s: var string, x: DateTime) =
s.toFlatty(x.toTime().toUnix())

proc fromFlatty*(s: string, i: var int, x: var DateTime) =
x = fromUnix(s.fromFlatty(int64)).utc()
var unix: int64
s.fromFlatty(i, unix)
x = fromUnix(unix).utc()

proc setCacheTimes*(cfg: Config) =
rssCacheTime = cfg.rssCacheTime * 60
Expand Down Expand Up @@ -56,7 +59,7 @@ proc initRedisPool*(cfg: Config) {.async.} =

template pidKey(name: string): string = "pid:" & $(hash(name) div 1_000_000)
template profileKey(name: string): string = "p:" & name
template listKey(l: List): string = toLower("l:" & l.username & '/' & l.name)
template listKey(l: List): string = "l:" & l.id

proc get(query: string): Future[string] {.async.} =
pool.withAcquire(r):
Expand Down Expand Up @@ -129,17 +132,17 @@ proc getCachedPhotoRail*(name: string): Future[PhotoRail] {.async.} =
result = await getPhotoRail(name)
await cache(result, name)

proc getCachedList*(username=""; name=""; id=""): Future[List] {.async.} =
let list = if id.len > 0: redisNil
else: await get(toLower("l:" & username & '/' & name))
proc getCachedList*(username=""; slug=""; id=""): Future[List] {.async.} =
let list = if id.len == 0: redisNil
else: await get("l:" & id)

if list != redisNil:
result = fromFlatty(uncompress(list), List)
else:
if id.len > 0:
result = await getGraphListById(id)
result = await getGraphList(id)
else:
result = await getGraphList(username, name)
result = await getGraphListBySlug(username, slug)
await cache(result)

proc getCachedRss*(key: string): Future[Rss] {.async.} =
Expand Down
47 changes: 25 additions & 22 deletions src/routes/list.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-only
import strutils
import strutils, uri

import jester

Expand All @@ -8,41 +8,44 @@ import ".."/[types, redis_cache, api]
import ../views/[general, timeline, list]
export getListTimeline, getGraphList

template respList*(list, timeline, vnode: typed) =
if list.id.len == 0:
resp Http404, showError("List \"" & @"list" & "\" not found", cfg)
template respList*(list, timeline, title, vnode: typed) =
if list.id.len == 0 or list.name.len == 0:
resp Http404, showError("List " & @"id" & " not found", cfg)

let
html = renderList(vnode, timeline.query, list)
rss = "/$1/lists/$2/rss" % [@"name", @"list"]
rss = "/i/lists/$1/rss" % [@"id"]

resp renderMain(html, request, cfg, prefs, rss=rss, banner=list.banner)
resp renderMain(html, request, cfg, prefs, titleText=title, rss=rss, banner=list.banner)

proc createListRouter*(cfg: Config) =
router list:
get "/@name/lists/@list/?":
get "/@name/lists/@slug/?":
cond '.' notin @"name"
cond @"name" != "i"
cond @"slug" != "memberships"
let
slug = decodeUrl(@"slug")
list = await getCachedList(@"name", slug)
if list.id.len == 0:
resp Http404, showError("List \"" & @"slug" & "\" not found", cfg)
redirect("/i/lists/" & list.id)

get "/i/lists/@id/?":
cond '.' notin @"id"
let
prefs = cookiePrefs()
list = await getCachedList(@"name", @"list")
list = await getCachedList(id=(@"id"))
title = "@" & list.username & "/" & list.name
timeline = await getListTimeline(list.id, getCursor())
vnode = renderTimelineTweets(timeline, prefs, request.path)
respList(list, timeline, vnode)
respList(list, timeline, title, vnode)

get "/@name/lists/@list/members":
cond '.' notin @"name"
cond @"name" != "i"
get "/i/lists/@id/members":
cond '.' notin @"id"
let
prefs = cookiePrefs()
list = await getCachedList(@"name", @"list")
list = await getCachedList(id=(@"id"))
title = "@" & list.username & "/" & list.name
members = await getListMembers(list, getCursor())
respList(list, members, renderTimelineUsers(members, prefs, request.path))

get "/i/lists/@id/?":
cond '.' notin @"id"
let list = await getCachedList(id=(@"id"))
if list.id.len == 0:
resp Http404
await cache(list)
redirect("/" & list.username & "/lists/" & list.name)
respList(list, members, title, renderTimelineUsers(members, prefs, request.path))
2 changes: 1 addition & 1 deletion src/routes/preferences.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ proc createPrefRouter*(cfg: Config) =

post "/resetprefs":
genResetPrefs()
redirect($(parseUri("/settings") ? filterParams(request.params)))
redirect("/settings?referer=" & encodeUrl(refPath()))

post "/enablehls":
savePref("hlsPlayback", "on", request)
Expand Down
Loading

0 comments on commit 34bc872

Please sign in to comment.