aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/geddit.js392
-rw-r--r--src/index.js17
-rw-r--r--src/routes/index.js35
-rw-r--r--src/views/comment.pug18
-rw-r--r--src/views/comments.pug25
-rw-r--r--src/views/index.pug19
-rw-r--r--src/views/post.pug21
-rw-r--r--src/views/utils.pug3
8 files changed, 530 insertions, 0 deletions
diff --git a/src/geddit.js b/src/geddit.js
new file mode 100644
index 0000000..825c3a9
--- /dev/null
+++ b/src/geddit.js
@@ -0,0 +1,392 @@
1class Geddit {
2 constructor() {
3 this.host = "https://www.reddit.com";
4 this.parameters = {
5 limit: 25,
6 include_over_18: true,
7 }
8 this.search_params = {
9 limit: 25,
10 include_over_18: true,
11 type: "sr,link,user",
12 }
13 }
14
15 async getSubmissions(sort = null, subreddit = null, options = {}) {
16 let params = {
17 limit: 25,
18 include_over_18: true,
19 }
20
21 sort = sort ? sort : "hot";
22 subreddit = subreddit ? "/r/" + subreddit : "";
23
24 return await fetch(this.host + subreddit + `/${sort}.json?` + new URLSearchParams(Object.assign(params, options)))
25 .then(res => res.json())
26 .then(json => json.data)
27 .then(data => ({
28 after: data.after,
29 posts: data.children
30 }))
31 .catch(err => null);
32
33 }
34
35 async getDomainHot(domain, options = this.parameters) {
36 return await fetch(this.host + "/domain/" + domain + "/hot.json?" + new URLSearchParams(options))
37 .then(res => res.json())
38 .then(json => json.data)
39 .then(data => ({
40 after: data.after,
41 posts: data.children
42 }))
43 .catch(err => null);
44 }
45
46 async getDomainBest(domain, options = this.parameters) {
47 return await fetch(this.host + "/domain/" + domain + "/best.json?" + new URLSearchParams(options))
48 .then(res => res.json())
49 .then(json => json.data)
50 .then(data => ({
51 after: data.after,
52 posts: data.children
53 }))
54 .catch(err => null);
55 }
56
57 async getDomainTop(domain, options = this.parameters) {
58 return await fetch(this.host + "/domain/" + domain + "/top.json?" + new URLSearchParams(options))
59 .then(res => res.json())
60 .then(json => json.data)
61 .then(data => ({
62 after: data.after,
63 posts: data.children
64 }))
65 .catch(err => null);
66 }
67
68 async getDomainNew(domain, options = this.parameters) {
69 return await fetch(this.host + "/domain/" + domain + "/new.json?" + new URLSearchParams(options))
70 .then(res => res.json())
71 .then(json => json.data)
72 .then(data => ({
73 after: data.after,
74 posts: data.children
75 }))
76 .catch(err => null);
77 }
78
79 async getDomainRising(domain, options = this.parameters) {
80 return await fetch(this.host + "/domain/" + domain + "/rising.json?" + new URLSearchParams(options))
81 .then(res => res.json())
82 .then(json => json.data)
83 .then(data => ({
84 after: data.after,
85 posts: data.children
86 }))
87 .catch(err => null);
88 }
89
90 async getDomainControversial(domain, options = this.parameters) {
91 return await fetch(this.host + "/domain/" + domain + "/controversial.json?" + new URLSearchParams(options))
92 .then(res => res.json())
93 .then(json => json.data)
94 .then(data => ({
95 after: data.after,
96 posts: data.children
97 }))
98 .catch(err => null);
99 }
100
101 async getSubreddit(subreddit) {
102 return await fetch(this.host + "/r/" + subreddit + "/about.json")
103 .then(res => res.json())
104 .then(json => json.data)
105 .catch(err => null);
106 }
107
108 async getSubredditRules(subreddit) {
109 return await fetch(this.host + "/r/" + subreddit + "/about/rules.json")
110 .then(res => res.json())
111 .then(json => json.data)
112 .catch(err => null);
113 }
114
115 async getSubredditModerators(subreddit) {
116 return await fetch(this.host + "/r/" + subreddit + "/about/moderators.json")
117 .then(res => res.json())
118 .then(json => json.data)
119 .then(data = ({
120 users: data.children
121 }))
122 .catch(err => null);
123 }
124
125 async getSubredditWikiPages(subreddit) {
126 return await fetch(this.host + "/r/" + subreddit + "/wiki/pages.json")
127 .then(res => res.json())
128 .then(json => json.data)
129 .catch(err => null);
130 }
131
132 async getSubredditWikiPage(subreddit, page) {
133 return await fetch(this.host + "/r/" + subreddit + "/wiki/" + page + ".json")
134 .then(res => res.json())
135 .then(json => json.data)
136 .catch(err => null);
137 }
138
139 async getSubredditWikiPageRevisions(subreddit, page) {
140 return await fetch(this.host + "/r/" + subreddit + "/wiki/revisions" + page + ".json")
141 .then(res => res.json())
142 .then(json => json.data.children)
143 .catch(err => null);
144 }
145
146 async getPopularSubreddits(options = this.parameters) {
147 return await fetch(this.host + "/subreddits/popular.json?" + new URLSearchParams(options))
148 .then(res => res.json())
149 .then(json => json.data)
150 .then(data => ({
151 after: data.after,
152 subreddits: data.children
153 }))
154 .catch(err => null);
155 }
156
157 async getNewSubreddits(options = this.parameters) {
158 return await fetch(this.host + "/subreddits/new.json?" + new URLSearchParams(options))
159 .then(res => res.json())
160 .then(json => json.data)
161 .then(data => ({
162 after: data.after,
163 subreddits: data.children
164 }))
165 .catch(err => null);
166 }
167
168 async getPremiumSubreddits(options = this.parameters) {
169 return await fetch(this.host + "/subreddits/premium.json?" + new URLSearchParams(options))
170 .then(res => res.json())
171 .then(json => json.data)
172 .then(data => ({
173 after: data.after,
174 subreddits: data.children
175 }))
176 .catch(err => null);
177 }
178
179 async getDefaultSubreddits(options = this.parameters) {
180 return await fetch(this.host + "/subreddits/default.json?" + new URLSearchParams(options))
181 .then(res => res.json())
182 .then(json => json.data)
183 .then(data => ({
184 after: data.after,
185 subreddits: data.children
186 }))
187 .catch(err => null);
188 }
189
190 async getPopularUsers(options = this.parameters) {
191 return await fetch(this.host + "/users/popular.json?" + new URLSearchParams(options))
192 .then(res => res.json())
193 .then(json => json.data)
194 .then(data => ({
195 after: data.after,
196 users: data.children
197 }))
198 .catch(err => null);
199 }
200
201 async getNewUsers(options = this.parameters) {
202 return await fetch(this.host + "/users/new.json?" + new URLSearchParams(options))
203 .then(res => res.json())
204 .then(json => json.data)
205 .then(data => ({
206 after: data.after,
207 users: data.children
208 }))
209 .catch(err => null);
210 }
211
212 async searchSubmissions(query, options = {}) {
213 options.q = query;
214 options.type = "link";
215
216 let params = {
217 limit: 25,
218 include_over_18: true
219 }
220
221 console.log(this.host + "/search.json?" + new URLSearchParams(Object.assign(params, options)));
222
223 return await fetch(this.host + "/search.json?" + new URLSearchParams(Object.assign(params, options)))
224 .then(res => res.json())
225 .then(json => json.data)
226 .then(data => ({
227 after: data.after,
228 items: data.children
229 }))
230 .catch(err => null);
231 }
232
233 async searchSubreddits(query, options = {}) {
234 options.q = query;
235
236 let params = {
237 limit: 25,
238 include_over_18: true
239 }
240
241 return await fetch(this.host + "/subreddits/search.json?" + new URLSearchParams(Object.assign(params, options)))
242 .then(res => res.json())
243 .then(json => json.data)
244 .then(data => ({
245 after: data.after,
246 items: data.children
247 }))
248 .catch(err => null);
249 }
250
251 async searchUsers(query, options = {}) {
252 options.q = query;
253
254 let params = {
255 limit: 25,
256 include_over_18: true
257 }
258
259 return await fetch(this.host + "/users/search.json?" + new URLSearchParams(Object.assign(params, options)))
260 .then(res => res.json())
261 .then(json => json.data)
262 .then(data => ({
263 after: data.after,
264 items: data.children
265 }))
266 .catch(err => null);
267 }
268
269 async searchAll(query, subreddit = null, options = {}) {
270 options.q = query;
271 subreddit = subreddit ? "/r/" + subreddit : "";
272
273 let params = {
274 limit: 25,
275 include_over_18: true,
276 type: "sr,link,user",
277 }
278
279 return await fetch(this.host + subreddit + "/search.json?" + new URLSearchParams(Object.assign(params, options)))
280 .then(res => res.json())
281 .then(json => Array.isArray(json) ? ({
282 after: json[1].data.after,
283 items: json[0].data.children.concat(json[1].data.children)
284 }) : ({
285 after: json.data.after,
286 items: json.data.children
287 }))
288 .catch(err => null);
289 }
290
291 async getSubmission(id) {
292 return await fetch(this.host + "/by_id/" + id + ".json")
293 .then(res => res.json())
294 .then(json => json.data.children[0].data)
295 .catch(err => null);
296 }
297
298 async getSubmissionComments(id, options = this.parameters) {
299 return await fetch(this.host + "/comments/" + id + ".json?" + new URLSearchParams(options))
300 .then(res => res.json())
301 .then(json => ({
302 submission: json[0].data.children[0],
303 comments: json[1].data.children
304 }))
305 .catch(err => null);
306 }
307
308 async getSubredditComments(subreddit, options = this.parameters) {
309 return await fetch(this.host + "/r/" + subreddit + "/comments.json?" + new URLSearchParams(options))
310 .then(res => res.json())
311 .then(json => json.data.children)
312 .catch(err => null);
313 }
314
315 async getUser(username) {
316 return await fetch(this.host + "/user/" + username + "/about.json")
317 .then(res => res.json())
318 .then(json => json.data)
319 .catch(err => null);
320 }
321
322 async getUserOverview(username, options = this.parameters) {
323 return await fetch(this.host + "/user/" + username + "/overview.json?" + new URLSearchParams(options))
324 .then(res => res.json())
325 .then(json => json.data)
326 .then(data => ({
327 after: data.after,
328 items: data.children
329 }))
330 .catch(err => null);
331 }
332
333 async getUserComments(username, options = this.parameters) {
334 return await fetch(this.host + "/user/" + username + "/comments.json?" + new URLSearchParams(options))
335 .then(res => res.json())
336 .then(json => json.data)
337 .then(data => ({
338 after: data.after,
339 items: data.children
340 }))
341 .catch(err => null);
342 }
343
344 async getUserSubmissions(username, options = this.parameters) {
345 return await fetch(this.host + "/user/" + username + "/submitted.json?" + new URLSearchParams(options))
346 .then(res => res.json())
347 .then(json => json.data)
348 .then(data => ({
349 after: data.after,
350 items: data.children
351 }))
352 .catch(err => null);
353 }
354
355 async getLiveThread(id) {
356 return await fetch(this.host + "/live/" + id + "/about.json")
357 .then(res => res.json())
358 .then(json => json.data)
359 .catch(err => null);
360 }
361
362 async getLiveThreadUpdates(id, options = this.parameters) {
363 return await fetch(this.host + "/live/" + id + ".json?" + new URLSearchParams(options))
364 .then(res => res.json())
365 .then(json => json.data.children)
366 .catch(err => null);
367 }
368
369
370 async getLiveThreadContributors(id, options = this.parameters) {
371 return await fetch(this.host + "/live/" + id + "/contributors.json?" + new URLSearchParams(options))
372 .then(res => res.json())
373 .then(json => json.data.children)
374 .catch(err => null);
375 }
376
377 async getLiveThreadDiscussions(id, options = this.parameters) {
378 return await fetch(this.host + "/live/" + id + "/discussions.json?" + new URLSearchParams(options))
379 .then(res => res.json())
380 .then(json => json.data.children)
381 .catch(err => null);
382 }
383
384 async getLiveThreadsNow(options = this.parameters) {
385 return await fetch(this.host + "/live/happening_now.json?" + new URLSearchParams(options))
386 .then(res => res.json())
387 .then(json => json.data.children)
388 .catch(err => null);
389 }
390}
391
392export { Geddit }
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..bfe31f4
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,17 @@
1const express = require('express');
2const path = require('path');
3const routes = require('./routes/index');
4const geddit = require('./geddit.js');
5
6const app = express();
7
8app.set('views', path.join(__dirname, 'views'));
9app.set('view engine', 'pug');
10
11app.use(express.static('public'));
12app.use('/', routes);
13
14const server = app.listen(3000, () => {
15 console.log(`started on ${server.address().port}`);
16});
17
diff --git a/src/routes/index.js b/src/routes/index.js
new file mode 100644
index 0000000..6cf5403
--- /dev/null
+++ b/src/routes/index.js
@@ -0,0 +1,35 @@
1const express = require('express');
2const router = express.Router();
3const geddit = require('../geddit.js');
4const G = new geddit.Geddit();
5const fs = require('fs/promises');
6
7
8// GET /
9router.get('/', async (req, res) => {
10 res.redirect("/r/all")
11});
12
13// GET /r/:id
14router.get('/r/:subreddit', async (req, res) => {
15 var subreddit = req.params.subreddit;
16
17 var postsReq = G.getSubmissions(`r/${subreddit}`);
18 var aboutReq = G.getSubreddit(`${subreddit}`);
19
20 var [posts, about] = await Promise.all([postsReq, aboutReq]);
21 res.render('index', { subreddit, posts, about });
22});
23
24// GET /comments/:id
25router.get('/comments/:id', async (req, res) => {
26 var id = req.params.id;
27
28 response = await G.getSubmissionComments(id);
29 var post = response.submission.data;
30 var comments = response.comments;
31
32 res.render('comments', { post, comments });
33});
34
35module.exports = router;
diff --git a/src/views/comment.pug b/src/views/comment.pug
new file mode 100644
index 0000000..24e1a9b
--- /dev/null
+++ b/src/views/comment.pug
@@ -0,0 +1,18 @@
1include utils
2mixin comment(com, isfirst)
3 - var data = com.data
4 - var kind = com.kind
5 if kind == "more"
6 div.more #{data.count} more comments
7 else
8 div(class=`comment ${isfirst?'first':''}`)
9 div.comment-body !{data.body}
10 div.info-container
11 div.info-item by u/#{data.author}
12 div.info-item ↑ #{fmtnum(data.ups)}
13 div.replies
14 if data.replies
15 if data.replies.data
16 if data.replies.data.children
17 each reply in data.replies.data.children
18 +comment(reply,false)
diff --git a/src/views/comments.pug b/src/views/comments.pug
new file mode 100644
index 0000000..f7964a3
--- /dev/null
+++ b/src/views/comments.pug
@@ -0,0 +1,25 @@
1doctype html
2html
3 head
4 meta(charset='UTF-8')
5 title reddit
6 link(rel='stylesheet', href='/styles.css')
7 body
8 main#content
9 div.header
10 a(href=`/r/${post.subreddit}`)
11 h4 ← r/#{post.subreddit}
12 h2 #{post.title}
13 if post.post_hint == 'image'
14 img(src=post.url).post-media
15 else if post.post_hint == 'hosted:video'
16 video(src=post.url).post-media
17 p.self-text !{post.selftext}
18 hr
19
20 div.comments-container
21 each child in comments
22 include comment
23 +comment(child, true)
24
25 script(src='https://unpkg.com/[email protected]')
diff --git a/src/views/index.pug b/src/views/index.pug
new file mode 100644
index 0000000..d017570
--- /dev/null
+++ b/src/views/index.pug
@@ -0,0 +1,19 @@
1doctype html
2html
3 head
4 meta(charset='UTF-8')
5 title reddit
6 link(rel='stylesheet', href='/styles.css')
7 body
8 main#content
9 div.header
10 a(href=`/r/#{subreddit}`)
11 h1 r/#{subreddit}
12 if about
13 p #{about.public_description}
14
15 each child in posts.posts
16 include post
17 +post(child.data)
18
19 script(src='https://unpkg.com/[email protected]')
diff --git a/src/views/post.pug b/src/views/post.pug
new file mode 100644
index 0000000..77ef3f5
--- /dev/null
+++ b/src/views/post.pug
@@ -0,0 +1,21 @@
1include utils
2mixin post(p)
3 article.post
4 div.post-container
5 div.post-text
6 div.title-container !{p.title}
7 div.info-container
8 div.info-item by u/#{p.author}
9 div.info-item ↑ #{fmtnum(p.ups)}
10 div.info-item #{p.domain}
11 div.info-item
12 a(href=`/r/${p.subreddit}`) r/#{p.subreddit}
13 div.info-item
14 a(href=`/comments/${p.id}`) #{fmtnum (p.num_comments)} #{fmttxt(p.num_comments, 'comment')}
15 div.media-preview
16 if p.post_hint == "image" || p.post_hint == "link"
17 if p.thumbnail && p.thumbnail != "self" || p.thumbnail != "default"
18 a(href=p.url)
19 img(src=p.thumbnail width='100px')
20 else if p.post_hint == "hosted:video"
21 video(src=p.secure_media.reddit_video.scrubber_media_url width='100px')
diff --git a/src/views/utils.pug b/src/views/utils.pug
new file mode 100644
index 0000000..f3f61bb
--- /dev/null
+++ b/src/views/utils.pug
@@ -0,0 +1,3 @@
1- var fmtnum = (n)=>n>=1000?(n/1000).toFixed(1)+'k':n;
2- var fmttxt = (n,t)=>`${t}${n==1?'':'s'}`
3