Spaces:
Runtime error
Runtime error
import hashlib | |
from enum import Enum | |
from random import randint | |
from typing import Any, Optional | |
from hibiapi.utils.config import APIConfig | |
from hibiapi.utils.net import catch_network_error | |
from hibiapi.utils.routing import BaseEndpoint, dont_route | |
Config = APIConfig("tieba") | |
class TiebaSignUtils: | |
salt = b"tiebaclient!!!" | |
def random_digit(length: int) -> str: | |
return "".join(map(str, [randint(0, 9) for _ in range(length)])) | |
def construct_content(params: dict[str, Any]) -> bytes: | |
# NOTE: this function used to construct form content WITHOUT urlencode | |
# Don't ask me why this is necessary, ask Tieba's programmers instead | |
return b"&".join( | |
map( | |
lambda k, v: ( | |
k.encode() | |
+ b"=" | |
+ str(v.value if isinstance(v, Enum) else v).encode() | |
), | |
params.keys(), | |
params.values(), | |
) | |
) | |
def sign(cls, params: dict[str, Any]) -> bytes: | |
params.update( | |
{ | |
"_client_id": ( | |
"wappc_" + cls.random_digit(13) + "_" + cls.random_digit(3) | |
), | |
"_client_type": 2, | |
"_client_version": "9.9.8.32", | |
**{ | |
k.upper(): str(v).strip() | |
for k, v in Config["net"]["params"].as_dict().items() | |
if v | |
}, | |
} | |
) | |
params = {k: params[k] for k in sorted(params.keys())} | |
params["sign"] = ( | |
hashlib.md5(cls.construct_content(params).replace(b"&", b"") + cls.salt) | |
.hexdigest() | |
.upper() | |
) | |
return cls.construct_content(params) | |
class TiebaEndpoint(BaseEndpoint): | |
base = "http://c.tieba.baidu.com" | |
async def request( | |
self, endpoint: str, *, params: Optional[dict[str, Any]] = None | |
) -> dict[str, Any]: | |
response = await self.client.post( | |
url=self._join(self.base, endpoint, {}), | |
content=TiebaSignUtils.sign(params or {}), | |
) | |
response.raise_for_status() | |
return response.json() | |
async def post_list(self, *, name: str, page: int = 1, size: int = 50): | |
return await self.request( | |
"c/f/frs/page", | |
params={ | |
"kw": name, | |
"pn": page, | |
"rn": size, | |
}, | |
) | |
async def post_detail( | |
self, | |
*, | |
tid: int, | |
page: int = 1, | |
size: int = 50, | |
reversed: bool = False, | |
): | |
return await self.request( | |
"c/f/pb/page", | |
params={ | |
**({"last": 1, "r": 1} if reversed else {}), | |
"kz": tid, | |
"pn": page, | |
"rn": size, | |
}, | |
) | |
async def subpost_detail( | |
self, | |
*, | |
tid: int, | |
pid: int, | |
page: int = 1, | |
size: int = 50, | |
): | |
return await self.request( | |
"c/f/pb/floor", | |
params={ | |
"kz": tid, | |
"pid": pid, | |
"pn": page, | |
"rn": size, | |
}, | |
) | |
async def user_profile(self, *, uid: int): | |
return await self.request( | |
"c/u/user/profile", | |
params={ | |
"uid": uid, | |
"need_post_count": 1, | |
"has_plist": 1, | |
}, | |
) | |
async def user_subscribed( | |
self, *, uid: int, page: int = 1 | |
): # XXX This API required user login! | |
return await self.request( | |
"c/f/forum/like", | |
params={ | |
"is_guest": 0, | |
"uid": uid, | |
"page_no": page, | |
}, | |
) | |