|
"""
|
|
bilibili_api.rank
|
|
|
|
和哔哩哔哩视频排行榜相关的 API
|
|
"""
|
|
|
|
from enum import Enum
|
|
from typing import Union
|
|
|
|
from .utils.utils import get_api
|
|
from .utils.credential import Credential
|
|
from .utils.network import Api
|
|
|
|
API = get_api("rank")
|
|
|
|
|
|
class RankAPIType(Enum):
|
|
"""
|
|
排行榜 API 接口类型
|
|
|
|
- PGC: https://api.bilibili.com/pgc/web/rank/list
|
|
- V2: https://api.bilibili.com/x/web-interface/ranking/v2
|
|
"""
|
|
|
|
PGC = "pgc"
|
|
V2 = "x"
|
|
|
|
|
|
class RankDayType(Enum):
|
|
"""
|
|
RankAPIType.PGC 排行榜时间类型
|
|
|
|
- THREE_DAY: 三日排行
|
|
- WEEK: 周排行
|
|
"""
|
|
|
|
THREE_DAY = 3
|
|
WEEK = 7
|
|
|
|
|
|
class RankType(Enum):
|
|
"""
|
|
排行榜类型
|
|
|
|
- All: 全部
|
|
- Bangumi: 番剧
|
|
- GuochuangAnime: 国产动画
|
|
- Guochuang: 国创相关
|
|
- Documentary: 纪录片
|
|
- Douga: 动画
|
|
- Music: 音乐
|
|
- Dance: 舞蹈
|
|
- Game: 游戏
|
|
- Knowledge: 知识
|
|
- Technology: 科技
|
|
- Sports: 运动
|
|
- Car: 汽车
|
|
- Life: 生活
|
|
- Food: 美食
|
|
- Animal: 动物圈
|
|
- Kitchen: 鬼畜
|
|
- Fashion: 时尚
|
|
- Ent: 娱乐
|
|
- Cinephile: 影视
|
|
- Movie: 电影
|
|
- TV: 电视剧
|
|
- Variety: 综艺
|
|
- Original: 原创
|
|
- Rookie: 新人
|
|
"""
|
|
|
|
All = {"api_type": "x", "rid": 0, "type": "all"}
|
|
Bangumi = {"api_type": "pgc", "season_type": 1}
|
|
GuochuangAnime = {"api_type": "pgc", "season_type": 4}
|
|
Guochuang = {"api_type": "x", "rid": 168, "type": "all"}
|
|
Documentary = {"api_type": "pgc", "season_type": 3}
|
|
Douga = {"api_type": "x", "rid": 1, "type": "all"}
|
|
Music = {"api_type": "x", "rid": 3, "type": "all"}
|
|
Dance = {"api_type": "x", "rid": 129, "type": "all"}
|
|
Game = {"api_type": "x", "rid": 4, "type": "all"}
|
|
Knowledge = {"api_type": "x", "rid": 36, "type": "all"}
|
|
Technology = {"api_type": "x", "rid": 188, "type": "all"}
|
|
Sports = {"api_type": "x", "rid": 234, "type": "all"}
|
|
Car = {"api_type": "x", "rid": 223, "type": "all"}
|
|
Life = {"api_type": "x", "rid": 160, "type": "all"}
|
|
Food = {"api_type": "x", "rid": 211, "type": "all"}
|
|
Animal = {"api_type": "x", "rid": 217, "type": "all"}
|
|
Kichiku = {"api_type": "x", "rid": 119, "type": "all"}
|
|
Fashion = {"api_type": "x", "rid": 155, "type": "all"}
|
|
Ent = {"api_type": "x", "rid": 5, "type": "all"}
|
|
Cinephile = {"api_type": "x", "rid": 181, "type": "all"}
|
|
Movie = {"api_type": "pgc", "season_type": 2}
|
|
TV = {"api_type": "pgc", "season_type": 5}
|
|
Variety = {"api_type": "pgc", "season_type": 7}
|
|
Original = {"api_type": "x", "rid": 0, "type": "origin"}
|
|
Rookie = {"api_type": "x", "rid": 0, "type": "rookie"}
|
|
|
|
|
|
class VIPRankType(Enum):
|
|
"""
|
|
大会员中心热播榜单类型,即 rank_id
|
|
|
|
- VIP: 会员
|
|
- BANGUMI: 番剧
|
|
- GUOCHUANG: 国创
|
|
- MOVIE: 电影
|
|
- DOCUMENTARY: 纪录片
|
|
- TV: 电视剧
|
|
- VARIETY: 综艺
|
|
"""
|
|
|
|
VIP = 279
|
|
BANGUMI = 118
|
|
GUOCHUANG = 119
|
|
MOVIE = 174
|
|
DOCUMENTARY = 175
|
|
TV = 176
|
|
VARIETY = 177
|
|
|
|
|
|
class MangeRankType(Enum):
|
|
"""
|
|
漫画排行榜类型
|
|
|
|
- NEW: 新作
|
|
- BOY: 男生
|
|
- GRIL: 女生
|
|
- GUOCHUANG: 国漫
|
|
- JAPAN: 日漫
|
|
- SOUTHKOREA: 韩漫
|
|
- OFFICAL: 宝藏
|
|
- FINISH: 完结
|
|
"""
|
|
|
|
NEW = 7
|
|
BOY = 11
|
|
GRIL = 12
|
|
GUOCHUANG = 1
|
|
JAPAN = 0
|
|
SOUTHKOREA = 2
|
|
OFFICAL = 5
|
|
FINISH = 13
|
|
|
|
|
|
class LiveRankType(Enum):
|
|
"""
|
|
直播通用榜类型
|
|
|
|
- SAIL_BOAT_VALUE: 主播舰队榜
|
|
- SAIL_BOAT_TICKET: 船员价值榜
|
|
- SAIL_BOAT_NUMBER: 舰船人数榜
|
|
- MASTER_LEVEL: 主播等级榜
|
|
- USER_LEVEL: 用户等级榜
|
|
"""
|
|
|
|
SAIL_BOAT_VALUE = "sail_boat_value"
|
|
SAIL_BOAT_TICKET = "sail_boat_ticket"
|
|
SAIL_BOAT_NUMBER = "sail_boat_number"
|
|
MASTER_LEVEL = "master_level"
|
|
USER_LEVEL = "user_level"
|
|
|
|
|
|
class LiveEnergyRankType(Enum):
|
|
"""
|
|
直播超能用户榜类型
|
|
|
|
- MONTH: 本月
|
|
- PRE_MONTH: 上月
|
|
"""
|
|
|
|
MONTH = "month"
|
|
PRE_MONTH = "pre_month"
|
|
|
|
|
|
async def get_rank(
|
|
type_: RankType = RankType.All, day: RankDayType = RankDayType.THREE_DAY
|
|
) -> dict:
|
|
"""
|
|
获取视频排行榜
|
|
|
|
Args:
|
|
type_ (RankType): 排行榜类型. Defaults to RankType.All
|
|
|
|
day (RankDayType): 排行榜时间. Defaults to RankDayType.THREE_DAY
|
|
仅对 api_type 为 RankAPIType.PGC 有效
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
params = {}
|
|
|
|
|
|
if type_.value["api_type"] == RankAPIType.V2.value:
|
|
api = API["info"]["v2_ranking"]
|
|
params["rid"] = type_.value["rid"]
|
|
elif type_.value["api_type"] == RankAPIType.PGC.value:
|
|
api = API["info"]["pgc_ranking"]
|
|
params["season_type"] = type_.value["season_type"]
|
|
params["day"] = day.value
|
|
else:
|
|
raise Exception("Unknown RankType")
|
|
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_music_rank_list() -> dict:
|
|
"""
|
|
获取全站音乐榜每周信息(不包括具体的音频列表)
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["music_weekly_series"]
|
|
params = {"list_type": 1}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_music_rank_weekly_detail(week: int = 1) -> dict:
|
|
"""
|
|
获取全站音乐榜一周的详细信息(不包括具体的音频列表)
|
|
|
|
Args:
|
|
week(int): 第几周. Defaults to 1.
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["music_weekly_details"]
|
|
params = {"list_id": week}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_music_rank_weekly_musics(week: int = 1) -> dict:
|
|
"""
|
|
获取全站音乐榜一周的音频列表(返回的音乐的 id 对应了 music.Music 类创建实例传入的 id)
|
|
|
|
Args:
|
|
week(int): 第几周. Defaults to 1.
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["music_weekly_content"]
|
|
params = {"list_id": week}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_vip_rank(type_: VIPRankType = VIPRankType.VIP) -> dict:
|
|
"""
|
|
获取大会员中心的排行榜
|
|
|
|
Args:
|
|
type_ (VIPRankType): 排行榜类型. Defaults to VIPRankType.VIP
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["VIP_rank"]
|
|
params = {"rank_id": type_.value}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_manga_rank(type_: MangeRankType = MangeRankType.NEW, credential: Credential = None) -> dict:
|
|
"""
|
|
获取漫画专属排行榜
|
|
|
|
Args:
|
|
credential (Credential): 凭据类
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
credential = credential if credential else Credential()
|
|
credential.raise_for_no_sessdata()
|
|
|
|
api = API["info"]["manga_rank"]
|
|
params = {"device": "pc", "platform": "web"}
|
|
data = {"id": type_.value}
|
|
return (
|
|
await Api(**api, no_csrf=True, credential=credential)
|
|
.update_data(**data)
|
|
.update_params(**params)
|
|
.result
|
|
)
|
|
|
|
|
|
async def get_live_hot_rank() -> dict:
|
|
"""
|
|
获取直播首页人气排行榜
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["live_hot_rank"]
|
|
return await Api(**api).result
|
|
|
|
|
|
async def get_live_sailing_rank() -> dict:
|
|
"""
|
|
获取首页直播大航海排行榜
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["live_sailing_rank"]
|
|
return await Api(**api).update_params(**{}).result
|
|
|
|
|
|
async def get_live_energy_user_rank(
|
|
date: LiveEnergyRankType = LiveEnergyRankType.MONTH, pn: int = 1, ps: int = 20
|
|
) -> dict:
|
|
"""
|
|
获取直播超能用户榜
|
|
|
|
Args:
|
|
date (LiveEnergyRankType): 月份. Defaults to LiveEnergyRankType.MONTH
|
|
|
|
pn (int): 页码. Defaults to 1
|
|
|
|
ps (int): 每页数量. Defaults to 20
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["live_energy_user_rank"]
|
|
params = {"date": date.value, "page": pn, "page_size": ps}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_live_rank(
|
|
_type: LiveRankType = LiveRankType.SAIL_BOAT_VALUE, pn: int = 1, ps: int = 20
|
|
) -> dict:
|
|
"""
|
|
获取直播通用榜单
|
|
|
|
Args:
|
|
_type (LiveRankType): 榜单类型. Defaults to LiveRankType.VALUE
|
|
|
|
pn (int): 页码. Defaults to 1
|
|
|
|
ps (int): 每页数量. Defaults to 20
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["live_web_top"]
|
|
params = {
|
|
"type": _type.value,
|
|
"page": pn,
|
|
"page_size": ps,
|
|
"is_trend": 1,
|
|
"area_id": None,
|
|
}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def get_live_user_medal_rank(pn: int = 1, ps: int = 20) -> dict:
|
|
"""
|
|
获取直播用户勋章榜
|
|
|
|
Args:
|
|
pn (int): 页码. Defaults to 1
|
|
|
|
ps (int): 每页数量. Defaults to 20
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["live_medal_level_rank"]
|
|
params = {"page": pn, "page_size": ps}
|
|
return await Api(**api).update_params(**params).result
|
|
|
|
|
|
async def subscribe_music_rank(
|
|
status: bool = True, credential: Union[Credential, None] = None
|
|
) -> dict:
|
|
"""
|
|
设置关注全站音乐榜
|
|
|
|
Args:
|
|
status (bool) : 关注状态. Defaults to True.
|
|
|
|
credential (Credential): 凭据类. Defaults to None.
|
|
"""
|
|
credential = credential if credential else Credential()
|
|
credential.raise_for_no_sessdata()
|
|
credential.raise_for_no_bili_jct()
|
|
api = API["operate"]["subscribe"]
|
|
data = {"list_id": 1, "state": (1 if status else 2)}
|
|
return await Api(**api, credential=credential).update_data(**data).result
|
|
|
|
|
|
async def get_playlet_rank_phases() -> dict:
|
|
"""
|
|
获取全站短剧榜期数
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["playlet_rank_phase"]
|
|
return await Api(**api, json_body=True, no_csrf=True).result
|
|
|
|
|
|
async def get_playlet_rank_info(phase_id: int) -> dict:
|
|
"""
|
|
获取全站短剧榜
|
|
|
|
https://www.bilibili.com/v/popular/drama/
|
|
|
|
Args:
|
|
phase_id (int): 期数,从 get_playlet_rank_phase 获取
|
|
|
|
Returns:
|
|
dict: 调用 API 返回的结果
|
|
"""
|
|
api = API["info"]["playlet_rank_info"]
|
|
data = {"phaseID": phase_id}
|
|
return await Api(**api, json_body=True, no_csrf=True).update_data(**data).result
|
|
|