app.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # Copyright (C) 2023 MikuInvidious Team
  2. #
  3. # MikuInvidious is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License as
  5. # published by the Free Software Foundation; either version 3 of
  6. # the License, or (at your option) any later version.
  7. #
  8. # MikuInvidious is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. # General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with MikuInvidious. If not, see <http://www.gnu.org/licenses/>.
  15. import requests
  16. from urllib.parse import urlparse
  17. import asyncio
  18. from flask import request, make_response, redirect, url_for, send_from_directory
  19. import subprocess
  20. from bs4 import BeautifulSoup
  21. from shared import *
  22. from views import *
  23. from res import *
  24. from filters import *
  25. from extra import video_get_src_for_qn, video_get_dash_for_qn, bv2av, av2bv
  26. import traceback
  27. from bilibili_api import exceptions
  28. ##########################################
  29. # APIs
  30. ##########################################
  31. @app.route('/toggle_theme')
  32. def toggle_theme_api():
  33. resp = make_response()
  34. if dark_theme := request.cookies.get('dark-theme'):
  35. dark_theme = not int(dark_theme)
  36. else:
  37. dark_theme = False
  38. resp.set_cookie('dark-theme', '1' if dark_theme else '0')
  39. return resp
  40. ##########################################
  41. # Additional features
  42. ##########################################
  43. @app.route('/<b32tvid>')
  44. async def b32tv_redirect(b32tvid):
  45. req = requests.get(f'https://b23.tv/{b32tvid}', allow_redirects=False)
  46. if req.status_code != 302:
  47. e = req.json()
  48. return await render_template_with_theme('error.html',
  49. status = e['message'],
  50. desc = e['message'],
  51. suggest='请检查您的请求并重试。'), -e['code']
  52. url = urlparse(req.headers['Location'])
  53. if url.path.startswith('/read/mobile'):
  54. return redirect(url_for('read_view', cid = f'cv{url.path[13:]}'))
  55. elif url.path.startswith('/video/'):
  56. return redirect(url_for('video_view', vid = req.headers['Location'].split('/')[-1][:12]))
  57. @app.route('/download', methods=['POST'])
  58. def dl_redirect():
  59. bvid = request.form.get('id')
  60. cvid = request.form.get('cvid')
  61. qual = request.form.get('qual')
  62. return redirect(f'/proxy/video/{bvid}_{cvid}_{qual}', code=302)
  63. ##########################################
  64. # Misc
  65. ##########################################
  66. @app.route('/preferences')
  67. async def pref_view():
  68. return await render_template_with_theme('pref.html')
  69. @app.route('/test')
  70. async def test_view():
  71. theme = detect_theme()
  72. resp = make_response(theme)
  73. resp.set_cookie('theme', 'default')
  74. return resp
  75. @app.route('/robots.txt')
  76. def robots_txt():
  77. policy = appconf['site'].get('robots_policy') or 'strict'
  78. if policy == 'PLEASE_INDEX_EVERYTHING':
  79. return '', 404
  80. return send_from_directory(f'static/rules', f'robots_{policy}.txt')
  81. ##########################################
  82. # Error handling
  83. ##########################################
  84. @app.errorhandler(exceptions.ArgsException)
  85. async def args_exception_view(e):
  86. return await render_template_with_theme('error.html',
  87. status = '请求错误',
  88. desc = e), 400
  89. @app.errorhandler(exceptions.ResponseCodeException)
  90. async def resp_exception_view(e):
  91. suggest = None
  92. if e.code == -404:
  93. suggest = '这很可能说明您访问的视频/文章不存在,请检查您的请求。' \
  94. '如果您认为这是站点的问题,请联系网站管理员。'
  95. return await render_template_with_theme('error.html',
  96. status = e.msg,
  97. desc = (e.raw if appconf['site']['site_show_unsafe_error_response'] else f'后端服务器发送了无效的回复。'), suggest=suggest), -e.code
  98. @app.errorhandler(Exception)
  99. async def general_exception_view(e):
  100. error_msg = f'{type(e).__name__}: {e}'
  101. print(error_msg)
  102. return await render_template_with_theme('error.html', status='服务器错误', desc=error_msg), 500