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
# 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/>.
'''Bilibili extra apis'''
import subprocess
from bilibili_api.utils.network_httpx import request
from bilibili_api.exceptions import ArgsException
from bs4 import BeautifulSoup
from shared import appconf
'''Format the result returned by cv link.'''
def article_to_html(article_text):
article_soup = BeautifulSoup(article_text, features='lxml')
article_body = article_soup.find('div', id='read-article-holder')
article_body.attrs = {}
article_body['id'] = 'main-article'
del_elems = []
purge_elems = []
for child in article_body.descendants:
if not child.name:
continue
if child.name.startswith('h'):
child.name = f'h{int(child.name[1:])+1}'
if child.name == 'strong' and child.parent.name.startswith('h'):
purge_elems.append(child.parent)
if not hasattr(child, 'attrs'):
continue
if child.name == 'a':
child['href'] = child['href'].split('//')[1].strip('www.bilibili.com')
continue
elif child.name == 'img':
if appconf['proxy']['image']:
child['src'] = '/proxy/pic/' + child['data-src'].split('//')[1]
else:
child['src'] = child['data-src']
del child['data-src']
del child['data-size']
continue
elif child.name == 'span' and not child.parent in purge_elems:
purge_elems.append(child.parent)
child.attrs = {}
for purge_elem in purge_elems:
try:
purge_elem.string = purge_elem.get_text()
except:
pass
for del_elem in del_elems:
try:
del_elem.extract()
except:
pass
return str(article_body)
'''Convert the article to any file.'''
def article_to_any(article_text, dest_fmt):
cmd = ['pandoc', '-f', 'html', '-t', dest_fmt, '-']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output, _ = p.communicate(input=article_to_html(article_text).encode("utf-8"))
return output.decode("utf-8")
async def video_get_src_for_qn(vi, idx, quality = 16):
'''Get a specific available source for video.'''
cid = await vi.get_cid(idx)
return await request('GET', 'https://api.bilibili.com/x/player/playurl',
params={ 'avid': vi.get_aid(), 'cid': cid, 'qn': quality },
credential=vi.credential)
async def video_get_dash_for_qn(vi, idx):
'''Get a specific available source for video.'''
cid = await vi.get_cid(idx)
return await request('GET', 'https://api.bilibili.com/x/player/playurl',
params={ 'avid': vi.get_aid(), 'cid': cid, 'fnval': '16' },
credential=vi.credential)
# The following algorithm is adopted from bilibili-API-collect.
# https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/other/bvid_desc.md
table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
itable = { table[i]: i for i in range(len(table)) }
s = [11, 10, 3, 8, 4, 6]
XOR = 177451812
ADD = 8728348608
def bv2av(x):
r = 0
for i in range(6):
r += itable[x[s[i]]] * 58 ** i
return (r - ADD) ^ XOR
def av2bv(x):
try:
x = int(x[2:] if str(x).startswith('av') else x)
x = (x ^ XOR) + ADD
r = list('BV1 4 1 7 ')
for i in range(6):
r[s[i]] = table[x // 58 ** i % 58]
return ''. join(r)
except ValueError:
raise ArgsException("avid 提供错误,必须是以 av 开头的数字组成的字符串。")