bpi-py 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. bpi/__init__.py +29 -0
  2. bpi/_core/__init__.py +1 -0
  3. bpi/_core/params.py +21 -0
  4. bpi/_core/response.py +51 -0
  5. bpi/_generated/__init__.py +1 -0
  6. bpi/_generated/audio_client.py +217 -0
  7. bpi/_generated/audio_models.py +320 -0
  8. bpi/_generated/bangumi_client.py +68 -0
  9. bpi/_generated/bangumi_models.py +602 -0
  10. bpi/_generated/cheese_client.py +49 -0
  11. bpi/_generated/cheese_models.py +198 -0
  12. bpi/_generated/login_client.py +41 -0
  13. bpi/_generated/login_models.py +49 -0
  14. bpi/_generated/user_client.py +257 -0
  15. bpi/_generated/user_models.py +455 -0
  16. bpi/_generated/video_client.py +250 -0
  17. bpi/_generated/video_models.py +577 -0
  18. bpi/activity/__init__.py +4 -0
  19. bpi/activity/client.py +45 -0
  20. bpi/activity/models.py +42 -0
  21. bpi/activity/params.py +29 -0
  22. bpi/article/__init__.py +29 -0
  23. bpi/article/client.py +93 -0
  24. bpi/article/models.py +391 -0
  25. bpi/article/params.py +54 -0
  26. bpi/audio/__init__.py +58 -0
  27. bpi/audio/actions.py +111 -0
  28. bpi/audio/client.py +9 -0
  29. bpi/bangumi/__init__.py +18 -0
  30. bpi/bangumi/actions.py +34 -0
  31. bpi/bangumi/client.py +54 -0
  32. bpi/bangumi/models.py +55 -0
  33. bpi/cheese/__init__.py +3 -0
  34. bpi/cheese/client.py +51 -0
  35. bpi/cheese/models.py +120 -0
  36. bpi/client.py +410 -0
  37. bpi/clientinfo/__init__.py +4 -0
  38. bpi/clientinfo/client.py +43 -0
  39. bpi/clientinfo/models.py +11 -0
  40. bpi/comment/__init__.py +14 -0
  41. bpi/comment/client.py +139 -0
  42. bpi/comment/models.py +332 -0
  43. bpi/comment/params.py +176 -0
  44. bpi/creativecenter/__init__.py +63 -0
  45. bpi/creativecenter/client.py +344 -0
  46. bpi/creativecenter/models.py +526 -0
  47. bpi/creativecenter/params.py +237 -0
  48. bpi/danmaku/__init__.py +19 -0
  49. bpi/danmaku/client.py +219 -0
  50. bpi/danmaku/models.py +124 -0
  51. bpi/danmaku/params.py +238 -0
  52. bpi/dynamic/__init__.py +21 -0
  53. bpi/dynamic/client.py +285 -0
  54. bpi/dynamic/models.py +373 -0
  55. bpi/dynamic/params.py +161 -0
  56. bpi/electric/__init__.py +29 -0
  57. bpi/electric/client.py +181 -0
  58. bpi/electric/models.py +305 -0
  59. bpi/electric/params.py +139 -0
  60. bpi/errors.py +92 -0
  61. bpi/fav/__init__.py +41 -0
  62. bpi/fav/client.py +212 -0
  63. bpi/fav/models.py +196 -0
  64. bpi/fav/params.py +155 -0
  65. bpi/historytoview/__init__.py +24 -0
  66. bpi/historytoview/client.py +97 -0
  67. bpi/historytoview/models.py +176 -0
  68. bpi/historytoview/params.py +102 -0
  69. bpi/live/__init__.py +45 -0
  70. bpi/live/client.py +653 -0
  71. bpi/live/models.py +676 -0
  72. bpi/live/params.py +84 -0
  73. bpi/login/__init__.py +29 -0
  74. bpi/login/client.py +174 -0
  75. bpi/login/models.py +107 -0
  76. bpi/login/params.py +75 -0
  77. bpi/manga/__init__.py +25 -0
  78. bpi/manga/client.py +177 -0
  79. bpi/manga/models.py +116 -0
  80. bpi/manga/params.py +69 -0
  81. bpi/message/__init__.py +13 -0
  82. bpi/message/client.py +119 -0
  83. bpi/message/models.py +113 -0
  84. bpi/message/params.py +71 -0
  85. bpi/misc/__init__.py +13 -0
  86. bpi/misc/client.py +78 -0
  87. bpi/misc/models.py +44 -0
  88. bpi/misc/params.py +31 -0
  89. bpi/misc/sign.py +28 -0
  90. bpi/note/__init__.py +25 -0
  91. bpi/note/client.py +118 -0
  92. bpi/note/models.py +142 -0
  93. bpi/note/params.py +88 -0
  94. bpi/opus/__init__.py +5 -0
  95. bpi/opus/client.py +33 -0
  96. bpi/opus/models.py +29 -0
  97. bpi/opus/params.py +42 -0
  98. bpi/py.typed +0 -0
  99. bpi/search/__init__.py +58 -0
  100. bpi/search/client.py +156 -0
  101. bpi/search/models.py +316 -0
  102. bpi/search/params.py +160 -0
  103. bpi/session.py +42 -0
  104. bpi/sign/__init__.py +1 -0
  105. bpi/sign/wbi.py +107 -0
  106. bpi/user/__init__.py +3 -0
  107. bpi/user/actions.py +185 -0
  108. bpi/user/client.py +9 -0
  109. bpi/user/models.py +31 -0
  110. bpi/video/__init__.py +41 -0
  111. bpi/video/actions.py +277 -0
  112. bpi/video/client.py +64 -0
  113. bpi/video/models.py +135 -0
  114. bpi/video_ranking/__init__.py +24 -0
  115. bpi/video_ranking/client.py +132 -0
  116. bpi/video_ranking/models.py +101 -0
  117. bpi/video_ranking/params.py +108 -0
  118. bpi/vip/__init__.py +23 -0
  119. bpi/vip/client.py +50 -0
  120. bpi/vip/models.py +108 -0
  121. bpi/vip/params.py +13 -0
  122. bpi/wallet/__init__.py +4 -0
  123. bpi/wallet/client.py +56 -0
  124. bpi/wallet/models.py +18 -0
  125. bpi/web_widget/__init__.py +11 -0
  126. bpi/web_widget/client.py +44 -0
  127. bpi/web_widget/models.py +86 -0
  128. bpi/web_widget/params.py +9 -0
  129. bpi_py-0.3.0.dist-info/METADATA +290 -0
  130. bpi_py-0.3.0.dist-info/RECORD +132 -0
  131. bpi_py-0.3.0.dist-info/WHEEL +4 -0
  132. bpi_py-0.3.0.dist-info/licenses/LICENSE +21 -0
bpi/__init__.py ADDED
@@ -0,0 +1,29 @@
1
+ from .client import AsyncBpiClient
2
+ from .errors import (
3
+ ApiError,
4
+ AuthenticationError,
5
+ BpiError,
6
+ ClientClosedError,
7
+ HttpStatusError,
8
+ InvalidParameterError,
9
+ MissingDataError,
10
+ ResponseDecodeError,
11
+ TransportError,
12
+ UnsupportedResponseError,
13
+ )
14
+ from .session import Account
15
+
16
+ __all__ = [
17
+ "Account",
18
+ "ApiError",
19
+ "AsyncBpiClient",
20
+ "AuthenticationError",
21
+ "BpiError",
22
+ "ClientClosedError",
23
+ "HttpStatusError",
24
+ "InvalidParameterError",
25
+ "MissingDataError",
26
+ "ResponseDecodeError",
27
+ "TransportError",
28
+ "UnsupportedResponseError",
29
+ ]
bpi/_core/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Internal request and decoding implementation."""
bpi/_core/params.py ADDED
@@ -0,0 +1,21 @@
1
+ """Shared parameter validation for handwritten and generated read methods."""
2
+
3
+ import re
4
+
5
+ from bpi.errors import InvalidParameterError
6
+
7
+
8
+ def integer(value: int, name: str, minimum: int = 1) -> str:
9
+ if type(value) is not int or value < minimum:
10
+ raise InvalidParameterError(f"{name} must be an integer >= {minimum}")
11
+ return str(value)
12
+
13
+
14
+ def video_id(aid: int | None, bvid: str | None, *, play: bool = False) -> dict[str, str]:
15
+ if (aid is None) == (bvid is None):
16
+ raise InvalidParameterError("Provide exactly one of aid or bvid")
17
+ if aid is not None:
18
+ return {"avid" if play else "aid": integer(aid, "aid")}
19
+ if not isinstance(bvid, str) or not re.fullmatch(r"BV[0-9A-Za-z]{10}", bvid):
20
+ raise InvalidParameterError("bvid must be a 12-character BV identifier")
21
+ return {"bvid": bvid}
bpi/_core/response.py ADDED
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, TypeVar
5
+
6
+ from pydantic import BaseModel, ConfigDict, TypeAdapter, ValidationError
7
+
8
+ from bpi.errors import ApiError, AuthenticationError, MissingDataError, ResponseDecodeError
9
+
10
+ T = TypeVar("T")
11
+
12
+
13
+ class ResponseModel(BaseModel):
14
+ model_config = ConfigDict(
15
+ extra="ignore", strict=True, populate_by_name=True, hide_input_in_errors=True
16
+ )
17
+
18
+
19
+ def envelope(body: bytes, *, allow_anonymous_wbi: bool = False) -> dict[str, Any]:
20
+ try:
21
+ raw = json.loads(body)
22
+ except (ValueError, UnicodeError):
23
+ raise ResponseDecodeError(body) from None
24
+ if not isinstance(raw, dict):
25
+ raise ResponseDecodeError(body)
26
+ code = raw.get("code", raw.get("errno"))
27
+ if type(code) is not int:
28
+ raise ResponseDecodeError(body)
29
+ if code != 0 and not (allow_anonymous_wbi and code == -101):
30
+ message = raw.get("message", raw.get("msg", raw.get("showMsg", "")))
31
+ error_type = AuthenticationError if ApiError(code).requires_login() else ApiError
32
+ raise error_type(code, message if isinstance(message, str) else "")
33
+ return raw
34
+
35
+
36
+ def decode_payload(
37
+ body: bytes,
38
+ adapter: TypeAdapter[T],
39
+ *,
40
+ allow_anonymous_wbi: bool = False,
41
+ allow_missing: bool = False,
42
+ ) -> T:
43
+ raw = envelope(body, allow_anonymous_wbi=allow_anonymous_wbi)
44
+ value = raw.get("data", raw.get("result"))
45
+ if value is None and not allow_missing:
46
+ raise MissingDataError("Successful response has no payload")
47
+ try:
48
+ return adapter.validate_python(value)
49
+ except ValidationError:
50
+ # Suppress the default chain: ValidationError may contain account or response input.
51
+ raise ResponseDecodeError(body) from None
@@ -0,0 +1 @@
1
+ """Generated read methods and models; see migration/batch-3.json."""
@@ -0,0 +1,217 @@
1
+ # Generated by tools.migration.generate; edit migration/batch-*.json or the generator.
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING
5
+
6
+ from pydantic import ConfigDict, TypeAdapter
7
+
8
+ from bpi._core.params import integer
9
+ from bpi.errors import InvalidParameterError
10
+
11
+ from .audio_models import (
12
+ AudioCollection,
13
+ AudioCollectionsListData,
14
+ AudioHotMenuData,
15
+ AudioInfoData,
16
+ AudioMemberType,
17
+ AudioRankDetailData,
18
+ AudioRankMenuData,
19
+ AudioRankMusicListData,
20
+ AudioRankPeriodData,
21
+ AudioStatusNumberData,
22
+ AudioStreamUrlData,
23
+ AudioStreamUrlWebData,
24
+ AudioTag,
25
+ )
26
+
27
+ if TYPE_CHECKING:
28
+ from bpi.client import AsyncBpiClient
29
+
30
+ _INFO = TypeAdapter(AudioInfoData)
31
+ _TAGS = TypeAdapter(list[AudioTag])
32
+ _MEMBERS = TypeAdapter(list[AudioMemberType])
33
+ _LYRIC = TypeAdapter(str, config=ConfigDict(strict=True))
34
+ _STATUS_NUMBER = TypeAdapter(AudioStatusNumberData)
35
+ _COLLECTION_STATUS = TypeAdapter(bool, config=ConfigDict(strict=True))
36
+ _COIN_COUNT = TypeAdapter(int, config=ConfigDict(strict=True))
37
+ _STREAM_URL_WEB = TypeAdapter(AudioStreamUrlWebData)
38
+ _STREAM_URL = TypeAdapter(AudioStreamUrlData)
39
+ _COLLECTIONS_LIST = TypeAdapter(AudioCollectionsListData)
40
+ _COLLECTION_INFO: TypeAdapter[AudioCollection | None] = TypeAdapter(AudioCollection | None)
41
+ _HOT_MENU = TypeAdapter(AudioHotMenuData)
42
+ _RANK_MENU = TypeAdapter(AudioRankMenuData)
43
+ _RANK_PERIOD = TypeAdapter(AudioRankPeriodData)
44
+ _RANK_DETAIL = TypeAdapter(AudioRankDetailData)
45
+ _RANK_MUSIC_LIST = TypeAdapter(AudioRankMusicListData)
46
+
47
+
48
+ class AudioReadMethods:
49
+ def __init__(self, client: AsyncBpiClient) -> None:
50
+ self._client = client
51
+
52
+ async def info(self, *, sid: int) -> AudioInfoData:
53
+ """audio.info; public-read."""
54
+ params: dict[str, str] = {}
55
+ params["sid"] = integer(sid, "sid", 1)
56
+ return await self._client._get_payload(
57
+ "/audio/music-service-c/web/song/info", params, _INFO, host="www.bilibili.com"
58
+ )
59
+
60
+ async def tags(self, *, sid: int) -> list[AudioTag]:
61
+ """audio.tags; public-read."""
62
+ params: dict[str, str] = {}
63
+ params["sid"] = integer(sid, "sid", 1)
64
+ return await self._client._get_payload(
65
+ "/audio/music-service-c/web/tag/song", params, _TAGS, host="www.bilibili.com"
66
+ )
67
+
68
+ async def members(self, *, sid: int) -> list[AudioMemberType]:
69
+ """audio.members; public-read."""
70
+ params: dict[str, str] = {}
71
+ params["sid"] = integer(sid, "sid", 1)
72
+ return await self._client._get_payload(
73
+ "/audio/music-service-c/web/member/song", params, _MEMBERS, host="www.bilibili.com"
74
+ )
75
+
76
+ async def lyric(self, *, sid: int) -> str:
77
+ """audio.lyric; public-read."""
78
+ params: dict[str, str] = {}
79
+ params["sid"] = integer(sid, "sid", 1)
80
+ return await self._client._get_payload(
81
+ "/audio/music-service-c/web/song/lyric", params, _LYRIC, host="www.bilibili.com"
82
+ )
83
+
84
+ async def status_number(self, *, sid: int) -> AudioStatusNumberData:
85
+ """audio.status_number; public-read."""
86
+ params: dict[str, str] = {}
87
+ params["sid"] = integer(sid, "sid", 1)
88
+ return await self._client._get_payload(
89
+ "/audio/music-service-c/web/stat/song", params, _STATUS_NUMBER, host="www.bilibili.com"
90
+ )
91
+
92
+ async def collection_status(self, *, sid: int) -> bool:
93
+ """audio.collection_status; authenticated-read."""
94
+ params: dict[str, str] = {}
95
+ params["sid"] = integer(sid, "sid", 1)
96
+ return await self._client._get_payload(
97
+ "/audio/music-service-c/web/collections/songs-coll",
98
+ params,
99
+ _COLLECTION_STATUS,
100
+ host="www.bilibili.com",
101
+ )
102
+
103
+ async def coin_count(self, *, sid: int) -> int:
104
+ """audio.coin_count; authenticated-read."""
105
+ params: dict[str, str] = {}
106
+ params["sid"] = integer(sid, "sid", 1)
107
+ return await self._client._get_payload(
108
+ "/audio/music-service-c/web/coin/audio", params, _COIN_COUNT, host="www.bilibili.com"
109
+ )
110
+
111
+ async def stream_url_web(
112
+ self, *, sid: int, quality: int = 2, privilege: int = 2
113
+ ) -> AudioStreamUrlWebData:
114
+ """audio.stream_url_web; public-read."""
115
+ params: dict[str, str] = {}
116
+ params["sid"] = integer(sid, "sid", 1)
117
+ params["quality"] = integer(quality, "quality", 0)
118
+ if quality not in [0, 1, 2, 3]:
119
+ raise InvalidParameterError("Unsupported quality")
120
+ params["privilege"] = integer(privilege, "privilege", 1)
121
+ return await self._client._get_payload(
122
+ "/audio/music-service-c/web/url", params, _STREAM_URL_WEB, host="www.bilibili.com"
123
+ )
124
+
125
+ async def stream_url(
126
+ self,
127
+ *,
128
+ song_id: int,
129
+ quality: int,
130
+ privilege: int = 2,
131
+ mid: int = 2,
132
+ platform: str = "android",
133
+ ) -> AudioStreamUrlData:
134
+ """audio.stream_url; public-read."""
135
+ params: dict[str, str] = {}
136
+ params["songid"] = integer(song_id, "song_id", 1)
137
+ params["quality"] = integer(quality, "quality", 0)
138
+ if quality not in [0, 1, 2, 3]:
139
+ raise InvalidParameterError("Unsupported quality")
140
+ params["privilege"] = integer(privilege, "privilege", 1)
141
+ params["mid"] = integer(mid, "mid", 1)
142
+ if not isinstance(platform, str):
143
+ raise InvalidParameterError("platform must be a string")
144
+ params["platform"] = platform
145
+ params["platform"] = platform.strip()
146
+ if not params["platform"]:
147
+ raise InvalidParameterError("platform cannot be blank")
148
+ return await self._client._get_payload("/audio/music-service-c/url", params, _STREAM_URL)
149
+
150
+ async def collections_list(self, *, page: int, page_size: int) -> AudioCollectionsListData:
151
+ """audio.collections_list; authenticated-read."""
152
+ params: dict[str, str] = {}
153
+ params["pn"] = integer(page, "page", 1)
154
+ params["ps"] = integer(page_size, "page_size", 1)
155
+ return await self._client._get_payload(
156
+ "/audio/music-service-c/web/collections/list",
157
+ params,
158
+ _COLLECTIONS_LIST,
159
+ host="www.bilibili.com",
160
+ )
161
+
162
+ async def collection_info(self, *, sid: int) -> AudioCollection | None:
163
+ """audio.collection_info; authenticated-read."""
164
+ params: dict[str, str] = {}
165
+ params["sid"] = integer(sid, "sid", 1)
166
+ return await self._client._get_payload(
167
+ "/audio/music-service-c/web/collections/info",
168
+ params,
169
+ _COLLECTION_INFO,
170
+ host="www.bilibili.com",
171
+ optional=True,
172
+ )
173
+
174
+ async def hot_menu(self, *, page: int, page_size: int) -> AudioHotMenuData:
175
+ """audio.hot_menu; public-read."""
176
+ params: dict[str, str] = {}
177
+ params["pn"] = integer(page, "page", 1)
178
+ params["ps"] = integer(page_size, "page_size", 1)
179
+ return await self._client._get_payload(
180
+ "/audio/music-service-c/web/menu/hit", params, _HOT_MENU, host="www.bilibili.com"
181
+ )
182
+
183
+ async def rank_menu(self, *, page: int, page_size: int) -> AudioRankMenuData:
184
+ """audio.rank_menu; public-read."""
185
+ params: dict[str, str] = {}
186
+ params["pn"] = integer(page, "page", 1)
187
+ params["ps"] = integer(page_size, "page_size", 1)
188
+ return await self._client._get_payload(
189
+ "/audio/music-service-c/web/menu/rank", params, _RANK_MENU, host="www.bilibili.com"
190
+ )
191
+
192
+ async def rank_period(self, *, list_type: int) -> AudioRankPeriodData:
193
+ """audio.rank_period; public-read."""
194
+ params: dict[str, str] = {}
195
+ params["list_type"] = integer(list_type, "list_type", 1)
196
+ params["csrf"] = self._client._csrf(host="api.bilibili.com", optional=True)
197
+ return await self._client._get_payload(
198
+ "/x/copyright-music-publicity/toplist/all_period", params, _RANK_PERIOD
199
+ )
200
+
201
+ async def rank_detail(self, *, list_id: int) -> AudioRankDetailData:
202
+ """audio.rank_detail; public-read."""
203
+ params: dict[str, str] = {}
204
+ params["list_id"] = integer(list_id, "list_id", 1)
205
+ params["csrf"] = self._client._csrf(host="api.bilibili.com", optional=True)
206
+ return await self._client._get_payload(
207
+ "/x/copyright-music-publicity/toplist/detail", params, _RANK_DETAIL
208
+ )
209
+
210
+ async def rank_music_list(self, *, list_id: int) -> AudioRankMusicListData:
211
+ """audio.rank_music_list; public-read."""
212
+ params: dict[str, str] = {}
213
+ params["list_id"] = integer(list_id, "list_id", 1)
214
+ params["csrf"] = self._client._csrf(host="api.bilibili.com", optional=True)
215
+ return await self._client._get_payload(
216
+ "/x/copyright-music-publicity/toplist/music_list", params, _RANK_MUSIC_LIST
217
+ )
@@ -0,0 +1,320 @@
1
+ # Generated by tools.migration.generate; edit migration/batch-*.json or the generator.
2
+ from __future__ import annotations
3
+
4
+ import builtins
5
+
6
+ from pydantic import Field, JsonValue
7
+
8
+ from bpi._core.response import ResponseModel
9
+
10
+
11
+ class AudioStatistic(ResponseModel):
12
+ """Source: src/audio/info.rs:66:AudioStatistic."""
13
+
14
+ sid: int
15
+ play: int
16
+ collect: int
17
+ comment: int
18
+ share: int
19
+
20
+
21
+ class AudioVipInfo(ResponseModel):
22
+ """Source: src/audio/info.rs:81:AudioVipInfo."""
23
+
24
+ type: int
25
+ status: int
26
+ due_date: int
27
+ vip_pay_type: int
28
+
29
+
30
+ class AudioInfoData(ResponseModel):
31
+ """Source: src/audio/info.rs:9:AudioInfoData."""
32
+
33
+ id: int
34
+ uid: int
35
+ uname: str
36
+ author: str
37
+ title: str
38
+ cover: str
39
+ intro: str
40
+ lyric: str
41
+ crtype: int
42
+ duration: int
43
+ passtime: int
44
+ curtime: int
45
+ aid: int
46
+ bvid: str
47
+ cid: int
48
+ msid: int
49
+ attr: int
50
+ limit: int
51
+ activity_id: int = Field(alias="activityId")
52
+ limitdesc: str
53
+ ctime: JsonValue | None = Field(default=None)
54
+ statistic: AudioStatistic
55
+ vip_info: AudioVipInfo = Field(alias="vipInfo")
56
+ collect_ids: list[int] = Field(alias="collectIds")
57
+ coin_num: int
58
+
59
+
60
+ class AudioTag(ResponseModel):
61
+ """Source: src/audio/info.rs:94:AudioTag."""
62
+
63
+ type: str
64
+ subtype: int
65
+ key: int
66
+ info: str
67
+
68
+
69
+ class AudioMember(ResponseModel):
70
+ """Source: src/audio/info.rs:116:AudioMember."""
71
+
72
+ mid: int
73
+ name: str
74
+ member_id: int
75
+
76
+
77
+ class AudioMemberType(ResponseModel):
78
+ """Source: src/audio/info.rs:107:AudioMemberType."""
79
+
80
+ list: builtins.list[AudioMember]
81
+ type: int
82
+
83
+
84
+ class AudioStatusNumberData(ResponseModel):
85
+ """Source: src/audio/status_number.rs:7:AudioStatusNumberData."""
86
+
87
+ sid: int
88
+ play: int
89
+ collect: int
90
+ comment: int
91
+ share: int
92
+
93
+
94
+ class AudioStreamUrlWebData(ResponseModel):
95
+ """Source: src/audio/musicstream_url.rs:26:AudioStreamUrlWebData."""
96
+
97
+ sid: int
98
+ type: int
99
+ info: str
100
+ timeout: int
101
+ size: int
102
+ cdns: list[str]
103
+ qualities: JsonValue | None = Field(default=None)
104
+ title: str
105
+ cover: str
106
+
107
+
108
+ class AudioQualityInfo(ResponseModel):
109
+ """Source: src/audio/musicstream_url.rs:52:AudioQualityInfo."""
110
+
111
+ type: int
112
+ desc: str
113
+ size: int
114
+ bps: str
115
+ tag: str
116
+ require: int
117
+ requiredesc: str
118
+
119
+
120
+ class AudioStreamUrlData(ResponseModel):
121
+ """Source: src/audio/musicstream_url.rs:39:AudioStreamUrlData."""
122
+
123
+ sid: int
124
+ type: int
125
+ info: str
126
+ timeout: int
127
+ size: int
128
+ cdns: list[str]
129
+ qualities: list[AudioQualityInfo]
130
+ title: str
131
+ cover: str
132
+
133
+
134
+ class AudioCollectionStatistic(ResponseModel):
135
+ """Source: src/audio/music_list.rs:42:AudioCollectionStatistic."""
136
+
137
+ sid: int
138
+ play: int
139
+ collect: int
140
+ comment: int | None = Field(default=None)
141
+ share: int
142
+
143
+
144
+ class AudioCollection(ResponseModel):
145
+ """Source: src/audio/music_list.rs:24:AudioCollection."""
146
+
147
+ id: int
148
+ uid: int
149
+ uname: str
150
+ title: str
151
+ type: int
152
+ published: int
153
+ cover: str
154
+ ctime: int
155
+ song: int
156
+ desc: str
157
+ sids: list[int]
158
+ menu_id: int = Field(alias="menuId")
159
+ statistic: AudioCollectionStatistic
160
+
161
+
162
+ class AudioCollectionsListData(ResponseModel):
163
+ """Source: src/audio/music_list.rs:7:AudioCollectionsListData."""
164
+
165
+ cur_page: int = Field(alias="curPage")
166
+ page_count: int = Field(alias="pageCount")
167
+ total_size: int = Field(alias="totalSize")
168
+ page_size: int = Field(alias="pageSize")
169
+ data: list[AudioCollection]
170
+
171
+
172
+ class AudioHotMenuStatistic(ResponseModel):
173
+ """Source: src/audio/music_list.rs:104:AudioHotMenuStatistic."""
174
+
175
+ sid: int
176
+ play: int
177
+ collect: int
178
+ comment: int
179
+ share: int
180
+
181
+
182
+ class AudioHotMenu(ResponseModel):
183
+ """Source: src/audio/music_list.rs:68:AudioHotMenu."""
184
+
185
+ menu_id: int = Field(alias="menuId")
186
+ uid: int
187
+ uname: str
188
+ title: str
189
+ cover: str
190
+ intro: str
191
+ type: int
192
+ off: int
193
+ ctime: int
194
+ curtime: int
195
+ statistic: AudioHotMenuStatistic
196
+ snum: int
197
+ attr: int
198
+ is_default: int = Field(alias="isDefault")
199
+ collection_id: int = Field(alias="collectionId")
200
+
201
+
202
+ class AudioHotMenuData(ResponseModel):
203
+ """Source: src/audio/music_list.rs:51:AudioHotMenuData."""
204
+
205
+ cur_page: int = Field(alias="curPage")
206
+ page_count: int = Field(alias="pageCount")
207
+ total_size: int = Field(alias="totalSize")
208
+ page_size: int = Field(alias="pageSize")
209
+ data: list[AudioHotMenu]
210
+
211
+
212
+ class AudioRankMenuStatistic(ResponseModel):
213
+ """Source: src/audio/music_list.rs:168:AudioRankMenuStatistic."""
214
+
215
+ sid: int
216
+ play: int
217
+ collect: int
218
+ comment: int
219
+ share: int
220
+
221
+
222
+ class AudioRankItem(ResponseModel):
223
+ """Source: src/audio/music_list.rs:177:AudioRankItem."""
224
+
225
+ id: int
226
+ title: str
227
+ duration: int
228
+
229
+
230
+ class AudioRankMenu(ResponseModel):
231
+ """Source: src/audio/music_list.rs:130:AudioRankMenu."""
232
+
233
+ menu_id: int = Field(alias="menuId")
234
+ uid: int
235
+ uname: str
236
+ title: str
237
+ cover: str
238
+ intro: str
239
+ type: int
240
+ off: int
241
+ ctime: int
242
+ curtime: int
243
+ statistic: AudioRankMenuStatistic
244
+ snum: int
245
+ attr: int
246
+ is_default: int = Field(alias="isDefault")
247
+ collection_id: int = Field(alias="collectionId")
248
+ audios: list[AudioRankItem]
249
+
250
+
251
+ class AudioRankMenuData(ResponseModel):
252
+ """Source: src/audio/music_list.rs:113:AudioRankMenuData."""
253
+
254
+ cur_page: int = Field(alias="curPage")
255
+ page_count: int = Field(alias="pageCount")
256
+ total_size: int = Field(alias="totalSize")
257
+ page_size: int = Field(alias="pageSize")
258
+ data: list[AudioRankMenu]
259
+
260
+
261
+ class AudioRankPeriod(ResponseModel):
262
+ """Source: src/audio/rank.rs:20:AudioRankPeriod."""
263
+
264
+ id: int = Field(alias="ID")
265
+ priod: int
266
+ publish_time: int
267
+
268
+
269
+ class AudioRankPeriodData(ResponseModel):
270
+ """Source: src/audio/rank.rs:15:AudioRankPeriodData."""
271
+
272
+ list: dict[str, list[AudioRankPeriod]]
273
+
274
+
275
+ class AudioRankDetailData(ResponseModel):
276
+ """Source: src/audio/rank.rs:28:AudioRankDetailData."""
277
+
278
+ listen_fid: int
279
+ all_fid: int
280
+ fav_mid: int
281
+ cover_url: str
282
+ is_subscribe: bool
283
+ listen_count: int
284
+
285
+
286
+ class AudioRankMusicItem(ResponseModel):
287
+ """Source: src/audio/rank.rs:43:AudioRankMusicItem."""
288
+
289
+ music_id: str
290
+ music_title: str
291
+ singer: str
292
+ album: str
293
+ mv_aid: int
294
+ mv_bvid: str
295
+ mv_cover: str
296
+ heat: int
297
+ rank: int
298
+ can_listen: bool
299
+ recommendation: str
300
+ creation_aid: int
301
+ creation_bvid: str
302
+ creation_cover: str
303
+ creation_title: str
304
+ creation_up: int
305
+ creation_nickname: str
306
+ creation_duration: int
307
+ creation_play: int
308
+ creation_reason: str
309
+ achievements: list[str]
310
+ material_id: int
311
+ material_use_num: int
312
+ material_duration: int
313
+ material_show: int
314
+ song_type: int
315
+
316
+
317
+ class AudioRankMusicListData(ResponseModel):
318
+ """Source: src/audio/rank.rs:38:AudioRankMusicListData."""
319
+
320
+ list: builtins.list[AudioRankMusicItem]