Newer
Older
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# Copyright (C) 2023 MikuInvidious Team
#
# MikuInvidious is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of
# the License, or (at your option) any later version.
#
# MikuInvidious is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MikuInvidious. If not, see <http://www.gnu.org/licenses/>.
import asyncio, requests
from aioflask import render_template, request
from bilibili_api import user, video, article, comment, search, homepage, video_zone
from shared import *
from extra import video_get_src_for_qn, video_get_dash_for_qn, bv2av, av2bv, article_to_html, article_to_any
@app.route('/licenses')
async def static_licenses_view():
return await render_template_with_theme('licenses.html')
@app.route('/')
async def home_view():
return await render_template_with_theme('home.html', i=await homepage.get_videos())
@app.route('/vv/<zid>')
@app.route('/vv/<zid>/')
async def zone_id_view(zid):
pn = request.args.get('i') or 1
info = await video_zone.get_zone_new_videos(zid, pn)
return await render_template_with_theme('zone.html', info=info)
@app.route('/search')
async def search_view():
q = request.args.get('q')
i = request.args.get('i') or 1
if not q:
return await render_template_with_theme('error.html',
status='无法搜索',
desc='没有发送搜索关键字。',
sg='请设置搜索关键字后重试。'), 400
order_map = {
'rank': search.OrderVideo.TOTALRANK,
'click': search.OrderVideo.CLICK,
'pubdate': search.OrderVideo.PUBDATE,
'dm': search.OrderVideo.DM,
'stow': search.OrderVideo.STOW,
'scores': search.OrderVideo.SCORES,
'attention': search.OrderArticle.ATTENTION,
'fans': search.OrderUser.FANS,
'level': search.OrderUser.LEVEL,
}
if request.args.get('t') == 'article':
search_type = search.SearchObjectType.ARTICLE
tmpl = 'search_article.html'
elif request.args.get('t') == 'user':
search_type = search.SearchObjectType.USER
tmpl = 'search_user.html'
else:
search_type = search.SearchObjectType.VIDEO
tmpl = 'search.html'
sinfo = await search.search_by_type(q, page=i, search_type=search_type,
order_type=order_map.get(request.args.get('sort')))
return await render_template_with_theme(tmpl, q=q, sinfo=sinfo,
rs=sinfo.get('result'),
sort=request.args.get('sort'))
@app.route('/space/<mid>')
@app.route('/space/<mid>/')
async def space_view(mid):
u = user.User(mid)
uinfo, uvids = await asyncio.gather(u.get_user_info(),
u.get_videos(pn=request.args.get('i') or 1, ps=28))
return await render_template_with_theme('space.html', uinfo=uinfo, uvids=uvids)
@app.route('/author/<mid>')
@app.route('/author/<mid>/')
async def author_view(mid):
u = user.User(mid)
uinfo, uarticles = await asyncio.gather(u.get_user_info(),
u.get_articles(pn=request.args.get('i') or 1, ps=28))
return await render_template_with_theme('author.html', uinfo=uinfo, uarts=uarticles)
@app.route('/read/<cid>')
@app.route('/read/<cid>/')
@app.route('/read/mobile/<cid>')
@app.route('/read/mobile/<cid>/')
async def read_view(cid):
req = requests.get(f'https://www.bilibili.com/read/{cid}',
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0'
'Safari/537.36 Edg/111.0.1661.62'})
if req.status_code != 200:
st = '服务器错误'
sg = None
desc = '后端服务器发送了无效的回复'
if req.status_code == 404:
st = '没有找到文章'
sg = '这很可能说明您访问的文章不存在,请检查您的请求。' \
'如果您认为这是站点的问题,请联系网站管理员。'
return await render_template_with_theme('error.html',
status = st,
desc = desc,
suggest = sg), req.status_code
if appconf['render']['use_pandoc'] and \
request.args.get('format') in appconf['render']['article_allowed_formats']:
return article_to_any(req.text, request.args.get('format'))
else:
ar = article.Article(cid[2:])
try:
return await render_template_with_theme('read.html', cid=cid, arinfo = (await ar.get_all())['readInfo'], article_content=article_to_html(req.text))
except TypeError:
return await render_template_with_theme('error.html',
status='没有找到文章',
desc='文章不存在',
sg = '这很可能说明您访问的文章不存在,请检查您的请求。'), 404
@app.route('/video_listen/<vid>')
@app.route('/video_listen/<vid>:<idx>')
@app.route('/video_listen/<vid>/')
@app.route('/video_listen/<vid>:<idx>/')
async def video_listen_view(vid, idx=0):
ato = request.args.get('ato') == '1'
# Convert ids to bvid for peace of mind.
vid = av2bv(vid[2:]) if vid.startswith('av') else vid
v = video.Video(bvid=vid, credential=appcred)
vinfo, vtags, vrelated, vcomments, vset = \
await asyncio.gather(v.get_info(), v.get_tags(idx), v.get_related(),
comment.get_comments(vid, comment.CommentResourceType.VIDEO, 1, comment.OrderType.LIKE), v.get_pages())
# Store the download urls for proxies to use.
if not appredis.exists(f'mikuinv_{vid}_{idx}_0'):
vsrc = await video_get_dash_for_qn(v, idx)
appredis.setex(f'mikuinv_{vid}_{idx}_0', 1800, vsrc['dash']['audio'][0]['baseUrl'])
return await render_template_with_theme('video_listen.html', vid=vid, vinfo=vinfo, vrelated=vrelated[:10], vcomments=vcomments,
keywords = ','.join(map(lambda x: x['tag_name'], vtags)), ato=ato, idx=idx, vset=vset)
@app.route('/video/<vid>')
@app.route('/video/<vid>/')
@app.route('/video/<vid>:<idx>')
@app.route('/video/<vid>:<idx>/')
async def video_view(vid, idx=0):
idx = int(idx)
ato = request.args.get('ato') == '1'
if request.args.get('listen') == '1':
return await video_listen_view(vid, idx)
# Convert ids to bvid for peace of mind.
vid = av2bv(vid[2:]) if vid.startswith('av') else vid
v = video.Video(bvid=vid, credential=appcred)
# Fetch the download urls ahead of time to avoid blocking.
v_supported_src, vinfo, vtags, vrelated, vcomments, vset = \
await asyncio.gather(video_get_src_for_qn(v, idx), v.get_info(), v.get_tags(idx), v.get_related(),
comment.get_comments(vid, comment.CommentResourceType.VIDEO, 1, comment.OrderType.LIKE), v.get_pages())
v_supported_src = v_supported_src['support_formats']
# Store the download urls for proxies to use.
if not appredis.exists(f'mikuinv_{vid}_{idx}_16'):
for vsrc in await asyncio.gather(*[video_get_src_for_qn(v, idx, fmt['quality']) for fmt in v_supported_src]):
qn = vsrc['quality']
appredis.setex(f'mikuinv_{vid}_{idx}_{qn}', 1800, vsrc['durl'][0]['url'])
for vsrc in v_supported_src:
qn = vsrc['quality']
if not appredis.exists(f'mikuinv_{vid}_{idx}_{qn}'):
appredis.setex(f'mikuinv_{vid}_{idx}_{qn}', 1800, appredis.get(f'mikuinv_{vid}_{idx}_16'))
return await render_template_with_theme('video.html', vid=vid, vinfo=vinfo, vcomments=vcomments, vrelated=vrelated[:15],
keywords = ','.join(map(lambda x: x['tag_name'], vtags)),
supported_src=v_supported_src, ato=ato, idx=idx, vset=vset)