Skip to content

Commit

Permalink
Merge pull request #384 from Nemo2011/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
z0z0r4 authored Jul 8, 2023
2 parents 86f6882 + 63494c4 commit 94caf9d
Show file tree
Hide file tree
Showing 15 changed files with 323 additions and 255 deletions.
2 changes: 1 addition & 1 deletion bilibili_api/credential.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Credential(_Credential):
凭据操作类,用于各种请求操作。
"""

async def chcek_refresh(self) -> bool:
async def check_refresh(self) -> bool:
"""
检查是否需要刷新 cookies
Expand Down
5 changes: 3 additions & 2 deletions bilibili_api/data/api/login.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
"comment": "请求二维码及登录密钥"
},
"get_events": {
"url": "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?source=main-fe-header",
"url": "https://passport.bilibili.com/x/passport-login/web/qrcode/poll",
"method": "GET",
"verify": false,
"data": {
"qrcode_key": "str: 登陆密钥"
"qrcode_key": "str: 登陆密钥",
"source": "main-fe-header"
},
"comment": "获取最新信息"
},
Expand Down
6 changes: 4 additions & 2 deletions bilibili_api/data/api/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,13 @@
"comment": "获取用户所有关注(需要用户公开信息)"
},
"all_followings2": {
"url": "https://app.biliapi.net/x/v2/relation/followings",
"url": "https://api.bilibili.com/x/relation/followings",
"method": "GET",
"verify": false,
"verify": true,
"params": {
"vmid": "int: uid",
"order": "str: desc 倒序, asc 正序",
"order_type": "str: 按照关注顺序排列:留空 按照最常访问排列:attention",
"pn": "int: 页码",
"ps":"const int: 100"
},
Expand Down
10 changes: 6 additions & 4 deletions bilibili_api/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,16 @@ def transformPicInfo(image: dict):
return data


async def upload_image(image: Picture, credential: Credential) -> dict:
async def upload_image(image: Picture, credential: Credential, data: dict = None) -> dict:
"""
上传动态图片
Args:
image (Picture) : 图片流. 有格式要求.
image (Picture) : 图片流. 有格式要求.
credential (Credential): 凭据
credential (Credential): 凭据
data (dict): 自定义请求体
Returns:
dict: 调用 API 返回的结果
"""
Expand All @@ -197,7 +198,8 @@ async def upload_image(image: Picture, credential: Credential) -> dict:
api = API["send"]["upload_img"]
raw = image.content

data = {"biz": "new_dyn", "category": "daily"}
if data is None:
data = {"biz": "new_dyn", "category": "daily"}

return_info = await request(
"POST",
Expand Down
7 changes: 5 additions & 2 deletions bilibili_api/live.py
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,9 @@ async def __main(self) -> None:
self.logger.info(f"准备连接直播间 {self.room_display_id}")
# 获取真实房间号
self.logger.debug("正在获取真实房间号")
self.__room_real_id = (await room.get_room_play_info())["room_id"]
info = await room.get_room_play_info()
self.__room__uid = info["uid"]
self.__room_real_id = info["room_id"]
self.logger.debug(f"获取成功,真实房间号:{self.__room_real_id}")

# 获取直播服务器配置
Expand Down Expand Up @@ -1064,9 +1066,10 @@ async def __handle_data(self, data) -> None:

async def __send_verify_data(self, ws: ClientWebSocketResponse, token: str) -> None:
verifyData = {
"uid": 0,
"uid": self.__room__uid,
"roomid": self.__room_real_id,
"protover": 3,
"buvid": self.credential.buvid3,
"platform": "web",
"type": 2,
"key": token,
Expand Down
175 changes: 111 additions & 64 deletions bilibili_api/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import uuid
from yarl import URL
import webbrowser
import sys

import requests
from .exceptions.LoginError import LoginError

from .utils.credential import Credential
Expand Down Expand Up @@ -54,14 +54,40 @@
is_destroy = False
id_ = 0 # 事件 id,用于取消 after 绑定


def parse_credential_url(events: dict) -> Credential:
url = events["data"]["url"]
cookies_list = url.split("?")[1].split("&")
sessdata = ""
bili_jct = ""
dedeuserid = ""
for cookie in cookies_list:
if cookie[:8] == "SESSDATA":
sessdata = cookie[9:]
if cookie[:8] == "bili_jct":
bili_jct = cookie[9:]
if cookie[:11].upper() == "DEDEUSERID=":
dedeuserid = cookie[11:]
ac_time_value=events["data"]["refresh_token"]
buvid3=get_live_buvid()
return Credential(sessdata=sessdata,
bili_jct=bili_jct,
buvid3=buvid3,
dedeuserid=dedeuserid,
ac_time_value=ac_time_value)

def make_qrcode(url) -> str:
qr = qrcode.QRCode()
qr.add_data(url)
img = qr.make_image()
img.save(os.path.join(tempfile.gettempdir(), "qrcode.png"))
print("二维码已保存至", os.path.join(tempfile.gettempdir(), "qrcode.png"))
return os.path.join(tempfile.gettempdir(), "qrcode.png")

def update_qrcode_data() -> dict:
api = API["qrcode"]["get_qrcode_and_token"]
qrcode_data = httpx.get(api["url"], follow_redirects=True).json()['data']
return qrcode_data


def login_with_qrcode(root=None) -> Credential:
"""
Expand All @@ -85,68 +111,42 @@ def login_with_qrcode(root=None) -> Credential:
if root == None:
root = tkinter.Tk()
root.title("扫码登录")
qrcode_image = update_qrcode()
qrcode_data = update_qrcode_data()
login_key = qrcode_data["qrcode_key"]
qrcode_image = make_qrcode(qrcode_data["url"])
photo = PhotoImage(file=qrcode_image)
qrcode_label = tkinter.Label(root, image=photo, width=500, height=500)
qrcode_label = tkinter.Label(root, image=photo, width=600, height=600)
qrcode_label.pack()
big_font = tkinter.font.Font(root, size=25)
log = tkinter.Label(root, text="请扫描二维码↑", font=big_font, fg="red")
log.pack()

def update_events():
global id_
global start, credential, is_destroy
# log.configure(text="点下确认啊!", fg="orange", font=big_font)
events_api = API["qrcode"]["get_events"]
params = {"qrcode_key": login_key}
events = json.loads(
requests.get(
events_api["url"],
params=params,
cookies={"buvid3": str(uuid.uuid1()), "Domain": ".bilibili.com"},
).text
)
# print(events)
# 新的 events["data"]
# {'url': '', 'refresh_token': '', 'timestamp': 0, 'code': 86101, 'message': '未扫码'}
# {'url': '', 'refresh_token': '', 'timestamp': 0, 'code': 86090, 'message': '二维码已扫码未确认'}
# {'url': 'https://passport.biligame.com/x/passport-login/web/crossDomain?DedeUserID=x&DedeUserID__ckMd5=x&Expires=x&SESSDATA=x&bili_jct=x&gourl=x', 'refresh_token': 'x', 'timestamp': 1683903305723, 'code': 0, 'message': ''}
if "code" in events.keys() and events["code"] == -412:
raise LoginError(events["message"])
if events["data"]["code"] == 86101:
log.configure(text="请扫描二维码↑", fg="red", font=big_font)
elif events["data"]["code"] == 86090:
log.configure(text="点下确认啊!", fg="orange", font=big_font)
elif events["data"]["code"] == 0:
url: str = events["data"]["url"]
cookies_list = url.split("?")[1].split("&")
sessdata = ""
bili_jct = ""
dedeuserid = ""
for cookie in cookies_list:
if cookie[:8] == "SESSDATA":
sessdata = cookie[9:]
if cookie[:8] == "bili_jct":
bili_jct = cookie[9:]
if cookie[:11].upper() == "DEDEUSERID=":
dedeuserid = cookie[11:]
c = Credential(
sessdata=sessdata,
bili_jct=bili_jct,
dedeuserid=dedeuserid,
ac_time_value=events["data"]["refresh_token"],
)
global credential
credential = c
log.configure(text="成功!", fg="green", font=big_font)
global start
start = time.perf_counter()
root.after(1000, destroy)
id_ = root.after(500, update_events)
# 刷新
if time.perf_counter() - start > 120:
update_qrcode()
start = time.perf_counter()
global start, credential, is_destroy, login_key
events = login_with_key(login_key)
if "code" in events.keys() and events["code"] == 0:
if events["data"]["code"] == 86101:
log.configure(text="请扫描二维码↑", fg="red", font=big_font)
elif events["data"]["code"] == 86090:
log.configure(text="点下确认啊!", fg="orange", font=big_font)
elif events["data"]["code"] == 86038:
raise LoginError("二维码过期,请扫新二维码!")
elif events["data"]["code"] == 0:
log.configure(text="成功!", fg="green", font=big_font)
credential = parse_credential_url(events)
root.after(1000, destroy)
return 0
id_ = root.after(500, update_events)
if time.perf_counter() - start > 120: # 刷新
qrcode_data = update_qrcode_data()
login_key = qrcode_data["qrcode_key"]
qrcode_image = make_qrcode(qrcode_data["url"])
photo = PhotoImage(file=qrcode_image)
qrcode_label = tkinter.Label(root, image=photo, width=600, height=600)
qrcode_label.pack()
start = time.perf_counter()

root.update()

def destroy():
Expand All @@ -159,16 +159,63 @@ def destroy():
root.after_cancel(id_) # type: ignore
return credential

def login_with_qrcode_term() -> Credential:
"""
终端扫描二维码登录
def update_qrcode() -> str:
global login_key, qrcode_image
api = API["qrcode"]["get_qrcode_and_token"]
qrcode_login_data = json.loads(httpx.get(api["url"]).text)["data"]
login_key = qrcode_login_data["qrcode_key"]
qrcode = qrcode_login_data["url"]
qrcode_image = make_qrcode(qrcode)
return qrcode_image
Args:
Returns:
Credential: 凭据
"""
import qrcode_terminal
qrcode_data = update_qrcode_data()
qrcode_url = qrcode_data["url"]
login_key = qrcode_data["qrcode_key"]
print(qrcode_terminal.qr_terminal_str(qrcode_url) + "\n")
while True:
events = login_with_key(login_key)
if "code" in events.keys() and events["code"] == 0:
if events["data"]["code"] == 86101:
sys.stdout.write('\r 请扫描二维码↑')
sys.stdout.flush()
elif events["data"]["code"] == 86090:
sys.stdout.write('\r 点下确认啊!')
sys.stdout.flush()
elif events["data"]["code"] == 86038:
print("二维码过期,请扫新二维码!")
qrcode_data = update_qrcode_data()
qrcode_url = qrcode_data["url"]
print(qrcode_terminal.qr_terminal_str(qrcode_url) + "\n")
elif events["data"]["code"] == 0:
sys.stdout.write('\r 成功!')
sys.stdout.flush()
return parse_credential_url(events)
elif "code" in events.keys():
raise LoginError(events["message"])
time.sleep(0.5)


def login_with_key(key: str) -> dict:
params = {"qrcode_key": key, "source": "main-fe-header"}
events_api = API["qrcode"]["get_events"]
events = httpx.get(
events_api["url"],
params=params,
cookies={"buvid3": str(uuid.uuid1()), "Domain": ".bilibili.com"},
).json()
return events


def get_live_buvid():
import re
url = "https://api.live.bilibili.com/gift/v3/live/gift_config"
headers = HEADERS.copy()
response = httpx.get(url, headers=headers)
response.raise_for_status()
set_cookie = response.headers.get("Set-Cookie")
live_buvid = re.findall(r"LIVE_BUVID=(AUTO[0-9]+)", set_cookie)[0]
return live_buvid

# ----------------------------------------------------------------
# 密码登录
Expand Down
2 changes: 1 addition & 1 deletion bilibili_api/login_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def get_qrcode() -> Tuple[Picture, str]:
Returns:
Tuple[dir, str]: 第一项是二维码图片地址(本地缓存)和登录密钥。登录密钥需要保存。
"""
img = login.update_qrcode()
img = login.update_qrcode_image()
login_key = login.login_key
return (Picture.from_file(img), login_key)

Expand Down
4 changes: 2 additions & 2 deletions bilibili_api/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ async def send_msg(
"msg[msg_type]": int(msg_type),
"msg[msg_status]": 0,
"msg[content]": real_content,
"msg[dev_id]": "B9A37BF3-AA9D-4076-A4D3-366AC8C4C5DB",
"msg[new_face_version]": "0",
"msg[dev_id]": "A6716E9A-7CE3-47AF-994B-F0B34178D28D",
"msg[new_face_version]": 0,
"msg[timestamp]": int(time.time()),
"from_filework": 0,
"build": 0,
Expand Down
18 changes: 15 additions & 3 deletions bilibili_api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ class HistoryBusinessType(Enum):
article_list = "article-list"
article = "article"

class OrderType(Enum):
"""
排序字段
+ desc:倒序
+ asc:正序
"""
desc = "desc"
asc = "asc"

async def name2uid(names: Union[str, List[str]]):
"""
Expand Down Expand Up @@ -234,7 +243,7 @@ async def __get_self_info(self) -> dict:
if self.__self_info is not None:
return self.__self_info

self.__self_info = await get_self_info(credential=self.credential)
self.__self_info = await self.get_user_info()
return self.__self_info

def get_uid(self) -> int:
Expand Down Expand Up @@ -562,7 +571,7 @@ async def get_subscribed_bangumi(
)

async def get_followings(
self, pn: int = 1, ps: int = 100, attention: bool = False
self, pn: int = 1, ps: int = 100, attention: bool = False, order: OrderType = OrderType.desc
) -> dict:
"""
获取用户关注列表(不是自己只能访问前 5 页)
Expand All @@ -572,7 +581,9 @@ async def get_followings(
ps (int, optional) : 每页的数据量. Defaults to 100.
attention (bool, optional) : 是否采用“最常访问”排序. Defaults to False.
attention (bool, optional) : 是否采用“最常访问”排序,否则为“关注顺序”排序. Defaults to False.
order (OrderType, optional) : 排序方式. Defaults to OrderType.desc.
Returns:
dict: 调用接口返回的内容。
Expand All @@ -583,6 +594,7 @@ async def get_followings(
"ps": ps,
"pn": pn,
"order_type": "attention" if attention else "",
"order": order.value
}
return await request(
"GET", url=api["url"], params=params, credential=self.credential
Expand Down
Loading

0 comments on commit 94caf9d

Please sign in to comment.