Skip to content

Commit

Permalink
fix artist_get/song_list_hot_comments
Browse files Browse the repository at this point in the history
  • Loading branch information
cosven committed Jan 26, 2024
1 parent 6c56323 commit f0bce05
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 17 deletions.
29 changes: 20 additions & 9 deletions fuo_bilibili/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Type, Optional, Union, List

import requests.cookies
from cachetools import TTLCache, cached
from cachetools import TTLCache
from .compat import BaseModel

from fuo_bilibili.api.audio import AudioMixin
Expand All @@ -14,15 +14,12 @@
from fuo_bilibili.api.login import LoginMixin
from fuo_bilibili.api.media import MediaMixin
from fuo_bilibili.api.playlist import PlaylistMixin
from fuo_bilibili.api.schema.enums import VideoQualityNum, SearchType
from fuo_bilibili.api.schema.requests import BaseRequest, VideoInfoRequest, PlayUrlRequest, SearchRequest, \
FavoriteListRequest, PaginatedRequest, AudioFavoriteSongsRequest, AnotherPaginatedRequest, LivePlayUrlRequest, \
MediaFavlistRequest, HistoryAddLaterVideosRequest, BaseCsrfRequest, HistoryDelLaterVideosRequest, \
UserFollowingRequest, WeeklyDetailRequest
from fuo_bilibili.api.schema.responses import BaseResponse
from fuo_bilibili.api.schema.requests import * # noqa
from fuo_bilibili.api.schema.responses import * # noqa
from fuo_bilibili.api.user import UserMixin
from fuo_bilibili.api.video import VideoMixin
from fuo_bilibili.const import PLUGIN_API_COOKIEJAR_FILE, DANMAKU_DIRECTORY
from fuo_bilibili.const import PLUGIN_API_COOKIEJAR_FILE
from .wbi import encWbi

CACHE = TTLCache(50, ttl=timedelta(minutes=10).total_seconds())

Expand All @@ -44,6 +41,7 @@ def __init__(self):
# UPDATE(2023-xx-xx): The header cause some API failing: self.nav_info
self._session.headers.update(self._headers)
self._session.cookies = self._cookie
self._wbi: Optional[NavInfoResponse.NavInfoResponseData.Wbi] = None

@staticmethod
def cookie_check():
Expand Down Expand Up @@ -73,6 +71,9 @@ def load_cookies(self):
def _dump_cookie_to_file(self):
self._cookie.save()

def set_wbi(self, wbi: NavInfoResponse.NavInfoResponseData.Wbi):
self._wbi = wbi

@staticmethod
def clear_cache_by_url(urls: List[str]):
for key in CACHE.keys():
Expand All @@ -95,8 +96,18 @@ def get_uncached(self, url: str, param: Optional[BaseRequest], clazz: Union[Type
else:
if isinstance(param, BaseCsrfRequest):
param.csrf = self._get_csrf()
js = json.loads(param.json(exclude_none=True))
elif isinstance(param, BaseWbiRequest):
if self._wbi is None:
raise RuntimeError('wbi info is empty (not logged in)')
img_key = self._wbi.img_url.rsplit('/', 1)[1].split('.')[0]
sub_key = self._wbi.sub_url.rsplit('/', 1)[1].split('.')[0]
js = json.loads(param.json(exclude_none=True))
js = encWbi(js, img_key, sub_key)
else:
js = json.loads(param.json(exclude_none=True))
r = self._session.get(url, timeout=self.TIMEOUT,
params=json.loads(param.json(exclude_none=True)),
params=js,
**kwargs)
if r.status_code != 200:
print(r.text)
Expand Down
8 changes: 6 additions & 2 deletions fuo_bilibili/api/schema/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ def __hash__(self):
return hash(self.json())


class BaseWbiRequest(BaseRequest):
pass


class GeetestBase(BaseModel):
token: str
challenge: str
Expand Down Expand Up @@ -119,15 +123,15 @@ class HomeDynamicVideoRequest(BaseRequest):
page: int = 1


class UserInfoRequest(BaseRequest):
class UserInfoRequest(BaseWbiRequest):
mid: int # 用户UID


class UserBestVideoRequest(BaseRequest):
vmid: int


class UserVideoRequest(PaginatedRequest):
class UserVideoRequest(BaseWbiRequest, PaginatedRequest):
mid: int
order: str = None
tid: int = None
Expand Down
9 changes: 7 additions & 2 deletions fuo_bilibili/api/schema/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ class Wallet(BaseModel):
bcoin_balance: int # B币
coupon_balance: int # 赠送B币数

class Wbi(BaseModel):
img_url: str
sub_url: str

isLogin: bool
email_verified: bool = None
face: str = None
Expand All @@ -243,6 +247,7 @@ class Wallet(BaseModel):
wallet: Wallet = None
level_info: LevelInfo = None
vip_label: VipLabel = None
wbi_img: Wbi = None

@classmethod
@validator('vipDueDate')
Expand Down Expand Up @@ -817,8 +822,8 @@ class Member(BaseModel):

class Content(BaseModel):
message: str
plat: int
device: str
# plat: int
# device: str

rpid: int
like: int
Expand Down
4 changes: 2 additions & 2 deletions fuo_bilibili/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def get_uncached(self, url: str, param: Optional[BaseRequest], clazz: Union[Type
pass

def user_info(self, param: UserInfoRequest) -> UserInfoResponse:
url = f'{self.APIX_BASE}/space/acc/info'
url = f'{self.APIX_BASE}/space/wbi/acc/info'
return self.get_uncached(url, param, UserInfoResponse, headers={
'user-agent': 'Mozilla/5.0',
'referer': 'https://www.bilibili.com',
Expand All @@ -31,7 +31,7 @@ def user_best_videos(self, request: UserBestVideoRequest) -> UserBestVideoRespon
return self.get(url, request, UserBestVideoResponse)

def user_videos(self, request: UserVideoRequest) -> UserVideoResponse:
url = f'{self.APIX_BASE}/space/arc/search'
url = f'{self.APIX_BASE}/space/wbi/arc/search'
return self.get(url, request, UserVideoResponse)

def user_following(self, request: UserFollowingRequest) -> UserFollowingResponse:
Expand Down
39 changes: 39 additions & 0 deletions fuo_bilibili/api/wbi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
Copied from
https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
"""

from functools import reduce
from hashlib import md5
import urllib.parse
import time


mixinKeyEncTab = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
]

def getMixinKey(orig: str):
'对 imgKey 和 subKey 进行字符顺序打乱编码'
return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]


def encWbi(params: dict, img_key: str, sub_key: str):
'为请求参数进行 wbi 签名'
mixin_key = getMixinKey(img_key + sub_key)
curr_time = round(time.time())
params['wts'] = curr_time # 添加 wts 字段
params = dict(sorted(params.items())) # 按照 key 重排参数
# 过滤 value 中的 "!'()*" 字符
params = {
k : ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
for k, v
in params.items()
}
query = urllib.parse.urlencode(params) # 序列化参数
wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid
params['w_rid'] = wbi_sign
return params
5 changes: 3 additions & 2 deletions fuo_bilibili/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from feeluown.library import AbstractProvider, ProviderV2, ProviderFlags as Pf, UserModel, VideoModel, \
BriefPlaylistModel, BriefSongModel, LyricModel, SupportsSongSimilar, BriefSongProtocol, SupportsSongHotComments, \
SupportsAlbumGet, BriefAlbumModel, SupportsPlaylistAddSong, SupportsPlaylistRemoveSong, BriefUserModel, \
BriefArtistModel, SearchType as FuoSearchType, ModelType, SimpleSearchResult
BriefArtistModel, SearchType as FuoSearchType, ModelType, SimpleSearchResult, ModelNotFound
from feeluown.media import Quality, Media, MediaType, VideoAudioManifest
from feeluown.utils.reader import SequentialReader

Expand Down Expand Up @@ -146,6 +146,7 @@ def get_current_user(self):

def user_info(self) -> UserModel:
data: NavInfoResponse.NavInfoResponseData = self._api.nav_info().data
self._api.set_wbi(data.wbi_img)
user = UserModel(
source=__identifier__,
identifier=str(data.mid),
Expand Down Expand Up @@ -479,7 +480,7 @@ def album_get(self, identifier: str) -> Optional[BAlbumModel]:
_, __, ssid = identifier.split('_')
resp = self._api.media_bangumi_get_list(MediaGetListRequest(season_id=ssid))
return BAlbumModel.create_season_model(resp.result)
return None
raise ModelNotFound(f'album:{identifier} not found')

def playlist_get(self, identifier: str) -> Optional[BPlaylistModel]:
# fixme: fuo should support playlist_get v2 first
Expand Down

0 comments on commit f0bce05

Please sign in to comment.