-
-
Notifications
You must be signed in to change notification settings - Fork 516
/
rss.nim
167 lines (132 loc) · 4.64 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# SPDX-License-Identifier: AGPL-3.0-only
import asyncdispatch, tables, times, hashes, uri
import jester
import router_utils, timeline
import ../query
include "../views/rss.nimf"
export times, hashes
proc redisKey*(page, name, cursor: string): string =
result = page & ":" & name
if cursor.len > 0:
result &= ":" & cursor
proc timelineRss*(req: Request; cfg: Config; query: Query): Future[Rss] {.async.} =
var profile: Profile
let
name = req.params.getOrDefault("name")
after = getCursor(req)
names = getNames(name)
if names.len == 1:
profile = await fetchProfile(after, query, skipRail=true, skipPinned=true)
else:
var q = query
q.fromUser = names
profile = Profile(
tweets: await getGraphSearch(q, after),
# this is kinda dumb
user: User(
username: name,
fullname: names.join(" | "),
userpic: "https://abs.twimg.com/sticky/default_profile_images/default_profile.png"
)
)
if profile.user.suspended:
return Rss(feed: profile.user.username, cursor: "suspended")
if profile.user.fullname.len > 0:
let rss = renderTimelineRss(profile, cfg, multi=(names.len > 1))
return Rss(feed: rss, cursor: profile.tweets.bottom)
template respRss*(rss, page) =
if rss.cursor.len == 0:
let info = case page
of "User": " \"" & @"name" & "\" "
of "List": " \"" & @"id" & "\" "
else: " "
resp Http404, showError(page & info & "not found", cfg)
elif rss.cursor.len == 9 and rss.cursor == "suspended":
resp Http404, showError(getSuspended(@"name"), cfg)
let headers = {"Content-Type": "application/rss+xml; charset=utf-8",
"Min-Id": rss.cursor}
resp Http200, headers, 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 = redisKey("search", $hash(genQueryUrl(query)), cursor)
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss, "Search")
let tweets = await getGraphSearch(query, cursor)
rss.cursor = tweets.bottom
rss.feed = renderSearchRss(tweets.content, query.text, genQueryUrl(query), cfg)
await cacheRss(key, rss)
respRss(rss, "Search")
get "/@name/rss":
cond cfg.enableRss
cond '.' notin @"name"
let
name = @"name"
key = redisKey("twitter", name, getCursor())
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss, "User")
rss = await timelineRss(request, cfg, Query(fromUser: @[name]))
await cacheRss(key, rss)
respRss(rss, "User")
get "/@name/@tab/rss":
cond cfg.enableRss
cond '.' notin @"name"
cond @"tab" in ["with_replies", "media", "search"]
let
name = @"name"
tab = @"tab"
query =
case tab
of "with_replies": getReplyQuery(name)
of "media": getMediaQuery(name)
of "search": initQuery(params(request), name=name)
else: Query(fromUser: @[name])
let searchKey = if tab != "search": ""
else: ":" & $hash(genQueryUrl(query))
let key = redisKey(tab, name & searchKey, getCursor())
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss, "User")
rss = await timelineRss(request, cfg, query)
await cacheRss(key, rss)
respRss(rss, "User")
get "/@name/lists/@slug/rss":
cond cfg.enableRss
cond @"name" != "i"
let
slug = decodeUrl(@"slug")
list = await getCachedList(@"name", slug)
cursor = getCursor()
if list.id.len == 0:
resp Http404, showError("List \"" & @"slug" & "\" not found", cfg)
let url = "/i/lists/" & list.id & "/rss"
if cursor.len > 0:
redirect(url & "?cursor=" & encodeUrl(cursor, false))
else:
redirect(url)
get "/i/lists/@id/rss":
cond cfg.enableRss
let
id = @"id"
cursor = getCursor()
key = redisKey("lists", id, cursor)
var rss = await getCachedRss(key)
if rss.cursor.len > 0:
respRss(rss, "List")
let
list = await getCachedList(id=id)
timeline = await getGraphListTweets(list.id, cursor)
rss.cursor = timeline.bottom
rss.feed = renderListRss(timeline.content, list, cfg)
await cacheRss(key, rss)
respRss(rss, "List")