selfhostable, read-only reddit client

Compare changes

Choose any two refs to compare.

Changed files
+67 -29
src
+62 -14
src/geddit.js
··· 10 10 include_over_18: true, 11 11 type: "sr,link,user", 12 12 }; 13 + this.headers = { 14 + "User-Agent": 15 + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", 16 + }; 13 17 } 14 18 15 19 async getSubmissions(sort = "hot", subreddit = null, options = {}) { ··· 24 28 `${ 25 29 this.host + subredditStr 26 30 }/${sort}.json?${new URLSearchParams(Object.assign(params, options))}`, 31 + { headers: this.headers }, 27 32 ) 28 33 .then((res) => res.json()) 29 34 .then((json) => json.data) ··· 37 42 async getDomainHot(domain, options = this.parameters) { 38 43 return await fetch( 39 44 `${this.host}/domain/${domain}/hot.json?${new URLSearchParams(options)}`, 45 + { headers: this.headers }, 40 46 ) 41 47 .then((res) => res.json()) 42 48 .then((json) => json.data) ··· 50 56 async getDomainBest(domain, options = this.parameters) { 51 57 return await fetch( 52 58 `${this.host}/domain/${domain}/best.json?${new URLSearchParams(options)}`, 59 + { headers: this.headers }, 53 60 ) 54 61 .then((res) => res.json()) 55 62 .then((json) => json.data) ··· 63 70 async getDomainTop(domain, options = this.parameters) { 64 71 return await fetch( 65 72 `${this.host}/domain/${domain}/top.json?${new URLSearchParams(options)}`, 73 + { headers: this.headers }, 66 74 ) 67 75 .then((res) => res.json()) 68 76 .then((json) => json.data) ··· 76 84 async getDomainNew(domain, options = this.parameters) { 77 85 return await fetch( 78 86 `${this.host}/domain/${domain}/new.json?${new URLSearchParams(options)}`, 87 + { headers: this.headers }, 79 88 ) 80 89 .then((res) => res.json()) 81 90 .then((json) => json.data) ··· 89 98 async getDomainRising(domain, options = this.parameters) { 90 99 return await fetch( 91 100 `${this.host}/domain/${domain}/rising.json?${new URLSearchParams(options)}`, 101 + { headers: this.headers }, 92 102 ) 93 103 .then((res) => res.json()) 94 104 .then((json) => json.data) ··· 102 112 async getDomainControversial(domain, options = this.parameters) { 103 113 return await fetch( 104 114 `${this.host}/domain/${domain}/controversial.json?${new URLSearchParams(options)}`, 115 + { headers: this.headers }, 105 116 ) 106 117 .then((res) => res.json()) 107 118 .then((json) => json.data) ··· 113 124 } 114 125 115 126 async getSubreddit(subreddit) { 116 - return await fetch(`${this.host}/r/${subreddit}/about.json`) 127 + return await fetch(`${this.host}/r/${subreddit}/about.json`, { 128 + headers: this.headers, 129 + }) 117 130 .then((res) => res.json()) 118 131 .then((json) => json.data) 119 132 .catch((err) => null); 120 133 } 121 134 122 135 async getSubredditRules(subreddit) { 123 - return await fetch(`${this.host}/r/${subreddit}/about/rules.json`) 136 + return await fetch(`${this.host}/r/${subreddit}/about/rules.json`, { 137 + headers: this.headers, 138 + }) 124 139 .then((res) => res.json()) 125 140 .then((json) => json.data) 126 141 .catch((err) => null); 127 142 } 128 143 129 144 async getSubredditModerators(subreddit) { 130 - return await fetch(`${this.host}/r/${subreddit}/about/moderators.json`) 145 + return await fetch(`${this.host}/r/${subreddit}/about/moderators.json`, { 146 + headers: this.headers, 147 + }) 131 148 .then((res) => res.json()) 132 149 .then((json) => json.data) 133 - .then({ 134 - data: { 135 - users: data.children, 136 - }, 137 - }) 150 + .then((data) => ({ 151 + users: data.children, 152 + })) 138 153 .catch((err) => null); 139 154 } 140 155 141 156 async getSubredditWikiPages(subreddit) { 142 - return await fetch(`${this.host}/r/${subreddit}/wiki/pages.json`) 157 + return await fetch(`${this.host}/r/${subreddit}/wiki/pages.json`, { 158 + headers: this.headers, 159 + }) 143 160 .then((res) => res.json()) 144 161 .then((json) => json.data) 145 162 .catch((err) => null); 146 163 } 147 164 148 165 async getSubredditWikiPage(subreddit, page) { 149 - return await fetch(`${this.host}/r/${subreddit}/wiki/${page}.json`) 166 + return await fetch(`${this.host}/r/${subreddit}/wiki/${page}.json`, { 167 + headers: this.headers, 168 + }) 150 169 .then((res) => res.json()) 151 170 .then((json) => json.data) 152 171 .catch((err) => null); 153 172 } 154 173 155 174 async getSubredditWikiPageRevisions(subreddit, page) { 156 - return await fetch(`${this.host}/r/${subreddit}/wiki/revisions${page}.json`) 175 + return await fetch( 176 + `${this.host}/r/${subreddit}/wiki/revisions${page}.json`, 177 + { headers: this.headers }, 178 + ) 157 179 .then((res) => res.json()) 158 180 .then((json) => json.data.children) 159 181 .catch((err) => null); ··· 162 184 async getPopularSubreddits(options = this.parameters) { 163 185 return await fetch( 164 186 `${this.host}/subreddits/popular.json?${new URLSearchParams(options)}`, 187 + { headers: this.headers }, 165 188 ) 166 189 .then((res) => res.json()) 167 190 .then((json) => json.data) ··· 175 198 async getNewSubreddits(options = this.parameters) { 176 199 return await fetch( 177 200 `${this.host}/subreddits/new.json?${new URLSearchParams(options)}`, 201 + { headers: this.headers }, 178 202 ) 179 203 .then((res) => res.json()) 180 204 .then((json) => json.data) ··· 188 212 async getPremiumSubreddits(options = this.parameters) { 189 213 return await fetch( 190 214 `${this.host}/subreddits/premium.json?${new URLSearchParams(options)}`, 215 + { headers: this.headers }, 191 216 ) 192 217 .then((res) => res.json()) 193 218 .then((json) => json.data) ··· 201 226 async getDefaultSubreddits(options = this.parameters) { 202 227 return await fetch( 203 228 `${this.host}/subreddits/default.json?${new URLSearchParams(options)}`, 229 + { headers: this.headers }, 204 230 ) 205 231 .then((res) => res.json()) 206 232 .then((json) => json.data) ··· 214 240 async getPopularUsers(options = this.parameters) { 215 241 return await fetch( 216 242 `${this.host}/users/popular.json?${new URLSearchParams(options)}`, 243 + { headers: this.headers }, 217 244 ) 218 245 .then((res) => res.json()) 219 246 .then((json) => json.data) ··· 227 254 async getNewUsers(options = this.parameters) { 228 255 return await fetch( 229 256 `${this.host}/users/new.json?${new URLSearchParams(options)}`, 257 + { headers: this.headers }, 230 258 ) 231 259 .then((res) => res.json()) 232 260 .then((json) => json.data) ··· 243 271 244 272 return await fetch( 245 273 `${this.host}/search.json?${new URLSearchParams(options)}`, 274 + { headers: this.headers }, 246 275 ) 247 276 .then((res) => res.json()) 248 277 .then((json) => json.data) ··· 263 292 264 293 return await fetch( 265 294 `${this.host}/subreddits/search.json?${new URLSearchParams(Object.assign(params, options))}`, 295 + { headers: this.headers }, 266 296 ) 267 297 .then((res) => res.json()) 268 298 .then((json) => json.data) ··· 283 313 284 314 return await fetch( 285 315 `${this.host}/users/search.json?${new URLSearchParams(Object.assign(params, options))}`, 316 + { headers: this.headers }, 286 317 ) 287 318 .then((res) => res.json()) 288 319 .then((json) => json.data) ··· 307 338 `${ 308 339 this.host + subredditStr 309 340 }/search.json?${new URLSearchParams(Object.assign(params, options))}`, 341 + { headers: this.headers }, 310 342 ) 311 343 .then((res) => res.json()) 312 344 .then((json) => ··· 324 356 } 325 357 326 358 async getSubmission(id) { 327 - return await fetch(`${this.host}/by_id/${id}.json`) 359 + return await fetch(`${this.host}/by_id/${id}.json`, { 360 + headers: this.headers, 361 + }) 328 362 .then((res) => res.json()) 329 363 .then((json) => json.data.children[0].data) 330 364 .catch((err) => null); ··· 333 367 async getSubmissionComments(id, options = this.parameters) { 334 368 return await fetch( 335 369 `${this.host}/comments/${id}.json?${new URLSearchParams(options)}`, 370 + { headers: this.headers }, 336 371 ) 337 372 .then((res) => res.json()) 338 373 .then((json) => ({ ··· 345 380 async getSingleCommentThread(parent_id, child_id, options = this.parameters) { 346 381 return await fetch( 347 382 `${this.host}/comments/${parent_id}/comment/${child_id}.json?${new URLSearchParams(options)}`, 383 + { headers: this.headers }, 348 384 ) 349 385 .then((res) => res.json()) 350 386 .then((json) => ({ ··· 357 393 async getSubredditComments(subreddit, options = this.parameters) { 358 394 return await fetch( 359 395 `${this.host}/r/${subreddit}/comments.json?${new URLSearchParams(options)}`, 396 + { headers: this.headers }, 360 397 ) 361 398 .then((res) => res.json()) 362 399 .then((json) => json.data.children) ··· 364 401 } 365 402 366 403 async getUser(username) { 367 - return await fetch(`${this.host}/user/${username}/about.json`) 404 + return await fetch(`${this.host}/user/${username}/about.json`, { 405 + headers: this.headers, 406 + }) 368 407 .then((res) => res.json()) 369 408 .then((json) => json.data) 370 409 .catch((err) => null); ··· 373 412 async getUserOverview(username, options = this.parameters) { 374 413 return await fetch( 375 414 `${this.host}/user/${username}/overview.json?${new URLSearchParams(options)}`, 415 + { headers: this.headers }, 376 416 ) 377 417 .then((res) => res.json()) 378 418 .then((json) => json.data) ··· 386 426 async getUserComments(username, options = this.parameters) { 387 427 return await fetch( 388 428 `${this.host}/user/${username}/comments.json?${new URLSearchParams(options)}`, 429 + { headers: this.headers }, 389 430 ) 390 431 .then((res) => res.json()) 391 432 .then((json) => json.data) ··· 399 440 async getUserSubmissions(username, options = this.parameters) { 400 441 return await fetch( 401 442 `${this.host}/user/${username}/submitted.json?${new URLSearchParams(options)}`, 443 + { headers: this.headers }, 402 444 ) 403 445 .then((res) => res.json()) 404 446 .then((json) => json.data) ··· 410 452 } 411 453 412 454 async getLiveThread(id) { 413 - return await fetch(`${this.host}/live/${id}/about.json`) 455 + return await fetch(`${this.host}/live/${id}/about.json`, { 456 + headers: this.headers, 457 + }) 414 458 .then((res) => res.json()) 415 459 .then((json) => json.data) 416 460 .catch((err) => null); ··· 419 463 async getLiveThreadUpdates(id, options = this.parameters) { 420 464 return await fetch( 421 465 `${this.host}/live/${id}.json?${new URLSearchParams(options)}`, 466 + { headers: this.headers }, 422 467 ) 423 468 .then((res) => res.json()) 424 469 .then((json) => json.data.children) ··· 428 473 async getLiveThreadContributors(id, options = this.parameters) { 429 474 return await fetch( 430 475 `${this.host}/live/${id}/contributors.json?${new URLSearchParams(options)}`, 476 + { headers: this.headers }, 431 477 ) 432 478 .then((res) => res.json()) 433 479 .then((json) => json.data.children) ··· 437 483 async getLiveThreadDiscussions(id, options = this.parameters) { 438 484 return await fetch( 439 485 `${this.host}/live/${id}/discussions.json?${new URLSearchParams(options)}`, 486 + { headers: this.headers }, 440 487 ) 441 488 .then((res) => res.json()) 442 489 .then((json) => json.data.children) ··· 446 493 async getLiveThreadsNow(options = this.parameters) { 447 494 return await fetch( 448 495 `${this.host}/live/happening_now.json?${new URLSearchParams(options)}`, 496 + { headers: this.headers }, 449 497 ) 450 498 .then((res) => res.json()) 451 499 .then((json) => json.data.children)
+4 -4
src/mixins/post.pug
··· 46 46 - var url = postThumbnail(p) 47 47 img(src=url onclick=onclick) 48 48 else if isPostVideo(p) 49 - - var decodedVideos = decodePostVideoUrls(p) 50 - video(data-dashjs-player="" playsinline="" autoplay="" muted="" onclick=`toggleDetails('${p.id}')` src=decodedVideos[3] poster=decodedVideos[4] width="100px" height="100px") 49 + - var url = p.secure_media.reddit_video.scrubber_media_url 50 + video(src=url data-dashjs-player width='100px' height='100px' onclick=`toggleDetails('${p.id}')`) 51 51 else if isPostLink(p) 52 52 a(href=p.url) 53 53 | ↗ ··· 71 71 a(href=`/media/${p.url}`) 72 72 img(src=p.url loading="lazy") 73 73 else if isPostVideo(p) 74 - - var decodedVideos = decodePostVideoUrls(p) 75 - video(data-dashjs-player="" playsinline="" controls="" muted="" preload="metadata" src=decodedVideos[1] poster=decodedVideos[4]) 74 + - var url = p.secure_media.reddit_video.dash_url 75 + video(src=url controls data-dashjs-player loading="lazy").post-media 76 76 else if isPostLink(p) 77 77 a(href=p.url) 78 78 | #{p.domain} ↗
+1 -11
src/views/media.pug
··· 2 2 doctype html 3 3 html 4 4 +head("home") 5 - script(type='text/javascript'). 6 - function toggleZoom(event) { 7 - const percentX = event.offsetX / event.target.width; 8 - const percentY = event.offsetY / event.target.height; 9 - Array.from(document.getElementsByClassName('media-maximized')).forEach(element => element.classList.toggle('zoom')); 10 - const moveClientX = (event.target.width * percentX) + event.target.offsetLeft - (event.view.visualViewport.width / 2) 11 - const moveClientY = (event.target.height * percentY) + event.target.offsetTop - (event.view.visualViewport.height / 2); 12 - event.target.parentElement.scrollTo(moveClientX, moveClientY); 13 - } 14 - 15 5 body.media-maximized 16 6 div.media-maximized.container 17 7 if kind == 'img' 18 - img(src=url onclick=`toggleZoom(event)`).media-maximized 8 + img(src=url).media-maximized 19 9 else 20 10 video(src=url controls).media-maximized