-
-
Notifications
You must be signed in to change notification settings - Fork 516
/
rss.nim
139 lines (110 loc) · 3.83 KB
/
rss.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# SPDX-License-Identifier: AGPL-3.0-only
import asyncdispatch, strutils, tables, times, hashes, supersnappy
import jester
import router_utils, timeline
import ../query
include "../views/rss.nimf"
export times, hashes, supersnappy
proc timelineRss*(req: Request; cfg: Config; query: Query): Future[Rss] {.async.} =
var profile: Profile
var timeline: Timeline
let
name = req.params.getOrDefault("name")
after = getCursor(req)
names = getNames(name)
if names.len == 1:
(profile, timeline) =
await fetchSingleTimeline(after, query, skipRail=true)
else:
var q = query
q.fromUser = names
timeline = await getSearch[Tweet](q, after)
# this is kinda dumb
profile = Profile(
username: name,
fullname: names.join(" | "),
userpic: "https://abs.twimg.com/sticky/default_profile_images/default_profile.png"
)
if profile.suspended:
return Rss(feed: profile.username, cursor: "suspended")
if profile.fullname.len > 0:
let rss = compress renderTimelineRss(timeline, profile, cfg, multi=(names.len > 1))
return Rss(feed: rss, cursor: timeline.bottom)
template respRss*(rss) =
if rss.cursor.len == 0:
resp Http404, showError("User \"" & @"name" & "\" not found", cfg)
elif rss.cursor.len == 9 and rss.cursor == "suspended":
resp Http404, showError(getSuspended(rss.feed), cfg)
let headers = {"Content-Type": "application/rss+xml; charset=utf-8",
"Min-Id": rss.cursor}
resp Http200, headers, uncompress rss.feed
proc createRssRouter*(cfg: Config) =
router rss:
get "/search/rss":
cond cfg.enableRss
if @"q".len > 200:
resp Http400, showError("Search input too long.", cfg)
let query = initQuery(params(request))
if query.kind != tweets:
resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg)
let
cursor = getCursor()
key = $hash(genQueryUrl(query)) & cursor
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss)
let tweets = await getSearch[Tweet](query, cursor)
rss.cursor = tweets.bottom
rss.feed = compress renderSearchRss(tweets.content, query.text,
genQueryUrl(query), cfg)
await cacheRss(key, rss)
respRss(rss)
get "/@name/rss":
cond cfg.enableRss
cond '.' notin @"name"
let
cursor = getCursor()
name = @"name"
key = name & cursor
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss)
rss = await timelineRss(request, cfg, Query(fromUser: @[name]))
await cacheRss(key, rss)
respRss(rss)
get "/@name/@tab/rss":
cond cfg.enableRss
cond '.' notin @"name"
cond @"tab" in ["with_replies", "media", "search"]
let name = @"name"
let query =
case @"tab"
of "with_replies": getReplyQuery(name)
of "media": getMediaQuery(name)
of "search": initQuery(params(request), name=name)
else: Query(fromUser: @[name])
var key = @"name" & "/" & @"tab"
if @"tab" == "search":
key &= $hash(genQueryUrl(query))
key &= getCursor()
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss)
rss = await timelineRss(request, cfg, query)
await cacheRss(key, rss)
respRss(rss)
get "/i/lists/@id/rss":
cond cfg.enableRss
let
cursor = getCursor()
key = @"id" & cursor
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss)
let
list = await getCachedList(id=(@"id"))
timeline = await getListTimeline(list.id, cursor)
rss.cursor = timeline.bottom
rss.feed = compress renderListRss(timeline.content, list, cfg)
await cacheRss(key, rss)
respRss(rss)