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/__init__.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Chzzk Python SDK - Unofficial Python SDK for Chzzk streaming platform."""
|
|
2
|
+
|
|
3
|
+
from chzzk.api import (
|
|
4
|
+
AsyncCategoryService,
|
|
5
|
+
AsyncChannelService,
|
|
6
|
+
AsyncChatService,
|
|
7
|
+
AsyncLiveService,
|
|
8
|
+
AsyncRestrictionService,
|
|
9
|
+
AsyncSessionService,
|
|
10
|
+
AsyncUserService,
|
|
11
|
+
CategoryService,
|
|
12
|
+
ChannelService,
|
|
13
|
+
ChatService,
|
|
14
|
+
LiveService,
|
|
15
|
+
RestrictionService,
|
|
16
|
+
SessionService,
|
|
17
|
+
UserService,
|
|
18
|
+
)
|
|
19
|
+
from chzzk.auth import (
|
|
20
|
+
AsyncChzzkOAuth,
|
|
21
|
+
CallbackTokenStorage,
|
|
22
|
+
ChzzkOAuth,
|
|
23
|
+
FileTokenStorage,
|
|
24
|
+
InMemoryTokenStorage,
|
|
25
|
+
Token,
|
|
26
|
+
TokenStorage,
|
|
27
|
+
)
|
|
28
|
+
from chzzk.client import AsyncChzzkClient, ChzzkClient
|
|
29
|
+
from chzzk.exceptions import (
|
|
30
|
+
AuthenticationError,
|
|
31
|
+
ChzzkAPIError,
|
|
32
|
+
ChzzkError,
|
|
33
|
+
EventSubscriptionError,
|
|
34
|
+
ForbiddenError,
|
|
35
|
+
InvalidClientError,
|
|
36
|
+
InvalidStateError,
|
|
37
|
+
InvalidTokenError,
|
|
38
|
+
NotFoundError,
|
|
39
|
+
RateLimitError,
|
|
40
|
+
ServerError,
|
|
41
|
+
SessionConnectionError,
|
|
42
|
+
SessionError,
|
|
43
|
+
SessionLimitExceededError,
|
|
44
|
+
TokenExpiredError,
|
|
45
|
+
)
|
|
46
|
+
from chzzk.models import (
|
|
47
|
+
Badge,
|
|
48
|
+
Category,
|
|
49
|
+
CategoryType,
|
|
50
|
+
ChannelInfo,
|
|
51
|
+
ChannelManager,
|
|
52
|
+
ChatAvailableCondition,
|
|
53
|
+
ChatAvailableGroup,
|
|
54
|
+
ChatEvent,
|
|
55
|
+
ChatMessageResponse,
|
|
56
|
+
ChatProfile,
|
|
57
|
+
ChatSettings,
|
|
58
|
+
DonationEvent,
|
|
59
|
+
DonationType,
|
|
60
|
+
EventType,
|
|
61
|
+
Follower,
|
|
62
|
+
LiveInfo,
|
|
63
|
+
LiveListResponse,
|
|
64
|
+
LiveSetting,
|
|
65
|
+
LiveSettingCategory,
|
|
66
|
+
Page,
|
|
67
|
+
RestrictedChannel,
|
|
68
|
+
SessionAuthResponse,
|
|
69
|
+
SessionInfo,
|
|
70
|
+
SessionListResponse,
|
|
71
|
+
StreamKey,
|
|
72
|
+
SubscribedEvent,
|
|
73
|
+
Subscriber,
|
|
74
|
+
SubscriberSortType,
|
|
75
|
+
SubscriptionEvent,
|
|
76
|
+
SystemEvent,
|
|
77
|
+
SystemEventData,
|
|
78
|
+
SystemMessageType,
|
|
79
|
+
UpdateChatSettingsRequest,
|
|
80
|
+
UpdateLiveSettingRequest,
|
|
81
|
+
UserInfo,
|
|
82
|
+
UserRole,
|
|
83
|
+
UserRoleCode,
|
|
84
|
+
)
|
|
85
|
+
from chzzk.realtime import AsyncChzzkEventClient, ChzzkEventClient
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
from chzzk._version import __version__
|
|
89
|
+
except ImportError:
|
|
90
|
+
__version__ = "0.0.0.dev0" # 개발 환경 fallback
|
|
91
|
+
|
|
92
|
+
__all__ = [
|
|
93
|
+
# Clients
|
|
94
|
+
"AsyncChzzkClient",
|
|
95
|
+
"AsyncChzzkEventClient",
|
|
96
|
+
"ChzzkClient",
|
|
97
|
+
"ChzzkEventClient",
|
|
98
|
+
# Services
|
|
99
|
+
"AsyncCategoryService",
|
|
100
|
+
"AsyncChannelService",
|
|
101
|
+
"AsyncChatService",
|
|
102
|
+
"AsyncLiveService",
|
|
103
|
+
"AsyncRestrictionService",
|
|
104
|
+
"AsyncSessionService",
|
|
105
|
+
"AsyncUserService",
|
|
106
|
+
"CategoryService",
|
|
107
|
+
"ChannelService",
|
|
108
|
+
"ChatService",
|
|
109
|
+
"LiveService",
|
|
110
|
+
"RestrictionService",
|
|
111
|
+
"SessionService",
|
|
112
|
+
"UserService",
|
|
113
|
+
# Auth
|
|
114
|
+
"AsyncChzzkOAuth",
|
|
115
|
+
"CallbackTokenStorage",
|
|
116
|
+
"ChzzkOAuth",
|
|
117
|
+
"FileTokenStorage",
|
|
118
|
+
"InMemoryTokenStorage",
|
|
119
|
+
"Token",
|
|
120
|
+
"TokenStorage",
|
|
121
|
+
# Models
|
|
122
|
+
"Badge",
|
|
123
|
+
"Category",
|
|
124
|
+
"CategoryType",
|
|
125
|
+
"ChannelInfo",
|
|
126
|
+
"ChannelManager",
|
|
127
|
+
"ChatAvailableCondition",
|
|
128
|
+
"ChatAvailableGroup",
|
|
129
|
+
"ChatEvent",
|
|
130
|
+
"ChatMessageResponse",
|
|
131
|
+
"ChatProfile",
|
|
132
|
+
"ChatSettings",
|
|
133
|
+
"DonationEvent",
|
|
134
|
+
"DonationType",
|
|
135
|
+
"EventType",
|
|
136
|
+
"Follower",
|
|
137
|
+
"LiveInfo",
|
|
138
|
+
"LiveListResponse",
|
|
139
|
+
"LiveSetting",
|
|
140
|
+
"LiveSettingCategory",
|
|
141
|
+
"Page",
|
|
142
|
+
"RestrictedChannel",
|
|
143
|
+
"SessionAuthResponse",
|
|
144
|
+
"SessionInfo",
|
|
145
|
+
"SessionListResponse",
|
|
146
|
+
"StreamKey",
|
|
147
|
+
"SubscribedEvent",
|
|
148
|
+
"Subscriber",
|
|
149
|
+
"SubscriberSortType",
|
|
150
|
+
"SubscriptionEvent",
|
|
151
|
+
"SystemEvent",
|
|
152
|
+
"SystemEventData",
|
|
153
|
+
"SystemMessageType",
|
|
154
|
+
"UpdateChatSettingsRequest",
|
|
155
|
+
"UpdateLiveSettingRequest",
|
|
156
|
+
"UserInfo",
|
|
157
|
+
"UserRole",
|
|
158
|
+
"UserRoleCode",
|
|
159
|
+
# Exceptions
|
|
160
|
+
"AuthenticationError",
|
|
161
|
+
"ChzzkAPIError",
|
|
162
|
+
"ChzzkError",
|
|
163
|
+
"EventSubscriptionError",
|
|
164
|
+
"ForbiddenError",
|
|
165
|
+
"InvalidClientError",
|
|
166
|
+
"InvalidStateError",
|
|
167
|
+
"InvalidTokenError",
|
|
168
|
+
"NotFoundError",
|
|
169
|
+
"RateLimitError",
|
|
170
|
+
"ServerError",
|
|
171
|
+
"SessionConnectionError",
|
|
172
|
+
"SessionError",
|
|
173
|
+
"SessionLimitExceededError",
|
|
174
|
+
"TokenExpiredError",
|
|
175
|
+
]
|
chzzk/_version.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
chzzk/api/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""API services for Chzzk SDK."""
|
|
2
|
+
|
|
3
|
+
from chzzk.api.base import AsyncBaseService, BaseService
|
|
4
|
+
from chzzk.api.category import AsyncCategoryService, CategoryService
|
|
5
|
+
from chzzk.api.channel import AsyncChannelService, ChannelService
|
|
6
|
+
from chzzk.api.chat import AsyncChatService, ChatService
|
|
7
|
+
from chzzk.api.live import AsyncLiveService, LiveService
|
|
8
|
+
from chzzk.api.restriction import AsyncRestrictionService, RestrictionService
|
|
9
|
+
from chzzk.api.session import AsyncSessionService, SessionService
|
|
10
|
+
from chzzk.api.user import AsyncUserService, UserService
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AsyncBaseService",
|
|
14
|
+
"AsyncCategoryService",
|
|
15
|
+
"AsyncChannelService",
|
|
16
|
+
"AsyncChatService",
|
|
17
|
+
"AsyncLiveService",
|
|
18
|
+
"AsyncRestrictionService",
|
|
19
|
+
"AsyncSessionService",
|
|
20
|
+
"AsyncUserService",
|
|
21
|
+
"BaseService",
|
|
22
|
+
"CategoryService",
|
|
23
|
+
"ChannelService",
|
|
24
|
+
"ChatService",
|
|
25
|
+
"LiveService",
|
|
26
|
+
"RestrictionService",
|
|
27
|
+
"SessionService",
|
|
28
|
+
"UserService",
|
|
29
|
+
]
|
chzzk/api/base.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Base service class for API services."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from chzzk.http.client import AsyncHTTPClient, HTTPClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseService:
|
|
13
|
+
"""Base class for synchronous API services."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
http_client: HTTPClient,
|
|
18
|
+
*,
|
|
19
|
+
client_id: str | None = None,
|
|
20
|
+
client_secret: str | None = None,
|
|
21
|
+
access_token: str | None = None,
|
|
22
|
+
token_refresher: Callable[[], str | None] | None = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Initialize the service.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
http_client: HTTP client instance for making requests.
|
|
28
|
+
client_id: Client ID for API authentication.
|
|
29
|
+
client_secret: Client secret for API authentication.
|
|
30
|
+
access_token: Access token for user-authenticated requests.
|
|
31
|
+
token_refresher: Optional callback to get/refresh access token.
|
|
32
|
+
"""
|
|
33
|
+
self._http = http_client
|
|
34
|
+
self._client_id = client_id
|
|
35
|
+
self._client_secret = client_secret
|
|
36
|
+
self._access_token = access_token
|
|
37
|
+
self._token_refresher = token_refresher
|
|
38
|
+
|
|
39
|
+
def _get_client_headers(self) -> dict[str, str]:
|
|
40
|
+
"""Get headers for Client-authenticated requests.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Headers dict with Client-Id and Client-Secret.
|
|
44
|
+
"""
|
|
45
|
+
headers: dict[str, str] = {}
|
|
46
|
+
if self._client_id:
|
|
47
|
+
headers["Client-Id"] = self._client_id
|
|
48
|
+
if self._client_secret:
|
|
49
|
+
headers["Client-Secret"] = self._client_secret
|
|
50
|
+
return headers
|
|
51
|
+
|
|
52
|
+
def _get_token_headers(self) -> dict[str, str]:
|
|
53
|
+
"""Get headers for Access Token-authenticated requests.
|
|
54
|
+
|
|
55
|
+
If a token_refresher callback is configured, it will be called
|
|
56
|
+
to get the current access token (and potentially refresh it).
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Headers dict with Authorization Bearer token.
|
|
60
|
+
"""
|
|
61
|
+
# Use token refresher if available (may refresh expired token)
|
|
62
|
+
if self._token_refresher:
|
|
63
|
+
token = self._token_refresher()
|
|
64
|
+
if token:
|
|
65
|
+
self._access_token = token
|
|
66
|
+
|
|
67
|
+
headers: dict[str, str] = {}
|
|
68
|
+
if self._access_token:
|
|
69
|
+
headers["Authorization"] = f"Bearer {self._access_token}"
|
|
70
|
+
return headers
|
|
71
|
+
|
|
72
|
+
def set_access_token(self, token: str) -> None:
|
|
73
|
+
"""Update the access token.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
token: New access token.
|
|
77
|
+
"""
|
|
78
|
+
self._access_token = token
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AsyncBaseService:
|
|
82
|
+
"""Base class for asynchronous API services."""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
http_client: AsyncHTTPClient,
|
|
87
|
+
*,
|
|
88
|
+
client_id: str | None = None,
|
|
89
|
+
client_secret: str | None = None,
|
|
90
|
+
access_token: str | None = None,
|
|
91
|
+
async_token_refresher: Callable[[], str | None] | None = None,
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Initialize the async service.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
http_client: Async HTTP client instance for making requests.
|
|
97
|
+
client_id: Client ID for API authentication.
|
|
98
|
+
client_secret: Client secret for API authentication.
|
|
99
|
+
access_token: Access token for user-authenticated requests.
|
|
100
|
+
async_token_refresher: Optional async callback to get/refresh access token.
|
|
101
|
+
"""
|
|
102
|
+
self._http = http_client
|
|
103
|
+
self._client_id = client_id
|
|
104
|
+
self._client_secret = client_secret
|
|
105
|
+
self._access_token = access_token
|
|
106
|
+
self._async_token_refresher = async_token_refresher
|
|
107
|
+
|
|
108
|
+
def _get_client_headers(self) -> dict[str, str]:
|
|
109
|
+
"""Get headers for Client-authenticated requests.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Headers dict with Client-Id and Client-Secret.
|
|
113
|
+
"""
|
|
114
|
+
headers: dict[str, str] = {}
|
|
115
|
+
if self._client_id:
|
|
116
|
+
headers["Client-Id"] = self._client_id
|
|
117
|
+
if self._client_secret:
|
|
118
|
+
headers["Client-Secret"] = self._client_secret
|
|
119
|
+
return headers
|
|
120
|
+
|
|
121
|
+
async def _get_token_headers(self) -> dict[str, str]:
|
|
122
|
+
"""Get headers for Access Token-authenticated requests.
|
|
123
|
+
|
|
124
|
+
If an async_token_refresher callback is configured, it will be called
|
|
125
|
+
to get the current access token (and potentially refresh it).
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Headers dict with Authorization Bearer token.
|
|
129
|
+
"""
|
|
130
|
+
# Use async token refresher if available (may refresh expired token)
|
|
131
|
+
if self._async_token_refresher:
|
|
132
|
+
token = await self._async_token_refresher()
|
|
133
|
+
if token:
|
|
134
|
+
self._access_token = token
|
|
135
|
+
|
|
136
|
+
headers: dict[str, str] = {}
|
|
137
|
+
if self._access_token:
|
|
138
|
+
headers["Authorization"] = f"Bearer {self._access_token}"
|
|
139
|
+
return headers
|
|
140
|
+
|
|
141
|
+
def set_access_token(self, token: str) -> None:
|
|
142
|
+
"""Update the access token.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
token: New access token.
|
|
146
|
+
"""
|
|
147
|
+
self._access_token = token
|
chzzk/api/category.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Category API service for Chzzk."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from chzzk.api.base import AsyncBaseService, BaseService
|
|
6
|
+
from chzzk.http import CATEGORIES_SEARCH_URL
|
|
7
|
+
from chzzk.models.category import Category
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CategoryService(BaseService):
|
|
11
|
+
"""Synchronous Category API service.
|
|
12
|
+
|
|
13
|
+
Provides access to category-related API endpoints.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def search(self, query: str, *, size: int = 20) -> list[Category]:
|
|
17
|
+
"""Search for categories.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
query: Search query string.
|
|
21
|
+
size: Maximum number of results to return (default: 20).
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
List of Category objects matching the query.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ChzzkAPIError: If the API request fails.
|
|
28
|
+
"""
|
|
29
|
+
params = {"query": query, "size": size}
|
|
30
|
+
data = self._http.get(
|
|
31
|
+
CATEGORIES_SEARCH_URL,
|
|
32
|
+
params=params,
|
|
33
|
+
headers=self._get_client_headers(),
|
|
34
|
+
)
|
|
35
|
+
categories = data.get("data", [])
|
|
36
|
+
return [Category.model_validate(item) for item in categories]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AsyncCategoryService(AsyncBaseService):
|
|
40
|
+
"""Asynchronous Category API service.
|
|
41
|
+
|
|
42
|
+
Provides access to category-related API endpoints.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
async def search(self, query: str, *, size: int = 20) -> list[Category]:
|
|
46
|
+
"""Search for categories.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
query: Search query string.
|
|
50
|
+
size: Maximum number of results to return (default: 20).
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
List of Category objects matching the query.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ChzzkAPIError: If the API request fails.
|
|
57
|
+
"""
|
|
58
|
+
params = {"query": query, "size": size}
|
|
59
|
+
data = await self._http.get(
|
|
60
|
+
CATEGORIES_SEARCH_URL,
|
|
61
|
+
params=params,
|
|
62
|
+
headers=self._get_client_headers(),
|
|
63
|
+
)
|
|
64
|
+
categories = data.get("data", [])
|
|
65
|
+
return [Category.model_validate(item) for item in categories]
|
chzzk/api/channel.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""Channel API service for Chzzk."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from chzzk.api.base import AsyncBaseService, BaseService
|
|
6
|
+
from chzzk.http import (
|
|
7
|
+
CHANNEL_FOLLOWERS_URL,
|
|
8
|
+
CHANNEL_ROLES_URL,
|
|
9
|
+
CHANNEL_SUBSCRIBERS_URL,
|
|
10
|
+
CHANNELS_URL,
|
|
11
|
+
)
|
|
12
|
+
from chzzk.models.channel import (
|
|
13
|
+
ChannelInfo,
|
|
14
|
+
ChannelManager,
|
|
15
|
+
Follower,
|
|
16
|
+
Subscriber,
|
|
17
|
+
SubscriberSortType,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ChannelService(BaseService):
|
|
22
|
+
"""Synchronous Channel API service.
|
|
23
|
+
|
|
24
|
+
Provides access to channel-related API endpoints.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def get_channels(self, channel_ids: list[str]) -> list[ChannelInfo]:
|
|
28
|
+
"""Get information for multiple channels.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
channel_ids: List of channel IDs to look up (max 20).
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
List of ChannelInfo objects.
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
ChzzkAPIError: If the API request fails.
|
|
38
|
+
"""
|
|
39
|
+
params = {"channelIds": ",".join(channel_ids)}
|
|
40
|
+
data = self._http.get(
|
|
41
|
+
CHANNELS_URL,
|
|
42
|
+
params=params,
|
|
43
|
+
headers=self._get_client_headers(),
|
|
44
|
+
)
|
|
45
|
+
channels = data.get("data", [])
|
|
46
|
+
return [ChannelInfo.model_validate(item) for item in channels]
|
|
47
|
+
|
|
48
|
+
def get_streaming_roles(self) -> list[ChannelManager]:
|
|
49
|
+
"""Get channel managers for the authenticated user's channel.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
List of ChannelManager objects.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
InvalidTokenError: If the access token is invalid.
|
|
56
|
+
ChzzkAPIError: If the API request fails.
|
|
57
|
+
"""
|
|
58
|
+
data = self._http.get(CHANNEL_ROLES_URL, headers=self._get_token_headers())
|
|
59
|
+
managers = data.get("data", [])
|
|
60
|
+
return [ChannelManager.model_validate(item) for item in managers]
|
|
61
|
+
|
|
62
|
+
def get_followers(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
page: int = 0,
|
|
66
|
+
size: int = 20,
|
|
67
|
+
) -> list[Follower]:
|
|
68
|
+
"""Get followers for the authenticated user's channel.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
page: Page number (0-indexed).
|
|
72
|
+
size: Number of results per page.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
List of Follower objects.
|
|
76
|
+
|
|
77
|
+
Raises:
|
|
78
|
+
InvalidTokenError: If the access token is invalid.
|
|
79
|
+
ChzzkAPIError: If the API request fails.
|
|
80
|
+
"""
|
|
81
|
+
params = {"page": page, "size": size}
|
|
82
|
+
data = self._http.get(
|
|
83
|
+
CHANNEL_FOLLOWERS_URL,
|
|
84
|
+
params=params,
|
|
85
|
+
headers=self._get_token_headers(),
|
|
86
|
+
)
|
|
87
|
+
followers = data.get("data", [])
|
|
88
|
+
return [Follower.model_validate(item) for item in followers]
|
|
89
|
+
|
|
90
|
+
def get_subscribers(
|
|
91
|
+
self,
|
|
92
|
+
*,
|
|
93
|
+
page: int = 0,
|
|
94
|
+
size: int = 20,
|
|
95
|
+
sort: SubscriberSortType = SubscriberSortType.RECENT,
|
|
96
|
+
) -> list[Subscriber]:
|
|
97
|
+
"""Get subscribers for the authenticated user's channel.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
page: Page number (0-indexed).
|
|
101
|
+
size: Number of results per page.
|
|
102
|
+
sort: Sort order (RECENT or LONGER).
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List of Subscriber objects.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
InvalidTokenError: If the access token is invalid.
|
|
109
|
+
ChzzkAPIError: If the API request fails.
|
|
110
|
+
"""
|
|
111
|
+
params = {"page": page, "size": size, "sortType": sort.value}
|
|
112
|
+
data = self._http.get(
|
|
113
|
+
CHANNEL_SUBSCRIBERS_URL,
|
|
114
|
+
params=params,
|
|
115
|
+
headers=self._get_token_headers(),
|
|
116
|
+
)
|
|
117
|
+
subscribers = data.get("data", [])
|
|
118
|
+
return [Subscriber.model_validate(item) for item in subscribers]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class AsyncChannelService(AsyncBaseService):
|
|
122
|
+
"""Asynchronous Channel API service.
|
|
123
|
+
|
|
124
|
+
Provides access to channel-related API endpoints.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
async def get_channels(self, channel_ids: list[str]) -> list[ChannelInfo]:
|
|
128
|
+
"""Get information for multiple channels.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
channel_ids: List of channel IDs to look up (max 20).
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
List of ChannelInfo objects.
|
|
135
|
+
|
|
136
|
+
Raises:
|
|
137
|
+
ChzzkAPIError: If the API request fails.
|
|
138
|
+
"""
|
|
139
|
+
params = {"channelIds": ",".join(channel_ids)}
|
|
140
|
+
data = await self._http.get(
|
|
141
|
+
CHANNELS_URL,
|
|
142
|
+
params=params,
|
|
143
|
+
headers=self._get_client_headers(),
|
|
144
|
+
)
|
|
145
|
+
channels = data.get("data", [])
|
|
146
|
+
return [ChannelInfo.model_validate(item) for item in channels]
|
|
147
|
+
|
|
148
|
+
async def get_streaming_roles(self) -> list[ChannelManager]:
|
|
149
|
+
"""Get channel managers for the authenticated user's channel.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
List of ChannelManager objects.
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
InvalidTokenError: If the access token is invalid.
|
|
156
|
+
ChzzkAPIError: If the API request fails.
|
|
157
|
+
"""
|
|
158
|
+
data = await self._http.get(CHANNEL_ROLES_URL, headers=await self._get_token_headers())
|
|
159
|
+
managers = data.get("data", [])
|
|
160
|
+
return [ChannelManager.model_validate(item) for item in managers]
|
|
161
|
+
|
|
162
|
+
async def get_followers(
|
|
163
|
+
self,
|
|
164
|
+
*,
|
|
165
|
+
page: int = 0,
|
|
166
|
+
size: int = 20,
|
|
167
|
+
) -> list[Follower]:
|
|
168
|
+
"""Get followers for the authenticated user's channel.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
page: Page number (0-indexed).
|
|
172
|
+
size: Number of results per page.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of Follower objects.
|
|
176
|
+
|
|
177
|
+
Raises:
|
|
178
|
+
InvalidTokenError: If the access token is invalid.
|
|
179
|
+
ChzzkAPIError: If the API request fails.
|
|
180
|
+
"""
|
|
181
|
+
params = {"page": page, "size": size}
|
|
182
|
+
data = await self._http.get(
|
|
183
|
+
CHANNEL_FOLLOWERS_URL,
|
|
184
|
+
params=params,
|
|
185
|
+
headers=await self._get_token_headers(),
|
|
186
|
+
)
|
|
187
|
+
followers = data.get("data", [])
|
|
188
|
+
return [Follower.model_validate(item) for item in followers]
|
|
189
|
+
|
|
190
|
+
async def get_subscribers(
|
|
191
|
+
self,
|
|
192
|
+
*,
|
|
193
|
+
page: int = 0,
|
|
194
|
+
size: int = 20,
|
|
195
|
+
sort: SubscriberSortType = SubscriberSortType.RECENT,
|
|
196
|
+
) -> list[Subscriber]:
|
|
197
|
+
"""Get subscribers for the authenticated user's channel.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
page: Page number (0-indexed).
|
|
201
|
+
size: Number of results per page.
|
|
202
|
+
sort: Sort order (RECENT or LONGER).
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
List of Subscriber objects.
|
|
206
|
+
|
|
207
|
+
Raises:
|
|
208
|
+
InvalidTokenError: If the access token is invalid.
|
|
209
|
+
ChzzkAPIError: If the API request fails.
|
|
210
|
+
"""
|
|
211
|
+
params = {"page": page, "size": size, "sortType": sort.value}
|
|
212
|
+
data = await self._http.get(
|
|
213
|
+
CHANNEL_SUBSCRIBERS_URL,
|
|
214
|
+
params=params,
|
|
215
|
+
headers=await self._get_token_headers(),
|
|
216
|
+
)
|
|
217
|
+
subscribers = data.get("data", [])
|
|
218
|
+
return [Subscriber.model_validate(item) for item in subscribers]
|