routes.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. from bottle import request, response, abort, static_file
  2. from kddit import app
  3. from urllib.parse import urlparse
  4. from kddit import settings
  5. from kddit.utils import req, success, ydl, req_url
  6. from kddit import html
  7. from kddit.utils import verify_subreddit_option, verify_user_option
  8. from kddit.utils import get_subreddit_url, get_subreddit
  9. from kddit.utils import nsfw_mode, get_query
  10. def subreddit_content(data, subreddit, option, time, safe):
  11. content = (html.subreddit_menu(option, subreddit))
  12. if option in settings.EXPANDED_OPTIONS:
  13. content += (html.subreddit_sort_menu(subreddit, option or settings.DEFAULT_OPTION, time))
  14. content += (html.mixed_content(data, safe) or html.nothing,)
  15. content += html.subreddit_nav(data, subreddit, option, time)
  16. return content
  17. def search_content(data, subreddit, sort, time, query):
  18. content = html.search_sort_menu(subreddit, query)
  19. content += html.search_time_menu(subreddit, query )
  20. content += html.mixed_content(data, True) or html.nothing
  21. content += html.search_nav(data, subreddit, query)
  22. return content
  23. def domain_content(data, domain, option, time):
  24. content = html.domain_menu(option, domain)
  25. if option in settings.EXPANDED_OPTIONS:
  26. content += html.domain_sort_menu(domain, option or settings.DEFAULT_OPTION, time)
  27. content += html.mixed_content(data, True) or html.nothing
  28. content += html.domain_nav(data, domain, option, time)
  29. return content
  30. def user_content(data, user, option, sort):
  31. content = html.user_menu(option, user)
  32. content += html.user_sort_menu(option, sort, user)
  33. content += (html.mixed_content(data, True, True),)
  34. content += html.user_nav(data, user, option, sort)
  35. return content
  36. def multi_content(data, user, multi, option, sort):
  37. content = html.multi_menu(option, user, multi)
  38. content += html.multi_sort_menu(user, multi, option, sort)
  39. content += (html.mixed_content(data, True),)
  40. content += html.multi_nav(data, user, multi, option, sort)
  41. return content
  42. @app.route("/search", "GET")
  43. @app.route("/r/<subreddit>/search", "GET")
  44. def search_page(subreddit=None):
  45. url = f'{get_subreddit_url()}/search/.json'
  46. query = dict(request.query)
  47. r = req(url, query)
  48. if success(r):
  49. data = r.json()
  50. time = query.get("t")
  51. sort = query.get("sort")
  52. q = query.get("q") or ""
  53. title = f"search results - {q}"
  54. header = html.page_header(subreddit=subreddit)
  55. content = search_content(data, subreddit, sort, time, query)
  56. return html.page(title, header, content).render()
  57. else:
  58. return abort(r.status_code)
  59. @app.route("/u/<user>/m/<multi>", "GET")
  60. @app.route("/user/<user>/m/<multi>", "GET")
  61. @app.route("/u/<user>/m/<multi>/<option>", "GET")
  62. @app.route("/user/<user>/m/<multi>/<option>", "GET")
  63. def multi_page(user, multi=None ,option=None):
  64. verify_subreddit_option()
  65. url = f"/user/{user}/m/{multi}/{option or settings.DEFAULT_OPTION}/.json"
  66. query = dict(request.query)
  67. r = req(url, query)
  68. if success(r):
  69. data = r.json()
  70. sort = query.get("t")
  71. title = f"m/{multi} by u/{user}"
  72. header = html.page_header(user=user, multi=multi)
  73. content = multi_content(data, user, multi, option, sort)
  74. return html.page(title, header, content).render()
  75. else:
  76. return abort(r.status_code)
  77. @app.route("/u/<user>", "GET")
  78. @app.route("/user/<user>", "GET")
  79. @app.route("/u/<user>/<option>", "GET")
  80. @app.route("/user/<user>/<option>", "GET")
  81. def user_page(user, option="overview"):
  82. verify_user_option()
  83. url = f"/user/{user}/{option}/.json"
  84. query = dict(request.query)
  85. r = req(url, query)
  86. if success(r):
  87. data = r.json()
  88. sort = query.get("sort")
  89. title = f"{option} by u/{user}"
  90. header = html.page_header(user=user)
  91. content = user_content(data, user, option, sort)
  92. return html.page(title, header, content).render()
  93. else:
  94. return abort(r.status_code)
  95. @app.route("/u/<user>/comments/<post_id>/<path>", "GET")
  96. @app.route("/user/<user>/comments/<post_id>/<path>", "GET")
  97. @app.route("/u/<user>/comments/<post_id>/comment/<comment_id>", "GET")
  98. @app.route("/user/<user>/comments/<post_id>/comment/<comment_id>", "GET")
  99. def user_comment_page(user, post_id, path=None, comment_id=None):
  100. if path:
  101. url = f"/user/{user}/comments/{post_id}/{path}/.json"
  102. else:
  103. url = f"/user/{user}/comments/{post_id}/comment/{comment_id}/.json"
  104. query = dict(request.query)
  105. r = req(url, query)
  106. if success(r):
  107. data = r.json()
  108. header = html.page_header(user=user)
  109. safe = data[0]["data"]["children"][0]["data"]["over_18"]
  110. sort = query.get("sort") or settings.DEFAULT_OPTION
  111. content = html.mixed_content(data[0], safe)
  112. if path:
  113. content += html.user_comments_sort_menu(path, sort)
  114. title = f"{data[0]['data']['children'][0]['data']['title']} by u/{user}"
  115. comments = data[1]["data"]["children"]
  116. content += html.comments(comments, True)
  117. return html.page(title, header, content).render()
  118. else:
  119. return abort(r.status_code)
  120. @app.route("/", "GET")
  121. @app.route("/<option>", "GET")
  122. @app.route("/r/<subreddit>", "GET")
  123. @app.route("/r/<subreddit>/<option>", "GET")
  124. def subreddit_page(subreddit=None, option=None):
  125. verify_subreddit_option()
  126. url = f'{get_subreddit_url()}/{option or settings.DEFAULT_OPTION}.json'
  127. query = dict(request.query)
  128. r = req(url, query)
  129. if success(r):
  130. data = r.json()
  131. time = query.get("t")
  132. title = get_subreddit() or "kddit"
  133. header = html.page_header(subreddit=subreddit)
  134. safe = nsfw_mode(subreddit)
  135. content = subreddit_content(data, subreddit, option, time, safe)
  136. return html.page(title, header, content).render()
  137. return abort(r.status_code)
  138. @app.route("/domain/<domain>", "GET")
  139. @app.route("/domain/<domain>/<option>", "GET")
  140. def domain_page(domain, option=None):
  141. verify_subreddit_option()
  142. query = get_query()
  143. time = query.get("t")
  144. url = f'/domain/{domain}/{option or settings.DEFAULT_OPTION}.json'
  145. r = req(url, query)
  146. if success(r):
  147. data = r.json()
  148. title = domain
  149. header = html.page_header(domain=domain)
  150. content = domain_content(data, domain, option, time)
  151. return html.page(title, header, content).render()
  152. else:
  153. return abort(r.status_code)
  154. @app.route("/r/<subreddit>/comments/<post_id>/<path>", "GET")
  155. @app.route("/r/<subreddit>/comments/<post_id>/<path>/<comment_id>", "GET")
  156. def post_page(subreddit, post_id, path, comment_id=""):
  157. u = f"/r/{subreddit}/comments/{post_id}/{path}/{comment_id}.json"
  158. query = get_query()
  159. r = req(u, query)
  160. if success(r):
  161. data = r.json()
  162. post = data[0]["data"]["children"][0]["data"]
  163. comments = data[1]["data"]["children"]
  164. title = post["title"]
  165. content = (html.post(post), html.comments(comments))
  166. header = html.page_header(subreddit=subreddit)
  167. return html.page(title, header, content).render()
  168. else:
  169. return abort(r.status_code)
  170. @app.route("/static/<file>")
  171. def static(file):
  172. return static_file(file, root=f"{settings.ROOT}/static")
  173. @app.route("/video/<url:path>")
  174. def video_proxy(url):
  175. uri = urlparse(url)
  176. if uri.netloc in settings.PROXY_ALLOW["video"]:
  177. with ydl:
  178. result = ydl.extract_info(url, download=True)
  179. return static_file(
  180. f'{result["id"]}.mp4',
  181. root=settings.FILE_PATH)
  182. else:
  183. return abort(403)
  184. @app.route("/proxy/<url:path>")
  185. def proxy(url):
  186. uri = urlparse(url)
  187. netloc = uri.netloc
  188. query = get_query()
  189. if netloc not in settings.PROXY_ALLOW["image"]:
  190. return abort(403)
  191. r = req_url(url, query)
  192. if success(r):
  193. response.set_header("content-type", r.headers["content-type"])
  194. return r.content
  195. else:
  196. return abort(r.status_code)
  197. @app.error(401)
  198. @app.error(403)
  199. @app.error(404)
  200. @app.error(405)
  201. @app.error(406)
  202. @app.error(429)
  203. @app.error(451)
  204. @app.error(500)
  205. @app.error(503)
  206. def error_redirect(error):
  207. return html.error_page(error).render()