chzzk-python 0.1.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.
- chzzk/__init__.py +175 -0
- chzzk/_version.py +34 -0
- chzzk/api/__init__.py +29 -0
- chzzk/api/base.py +147 -0
- chzzk/api/category.py +65 -0
- chzzk/api/channel.py +218 -0
- chzzk/api/chat.py +239 -0
- chzzk/api/live.py +212 -0
- chzzk/api/restriction.py +147 -0
- chzzk/api/session.py +389 -0
- chzzk/api/user.py +47 -0
- chzzk/auth/__init__.py +34 -0
- chzzk/auth/models.py +115 -0
- chzzk/auth/oauth.py +452 -0
- chzzk/auth/token.py +119 -0
- chzzk/client.py +515 -0
- chzzk/exceptions/__init__.py +37 -0
- chzzk/exceptions/errors.py +130 -0
- chzzk/http/__init__.py +68 -0
- chzzk/http/client.py +310 -0
- chzzk/http/endpoints.py +52 -0
- chzzk/models/__init__.py +86 -0
- chzzk/models/category.py +18 -0
- chzzk/models/channel.py +69 -0
- chzzk/models/chat.py +63 -0
- chzzk/models/common.py +23 -0
- chzzk/models/live.py +78 -0
- chzzk/models/restriction.py +18 -0
- chzzk/models/session.py +161 -0
- chzzk/models/user.py +14 -0
- chzzk/py.typed +0 -0
- chzzk/realtime/__init__.py +8 -0
- chzzk/realtime/client.py +635 -0
- chzzk_python-0.1.0.dist-info/METADATA +314 -0
- chzzk_python-0.1.0.dist-info/RECORD +37 -0
- chzzk_python-0.1.0.dist-info/WHEEL +4 -0
- chzzk_python-0.1.0.dist-info/licenses/LICENSE +21 -0
chzzk/http/__init__.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""HTTP client and endpoint utilities for Chzzk SDK."""
|
|
2
|
+
|
|
3
|
+
from chzzk.http.client import AsyncHTTPClient, HTTPClient
|
|
4
|
+
from chzzk.http.endpoints import (
|
|
5
|
+
AUTH_INTERLOCK_URL,
|
|
6
|
+
AUTH_REVOKE_URL,
|
|
7
|
+
AUTH_TOKEN_URL,
|
|
8
|
+
CATEGORIES_SEARCH_URL,
|
|
9
|
+
CHANNEL_FOLLOWERS_URL,
|
|
10
|
+
CHANNEL_ROLES_URL,
|
|
11
|
+
CHANNEL_SUBSCRIBERS_URL,
|
|
12
|
+
CHANNELS_URL,
|
|
13
|
+
CHAT_NOTICE_URL,
|
|
14
|
+
CHAT_SEND_URL,
|
|
15
|
+
CHAT_SETTINGS_URL,
|
|
16
|
+
CHZZK_BASE_URL,
|
|
17
|
+
LIVE_SETTING_URL,
|
|
18
|
+
LIVES_URL,
|
|
19
|
+
OPEN_API_PREFIX,
|
|
20
|
+
OPENAPI_BASE_URL,
|
|
21
|
+
RESTRICT_CHANNELS_URL,
|
|
22
|
+
SESSIONS_AUTH_CLIENT_URL,
|
|
23
|
+
SESSIONS_AUTH_URL,
|
|
24
|
+
SESSIONS_CLIENT_URL,
|
|
25
|
+
SESSIONS_SUBSCRIBE_CHAT_URL,
|
|
26
|
+
SESSIONS_SUBSCRIBE_DONATION_URL,
|
|
27
|
+
SESSIONS_SUBSCRIBE_SUBSCRIPTION_URL,
|
|
28
|
+
SESSIONS_UNSUBSCRIBE_CHAT_URL,
|
|
29
|
+
SESSIONS_UNSUBSCRIBE_DONATION_URL,
|
|
30
|
+
SESSIONS_UNSUBSCRIBE_SUBSCRIPTION_URL,
|
|
31
|
+
SESSIONS_URL,
|
|
32
|
+
STREAM_KEY_URL,
|
|
33
|
+
USER_ME_URL,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"AUTH_INTERLOCK_URL",
|
|
38
|
+
"AUTH_REVOKE_URL",
|
|
39
|
+
"AUTH_TOKEN_URL",
|
|
40
|
+
"AsyncHTTPClient",
|
|
41
|
+
"CATEGORIES_SEARCH_URL",
|
|
42
|
+
"CHANNELS_URL",
|
|
43
|
+
"CHANNEL_FOLLOWERS_URL",
|
|
44
|
+
"CHANNEL_ROLES_URL",
|
|
45
|
+
"CHANNEL_SUBSCRIBERS_URL",
|
|
46
|
+
"CHAT_NOTICE_URL",
|
|
47
|
+
"CHAT_SEND_URL",
|
|
48
|
+
"CHAT_SETTINGS_URL",
|
|
49
|
+
"CHZZK_BASE_URL",
|
|
50
|
+
"HTTPClient",
|
|
51
|
+
"LIVES_URL",
|
|
52
|
+
"LIVE_SETTING_URL",
|
|
53
|
+
"OPEN_API_PREFIX",
|
|
54
|
+
"OPENAPI_BASE_URL",
|
|
55
|
+
"RESTRICT_CHANNELS_URL",
|
|
56
|
+
"SESSIONS_AUTH_CLIENT_URL",
|
|
57
|
+
"SESSIONS_AUTH_URL",
|
|
58
|
+
"SESSIONS_CLIENT_URL",
|
|
59
|
+
"SESSIONS_SUBSCRIBE_CHAT_URL",
|
|
60
|
+
"SESSIONS_SUBSCRIBE_DONATION_URL",
|
|
61
|
+
"SESSIONS_SUBSCRIBE_SUBSCRIPTION_URL",
|
|
62
|
+
"SESSIONS_UNSUBSCRIBE_CHAT_URL",
|
|
63
|
+
"SESSIONS_UNSUBSCRIBE_DONATION_URL",
|
|
64
|
+
"SESSIONS_UNSUBSCRIBE_SUBSCRIPTION_URL",
|
|
65
|
+
"SESSIONS_URL",
|
|
66
|
+
"STREAM_KEY_URL",
|
|
67
|
+
"USER_ME_URL",
|
|
68
|
+
]
|
chzzk/http/client.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""HTTP client wrapper for Chzzk API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from chzzk.exceptions import (
|
|
10
|
+
ChzzkAPIError,
|
|
11
|
+
ForbiddenError,
|
|
12
|
+
InvalidClientError,
|
|
13
|
+
InvalidTokenError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
RateLimitError,
|
|
16
|
+
ServerError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Mapping
|
|
21
|
+
|
|
22
|
+
DEFAULT_TIMEOUT = 30.0
|
|
23
|
+
USER_AGENT = "chzzk-python/0.1.0"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _extract_content(data: Any) -> Any:
|
|
27
|
+
"""Extract content from Chzzk API response wrapper.
|
|
28
|
+
|
|
29
|
+
Chzzk API wraps responses in { code, message, content }.
|
|
30
|
+
This function extracts the actual content.
|
|
31
|
+
"""
|
|
32
|
+
if isinstance(data, dict) and "content" in data:
|
|
33
|
+
return data["content"]
|
|
34
|
+
return data
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _handle_error_response(response: httpx.Response) -> None:
|
|
38
|
+
"""Raise appropriate exception based on response status and content."""
|
|
39
|
+
status_code = response.status_code
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
data = response.json()
|
|
43
|
+
error_code = data.get("code") or data.get("error")
|
|
44
|
+
message = data.get("message") or data.get("error_description") or str(data)
|
|
45
|
+
except Exception:
|
|
46
|
+
error_code = None
|
|
47
|
+
message = response.text or f"HTTP {status_code}"
|
|
48
|
+
|
|
49
|
+
if status_code == 401:
|
|
50
|
+
if error_code == "INVALID_CLIENT":
|
|
51
|
+
raise InvalidClientError(message)
|
|
52
|
+
if error_code == "INVALID_TOKEN":
|
|
53
|
+
raise InvalidTokenError(message)
|
|
54
|
+
raise ChzzkAPIError(message, status_code=401, error_code=error_code)
|
|
55
|
+
|
|
56
|
+
if status_code == 403:
|
|
57
|
+
raise ForbiddenError(message)
|
|
58
|
+
|
|
59
|
+
if status_code == 404:
|
|
60
|
+
raise NotFoundError(message)
|
|
61
|
+
|
|
62
|
+
if status_code == 429:
|
|
63
|
+
raise RateLimitError(message)
|
|
64
|
+
|
|
65
|
+
if status_code >= 500:
|
|
66
|
+
raise ServerError(message)
|
|
67
|
+
|
|
68
|
+
raise ChzzkAPIError(message, status_code=status_code, error_code=error_code)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class HTTPClient:
|
|
72
|
+
"""Synchronous HTTP client for Chzzk API."""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
*,
|
|
77
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
78
|
+
headers: Mapping[str, str] | None = None,
|
|
79
|
+
) -> None:
|
|
80
|
+
default_headers = {
|
|
81
|
+
"User-Agent": USER_AGENT,
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
"Accept": "application/json",
|
|
84
|
+
}
|
|
85
|
+
if headers:
|
|
86
|
+
default_headers.update(headers)
|
|
87
|
+
|
|
88
|
+
self._client = httpx.Client(
|
|
89
|
+
timeout=timeout,
|
|
90
|
+
headers=default_headers,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def post(
|
|
94
|
+
self,
|
|
95
|
+
url: str,
|
|
96
|
+
*,
|
|
97
|
+
params: dict[str, Any] | None = None,
|
|
98
|
+
json: dict[str, Any] | None = None,
|
|
99
|
+
headers: Mapping[str, str] | None = None,
|
|
100
|
+
) -> dict[str, Any]:
|
|
101
|
+
"""Send a POST request and return JSON response."""
|
|
102
|
+
response = self._client.post(url, params=params, json=json, headers=headers)
|
|
103
|
+
|
|
104
|
+
if response.status_code >= 400:
|
|
105
|
+
_handle_error_response(response)
|
|
106
|
+
|
|
107
|
+
if response.status_code == 204 or not response.content:
|
|
108
|
+
return {}
|
|
109
|
+
|
|
110
|
+
return _extract_content(response.json())
|
|
111
|
+
|
|
112
|
+
def get(
|
|
113
|
+
self,
|
|
114
|
+
url: str,
|
|
115
|
+
*,
|
|
116
|
+
params: dict[str, Any] | None = None,
|
|
117
|
+
headers: Mapping[str, str] | None = None,
|
|
118
|
+
) -> dict[str, Any]:
|
|
119
|
+
"""Send a GET request and return JSON response."""
|
|
120
|
+
response = self._client.get(url, params=params, headers=headers)
|
|
121
|
+
|
|
122
|
+
if response.status_code >= 400:
|
|
123
|
+
_handle_error_response(response)
|
|
124
|
+
|
|
125
|
+
return _extract_content(response.json())
|
|
126
|
+
|
|
127
|
+
def put(
|
|
128
|
+
self,
|
|
129
|
+
url: str,
|
|
130
|
+
*,
|
|
131
|
+
json: dict[str, Any] | None = None,
|
|
132
|
+
headers: Mapping[str, str] | None = None,
|
|
133
|
+
) -> dict[str, Any]:
|
|
134
|
+
"""Send a PUT request and return JSON response."""
|
|
135
|
+
response = self._client.put(url, json=json, headers=headers)
|
|
136
|
+
|
|
137
|
+
if response.status_code >= 400:
|
|
138
|
+
_handle_error_response(response)
|
|
139
|
+
|
|
140
|
+
if response.status_code == 204 or not response.content:
|
|
141
|
+
return {}
|
|
142
|
+
|
|
143
|
+
return _extract_content(response.json())
|
|
144
|
+
|
|
145
|
+
def patch(
|
|
146
|
+
self,
|
|
147
|
+
url: str,
|
|
148
|
+
*,
|
|
149
|
+
json: dict[str, Any] | None = None,
|
|
150
|
+
headers: Mapping[str, str] | None = None,
|
|
151
|
+
) -> dict[str, Any]:
|
|
152
|
+
"""Send a PATCH request and return JSON response."""
|
|
153
|
+
response = self._client.patch(url, json=json, headers=headers)
|
|
154
|
+
|
|
155
|
+
if response.status_code >= 400:
|
|
156
|
+
_handle_error_response(response)
|
|
157
|
+
|
|
158
|
+
if response.status_code == 204 or not response.content:
|
|
159
|
+
return {}
|
|
160
|
+
|
|
161
|
+
return _extract_content(response.json())
|
|
162
|
+
|
|
163
|
+
def delete(
|
|
164
|
+
self,
|
|
165
|
+
url: str,
|
|
166
|
+
*,
|
|
167
|
+
json: dict[str, Any] | None = None,
|
|
168
|
+
headers: Mapping[str, str] | None = None,
|
|
169
|
+
) -> dict[str, Any]:
|
|
170
|
+
"""Send a DELETE request and return JSON response."""
|
|
171
|
+
response = self._client.request("DELETE", url, json=json, headers=headers)
|
|
172
|
+
|
|
173
|
+
if response.status_code >= 400:
|
|
174
|
+
_handle_error_response(response)
|
|
175
|
+
|
|
176
|
+
if response.status_code == 204 or not response.content:
|
|
177
|
+
return {}
|
|
178
|
+
|
|
179
|
+
return _extract_content(response.json())
|
|
180
|
+
|
|
181
|
+
def close(self) -> None:
|
|
182
|
+
"""Close the HTTP client."""
|
|
183
|
+
self._client.close()
|
|
184
|
+
|
|
185
|
+
def __enter__(self) -> HTTPClient:
|
|
186
|
+
return self
|
|
187
|
+
|
|
188
|
+
def __exit__(self, *args: object) -> None:
|
|
189
|
+
self.close()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class AsyncHTTPClient:
|
|
193
|
+
"""Asynchronous HTTP client for Chzzk API."""
|
|
194
|
+
|
|
195
|
+
def __init__(
|
|
196
|
+
self,
|
|
197
|
+
*,
|
|
198
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
199
|
+
headers: Mapping[str, str] | None = None,
|
|
200
|
+
) -> None:
|
|
201
|
+
default_headers = {
|
|
202
|
+
"User-Agent": USER_AGENT,
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
"Accept": "application/json",
|
|
205
|
+
}
|
|
206
|
+
if headers:
|
|
207
|
+
default_headers.update(headers)
|
|
208
|
+
|
|
209
|
+
self._client = httpx.AsyncClient(
|
|
210
|
+
timeout=timeout,
|
|
211
|
+
headers=default_headers,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
async def post(
|
|
215
|
+
self,
|
|
216
|
+
url: str,
|
|
217
|
+
*,
|
|
218
|
+
params: dict[str, Any] | None = None,
|
|
219
|
+
json: dict[str, Any] | None = None,
|
|
220
|
+
headers: Mapping[str, str] | None = None,
|
|
221
|
+
) -> dict[str, Any]:
|
|
222
|
+
"""Send a POST request and return JSON response."""
|
|
223
|
+
response = await self._client.post(url, params=params, json=json, headers=headers)
|
|
224
|
+
|
|
225
|
+
if response.status_code >= 400:
|
|
226
|
+
_handle_error_response(response)
|
|
227
|
+
|
|
228
|
+
if response.status_code == 204 or not response.content:
|
|
229
|
+
return {}
|
|
230
|
+
|
|
231
|
+
return _extract_content(response.json())
|
|
232
|
+
|
|
233
|
+
async def get(
|
|
234
|
+
self,
|
|
235
|
+
url: str,
|
|
236
|
+
*,
|
|
237
|
+
params: dict[str, Any] | None = None,
|
|
238
|
+
headers: Mapping[str, str] | None = None,
|
|
239
|
+
) -> dict[str, Any]:
|
|
240
|
+
"""Send a GET request and return JSON response."""
|
|
241
|
+
response = await self._client.get(url, params=params, headers=headers)
|
|
242
|
+
|
|
243
|
+
if response.status_code >= 400:
|
|
244
|
+
_handle_error_response(response)
|
|
245
|
+
|
|
246
|
+
return _extract_content(response.json())
|
|
247
|
+
|
|
248
|
+
async def put(
|
|
249
|
+
self,
|
|
250
|
+
url: str,
|
|
251
|
+
*,
|
|
252
|
+
json: dict[str, Any] | None = None,
|
|
253
|
+
headers: Mapping[str, str] | None = None,
|
|
254
|
+
) -> dict[str, Any]:
|
|
255
|
+
"""Send a PUT request and return JSON response."""
|
|
256
|
+
response = await self._client.put(url, json=json, headers=headers)
|
|
257
|
+
|
|
258
|
+
if response.status_code >= 400:
|
|
259
|
+
_handle_error_response(response)
|
|
260
|
+
|
|
261
|
+
if response.status_code == 204 or not response.content:
|
|
262
|
+
return {}
|
|
263
|
+
|
|
264
|
+
return _extract_content(response.json())
|
|
265
|
+
|
|
266
|
+
async def patch(
|
|
267
|
+
self,
|
|
268
|
+
url: str,
|
|
269
|
+
*,
|
|
270
|
+
json: dict[str, Any] | None = None,
|
|
271
|
+
headers: Mapping[str, str] | None = None,
|
|
272
|
+
) -> dict[str, Any]:
|
|
273
|
+
"""Send a PATCH request and return JSON response."""
|
|
274
|
+
response = await self._client.patch(url, json=json, headers=headers)
|
|
275
|
+
|
|
276
|
+
if response.status_code >= 400:
|
|
277
|
+
_handle_error_response(response)
|
|
278
|
+
|
|
279
|
+
if response.status_code == 204 or not response.content:
|
|
280
|
+
return {}
|
|
281
|
+
|
|
282
|
+
return _extract_content(response.json())
|
|
283
|
+
|
|
284
|
+
async def delete(
|
|
285
|
+
self,
|
|
286
|
+
url: str,
|
|
287
|
+
*,
|
|
288
|
+
json: dict[str, Any] | None = None,
|
|
289
|
+
headers: Mapping[str, str] | None = None,
|
|
290
|
+
) -> dict[str, Any]:
|
|
291
|
+
"""Send a DELETE request and return JSON response."""
|
|
292
|
+
response = await self._client.request("DELETE", url, json=json, headers=headers)
|
|
293
|
+
|
|
294
|
+
if response.status_code >= 400:
|
|
295
|
+
_handle_error_response(response)
|
|
296
|
+
|
|
297
|
+
if response.status_code == 204 or not response.content:
|
|
298
|
+
return {}
|
|
299
|
+
|
|
300
|
+
return _extract_content(response.json())
|
|
301
|
+
|
|
302
|
+
async def close(self) -> None:
|
|
303
|
+
"""Close the HTTP client."""
|
|
304
|
+
await self._client.aclose()
|
|
305
|
+
|
|
306
|
+
async def __aenter__(self) -> AsyncHTTPClient:
|
|
307
|
+
return self
|
|
308
|
+
|
|
309
|
+
async def __aexit__(self, *args: object) -> None:
|
|
310
|
+
await self.close()
|
chzzk/http/endpoints.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""API endpoints and base URLs for Chzzk API."""
|
|
2
|
+
|
|
3
|
+
# Base URLs
|
|
4
|
+
CHZZK_BASE_URL = "https://chzzk.naver.com"
|
|
5
|
+
OPENAPI_BASE_URL = "https://openapi.chzzk.naver.com"
|
|
6
|
+
|
|
7
|
+
# Authorization endpoints
|
|
8
|
+
AUTH_INTERLOCK_URL = f"{CHZZK_BASE_URL}/account-interlock"
|
|
9
|
+
AUTH_TOKEN_URL = f"{OPENAPI_BASE_URL}/auth/v1/token"
|
|
10
|
+
AUTH_REVOKE_URL = f"{OPENAPI_BASE_URL}/auth/v1/token/revoke"
|
|
11
|
+
|
|
12
|
+
# Open API prefix
|
|
13
|
+
OPEN_API_PREFIX = f"{OPENAPI_BASE_URL}/open/v1"
|
|
14
|
+
|
|
15
|
+
# User endpoints
|
|
16
|
+
USER_ME_URL = f"{OPEN_API_PREFIX}/users/me"
|
|
17
|
+
|
|
18
|
+
# Channel endpoints
|
|
19
|
+
CHANNELS_URL = f"{OPEN_API_PREFIX}/channels"
|
|
20
|
+
CHANNEL_ROLES_URL = f"{OPEN_API_PREFIX}/channels/streaming-roles"
|
|
21
|
+
CHANNEL_FOLLOWERS_URL = f"{OPEN_API_PREFIX}/channels/followers"
|
|
22
|
+
CHANNEL_SUBSCRIBERS_URL = f"{OPEN_API_PREFIX}/channels/subscribers"
|
|
23
|
+
|
|
24
|
+
# Category endpoints
|
|
25
|
+
CATEGORIES_SEARCH_URL = f"{OPEN_API_PREFIX}/categories/search"
|
|
26
|
+
|
|
27
|
+
# Live endpoints
|
|
28
|
+
LIVES_URL = f"{OPEN_API_PREFIX}/lives"
|
|
29
|
+
STREAM_KEY_URL = f"{OPEN_API_PREFIX}/streams/key"
|
|
30
|
+
LIVE_SETTING_URL = f"{OPEN_API_PREFIX}/lives/setting"
|
|
31
|
+
|
|
32
|
+
# Chat endpoints
|
|
33
|
+
CHAT_SEND_URL = f"{OPEN_API_PREFIX}/chats/send"
|
|
34
|
+
CHAT_NOTICE_URL = f"{OPEN_API_PREFIX}/chats/notice"
|
|
35
|
+
CHAT_SETTINGS_URL = f"{OPEN_API_PREFIX}/chats/settings"
|
|
36
|
+
|
|
37
|
+
# Restriction endpoints
|
|
38
|
+
RESTRICT_CHANNELS_URL = f"{OPEN_API_PREFIX}/restrict-channels"
|
|
39
|
+
|
|
40
|
+
# Session endpoints
|
|
41
|
+
SESSIONS_AUTH_URL = f"{OPEN_API_PREFIX}/sessions/auth"
|
|
42
|
+
SESSIONS_AUTH_CLIENT_URL = f"{OPEN_API_PREFIX}/sessions/auth/client"
|
|
43
|
+
SESSIONS_URL = f"{OPEN_API_PREFIX}/sessions"
|
|
44
|
+
SESSIONS_CLIENT_URL = f"{OPEN_API_PREFIX}/sessions/client"
|
|
45
|
+
SESSIONS_SUBSCRIBE_CHAT_URL = f"{OPEN_API_PREFIX}/sessions/events/subscribe/chat"
|
|
46
|
+
SESSIONS_SUBSCRIBE_DONATION_URL = f"{OPEN_API_PREFIX}/sessions/events/subscribe/donation"
|
|
47
|
+
SESSIONS_SUBSCRIBE_SUBSCRIPTION_URL = f"{OPEN_API_PREFIX}/sessions/events/subscribe/subscription"
|
|
48
|
+
SESSIONS_UNSUBSCRIBE_CHAT_URL = f"{OPEN_API_PREFIX}/sessions/events/unsubscribe/chat"
|
|
49
|
+
SESSIONS_UNSUBSCRIBE_DONATION_URL = f"{OPEN_API_PREFIX}/sessions/events/unsubscribe/donation"
|
|
50
|
+
SESSIONS_UNSUBSCRIBE_SUBSCRIPTION_URL = (
|
|
51
|
+
f"{OPEN_API_PREFIX}/sessions/events/unsubscribe/subscription"
|
|
52
|
+
)
|
chzzk/models/__init__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Pydantic models for Chzzk API responses."""
|
|
2
|
+
|
|
3
|
+
from chzzk.models.category import Category
|
|
4
|
+
from chzzk.models.channel import (
|
|
5
|
+
ChannelInfo,
|
|
6
|
+
ChannelManager,
|
|
7
|
+
Follower,
|
|
8
|
+
Subscriber,
|
|
9
|
+
SubscriberSortType,
|
|
10
|
+
UserRole,
|
|
11
|
+
)
|
|
12
|
+
from chzzk.models.chat import (
|
|
13
|
+
ChatAvailableCondition,
|
|
14
|
+
ChatAvailableGroup,
|
|
15
|
+
ChatMessageResponse,
|
|
16
|
+
ChatSettings,
|
|
17
|
+
UpdateChatSettingsRequest,
|
|
18
|
+
)
|
|
19
|
+
from chzzk.models.common import CategoryType, Page
|
|
20
|
+
from chzzk.models.live import (
|
|
21
|
+
LiveInfo,
|
|
22
|
+
LiveListResponse,
|
|
23
|
+
LiveSetting,
|
|
24
|
+
LiveSettingCategory,
|
|
25
|
+
StreamKey,
|
|
26
|
+
UpdateLiveSettingRequest,
|
|
27
|
+
)
|
|
28
|
+
from chzzk.models.restriction import RestrictedChannel
|
|
29
|
+
from chzzk.models.session import (
|
|
30
|
+
Badge,
|
|
31
|
+
ChatEvent,
|
|
32
|
+
ChatProfile,
|
|
33
|
+
DonationEvent,
|
|
34
|
+
DonationType,
|
|
35
|
+
EventType,
|
|
36
|
+
SessionAuthResponse,
|
|
37
|
+
SessionInfo,
|
|
38
|
+
SessionListResponse,
|
|
39
|
+
SubscribedEvent,
|
|
40
|
+
SubscriptionEvent,
|
|
41
|
+
SystemEvent,
|
|
42
|
+
SystemEventData,
|
|
43
|
+
SystemMessageType,
|
|
44
|
+
UserRoleCode,
|
|
45
|
+
)
|
|
46
|
+
from chzzk.models.user import UserInfo
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"Badge",
|
|
50
|
+
"Category",
|
|
51
|
+
"CategoryType",
|
|
52
|
+
"ChannelInfo",
|
|
53
|
+
"ChannelManager",
|
|
54
|
+
"ChatAvailableCondition",
|
|
55
|
+
"ChatAvailableGroup",
|
|
56
|
+
"ChatEvent",
|
|
57
|
+
"ChatMessageResponse",
|
|
58
|
+
"ChatProfile",
|
|
59
|
+
"ChatSettings",
|
|
60
|
+
"DonationEvent",
|
|
61
|
+
"DonationType",
|
|
62
|
+
"EventType",
|
|
63
|
+
"Follower",
|
|
64
|
+
"LiveInfo",
|
|
65
|
+
"LiveListResponse",
|
|
66
|
+
"LiveSetting",
|
|
67
|
+
"LiveSettingCategory",
|
|
68
|
+
"Page",
|
|
69
|
+
"RestrictedChannel",
|
|
70
|
+
"SessionAuthResponse",
|
|
71
|
+
"SessionInfo",
|
|
72
|
+
"SessionListResponse",
|
|
73
|
+
"StreamKey",
|
|
74
|
+
"SubscribedEvent",
|
|
75
|
+
"Subscriber",
|
|
76
|
+
"SubscriberSortType",
|
|
77
|
+
"SubscriptionEvent",
|
|
78
|
+
"SystemEvent",
|
|
79
|
+
"SystemEventData",
|
|
80
|
+
"SystemMessageType",
|
|
81
|
+
"UpdateChatSettingsRequest",
|
|
82
|
+
"UpdateLiveSettingRequest",
|
|
83
|
+
"UserInfo",
|
|
84
|
+
"UserRole",
|
|
85
|
+
"UserRoleCode",
|
|
86
|
+
]
|
chzzk/models/category.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Pydantic models for Category API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from chzzk.models.common import CategoryType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Category(BaseModel):
|
|
11
|
+
"""Category information."""
|
|
12
|
+
|
|
13
|
+
category_type: CategoryType = Field(alias="categoryType")
|
|
14
|
+
category_id: str = Field(alias="categoryId")
|
|
15
|
+
category_value: str = Field(alias="categoryValue")
|
|
16
|
+
poster_image_url: str | None = Field(default=None, alias="posterImageUrl")
|
|
17
|
+
|
|
18
|
+
model_config = {"populate_by_name": True}
|
chzzk/models/channel.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Pydantic models for Channel API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from enum import StrEnum
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UserRole(StrEnum):
|
|
12
|
+
"""User role enumeration for channel management."""
|
|
13
|
+
|
|
14
|
+
STREAMING_CHANNEL_OWNER = "STREAMING_CHANNEL_OWNER"
|
|
15
|
+
STREAMING_CHANNEL_MANAGER = "STREAMING_CHANNEL_MANAGER"
|
|
16
|
+
STREAMING_CHAT_MANAGER = "STREAMING_CHAT_MANAGER"
|
|
17
|
+
STREAMING_SETTLEMENT_MANAGER = "STREAMING_SETTLEMENT_MANAGER"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SubscriberSortType(StrEnum):
|
|
21
|
+
"""Sort type enumeration for subscriber list."""
|
|
22
|
+
|
|
23
|
+
RECENT = "RECENT"
|
|
24
|
+
LONGER = "LONGER"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ChannelInfo(BaseModel):
|
|
28
|
+
"""Channel information."""
|
|
29
|
+
|
|
30
|
+
channel_id: str = Field(alias="channelId")
|
|
31
|
+
channel_name: str = Field(alias="channelName")
|
|
32
|
+
channel_image_url: str | None = Field(default=None, alias="channelImageUrl")
|
|
33
|
+
follower_count: int = Field(alias="followerCount")
|
|
34
|
+
verified_mark: bool = Field(alias="verifiedMark")
|
|
35
|
+
|
|
36
|
+
model_config = {"populate_by_name": True}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ChannelManager(BaseModel):
|
|
40
|
+
"""Channel manager information."""
|
|
41
|
+
|
|
42
|
+
manager_channel_id: str = Field(alias="managerChannelId")
|
|
43
|
+
manager_channel_name: str = Field(alias="managerChannelName")
|
|
44
|
+
user_role: UserRole = Field(alias="userRole")
|
|
45
|
+
created_date: datetime = Field(alias="createdDate")
|
|
46
|
+
|
|
47
|
+
model_config = {"populate_by_name": True}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Follower(BaseModel):
|
|
51
|
+
"""Follower information."""
|
|
52
|
+
|
|
53
|
+
channel_id: str = Field(alias="channelId")
|
|
54
|
+
channel_name: str = Field(alias="channelName")
|
|
55
|
+
created_date: datetime = Field(alias="createdDate")
|
|
56
|
+
|
|
57
|
+
model_config = {"populate_by_name": True}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Subscriber(BaseModel):
|
|
61
|
+
"""Subscriber information."""
|
|
62
|
+
|
|
63
|
+
channel_id: str = Field(alias="channelId")
|
|
64
|
+
channel_name: str = Field(alias="channelName")
|
|
65
|
+
created_date: datetime = Field(alias="createdDate")
|
|
66
|
+
tier_no: int = Field(alias="tierNo")
|
|
67
|
+
month: int
|
|
68
|
+
|
|
69
|
+
model_config = {"populate_by_name": True}
|
chzzk/models/chat.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Pydantic models for Chat API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ChatAvailableCondition(StrEnum):
|
|
11
|
+
"""Chat available condition enumeration."""
|
|
12
|
+
|
|
13
|
+
NONE = "NONE"
|
|
14
|
+
REAL_NAME = "REAL_NAME"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ChatAvailableGroup(StrEnum):
|
|
18
|
+
"""Chat available group enumeration."""
|
|
19
|
+
|
|
20
|
+
ALL = "ALL"
|
|
21
|
+
FOLLOWER = "FOLLOWER"
|
|
22
|
+
MANAGER = "MANAGER"
|
|
23
|
+
SUBSCRIBER = "SUBSCRIBER"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ChatMessageResponse(BaseModel):
|
|
27
|
+
"""Response model for sending a chat message."""
|
|
28
|
+
|
|
29
|
+
message_id: str = Field(alias="messageId")
|
|
30
|
+
|
|
31
|
+
model_config = {"populate_by_name": True}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ChatSettings(BaseModel):
|
|
35
|
+
"""Chat settings information."""
|
|
36
|
+
|
|
37
|
+
chat_available_condition: ChatAvailableCondition = Field(alias="chatAvailableCondition")
|
|
38
|
+
chat_available_group: ChatAvailableGroup = Field(alias="chatAvailableGroup")
|
|
39
|
+
allow_subscriber_in_follower_mode: bool = Field(alias="allowSubscriberInFollowerMode")
|
|
40
|
+
min_follower_minute: int = Field(alias="minFollowerMinute")
|
|
41
|
+
chat_emoji_mode: bool = Field(alias="chatEmojiMode")
|
|
42
|
+
chat_slow_mode_sec: int = Field(alias="chatSlowModeSec")
|
|
43
|
+
|
|
44
|
+
model_config = {"populate_by_name": True}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class UpdateChatSettingsRequest(BaseModel):
|
|
48
|
+
"""Request model for updating chat settings."""
|
|
49
|
+
|
|
50
|
+
chat_available_condition: ChatAvailableCondition | None = Field(
|
|
51
|
+
default=None, serialization_alias="chatAvailableCondition"
|
|
52
|
+
)
|
|
53
|
+
chat_available_group: ChatAvailableGroup | None = Field(
|
|
54
|
+
default=None, serialization_alias="chatAvailableGroup"
|
|
55
|
+
)
|
|
56
|
+
allow_subscriber_in_follower_mode: bool | None = Field(
|
|
57
|
+
default=None, serialization_alias="allowSubscriberInFollowerMode"
|
|
58
|
+
)
|
|
59
|
+
min_follower_minute: int | None = Field(default=None, serialization_alias="minFollowerMinute")
|
|
60
|
+
chat_emoji_mode: bool | None = Field(default=None, serialization_alias="chatEmojiMode")
|
|
61
|
+
chat_slow_mode_sec: int | None = Field(default=None, serialization_alias="chatSlowModeSec")
|
|
62
|
+
|
|
63
|
+
model_config = {"populate_by_name": True}
|
chzzk/models/common.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Common models shared across API modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Page(BaseModel):
|
|
11
|
+
"""Pagination information for list responses."""
|
|
12
|
+
|
|
13
|
+
next: str | None = None
|
|
14
|
+
|
|
15
|
+
model_config = {"populate_by_name": True}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CategoryType(StrEnum):
|
|
19
|
+
"""Category type enumeration."""
|
|
20
|
+
|
|
21
|
+
GAME = "GAME"
|
|
22
|
+
SPORTS = "SPORTS"
|
|
23
|
+
ETC = "ETC"
|