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/api/chat.py ADDED
@@ -0,0 +1,239 @@
1
+ """Chat API service for Chzzk."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from chzzk.api.base import AsyncBaseService, BaseService
6
+ from chzzk.http import CHAT_NOTICE_URL, CHAT_SEND_URL, CHAT_SETTINGS_URL
7
+ from chzzk.models.chat import (
8
+ ChatAvailableCondition,
9
+ ChatAvailableGroup,
10
+ ChatMessageResponse,
11
+ ChatSettings,
12
+ UpdateChatSettingsRequest,
13
+ )
14
+
15
+
16
+ class ChatService(BaseService):
17
+ """Synchronous Chat API service.
18
+
19
+ Provides access to chat-related API endpoints.
20
+ """
21
+
22
+ def send_message(self, message: str) -> ChatMessageResponse:
23
+ """Send a chat message.
24
+
25
+ Args:
26
+ message: The message to send.
27
+
28
+ Returns:
29
+ ChatMessageResponse containing the message ID.
30
+
31
+ Raises:
32
+ InvalidTokenError: If the access token is invalid.
33
+ ChzzkAPIError: If the API request fails.
34
+ """
35
+ data = self._http.post(
36
+ CHAT_SEND_URL,
37
+ json={"message": message},
38
+ headers=self._get_token_headers(),
39
+ )
40
+ return ChatMessageResponse.model_validate(data)
41
+
42
+ def register_notice(
43
+ self,
44
+ *,
45
+ message: str | None = None,
46
+ message_id: str | None = None,
47
+ ) -> None:
48
+ """Register a chat notice.
49
+
50
+ Either message or message_id must be provided.
51
+
52
+ Args:
53
+ message: The notice message content.
54
+ message_id: The message ID to use as notice.
55
+
56
+ Raises:
57
+ InvalidTokenError: If the access token is invalid.
58
+ ChzzkAPIError: If the API request fails.
59
+ ValueError: If neither message nor message_id is provided.
60
+ """
61
+ if message is None and message_id is None:
62
+ msg = "Either message or message_id must be provided"
63
+ raise ValueError(msg)
64
+
65
+ payload: dict[str, str] = {}
66
+ if message is not None:
67
+ payload["message"] = message
68
+ if message_id is not None:
69
+ payload["messageId"] = message_id
70
+
71
+ self._http.post(
72
+ CHAT_NOTICE_URL,
73
+ json=payload,
74
+ headers=self._get_token_headers(),
75
+ )
76
+
77
+ def get_settings(self) -> ChatSettings:
78
+ """Get chat settings.
79
+
80
+ Returns:
81
+ ChatSettings object containing the chat configuration.
82
+
83
+ Raises:
84
+ InvalidTokenError: If the access token is invalid.
85
+ ChzzkAPIError: If the API request fails.
86
+ """
87
+ data = self._http.get(CHAT_SETTINGS_URL, headers=self._get_token_headers())
88
+ return ChatSettings.model_validate(data)
89
+
90
+ def update_settings(
91
+ self,
92
+ *,
93
+ chat_available_condition: ChatAvailableCondition | None = None,
94
+ chat_available_group: ChatAvailableGroup | None = None,
95
+ allow_subscriber_in_follower_mode: bool | None = None,
96
+ min_follower_minute: int | None = None,
97
+ chat_emoji_mode: bool | None = None,
98
+ chat_slow_mode_sec: int | None = None,
99
+ ) -> None:
100
+ """Update chat settings.
101
+
102
+ Args:
103
+ chat_available_condition: Chat availability condition.
104
+ chat_available_group: Chat availability group.
105
+ allow_subscriber_in_follower_mode: Allow subscribers in follower-only mode.
106
+ min_follower_minute: Minimum follower minutes required.
107
+ chat_emoji_mode: Enable emoji-only mode.
108
+ chat_slow_mode_sec: Slow mode delay in seconds.
109
+
110
+ Raises:
111
+ InvalidTokenError: If the access token is invalid.
112
+ ChzzkAPIError: If the API request fails.
113
+ """
114
+ request = UpdateChatSettingsRequest(
115
+ chat_available_condition=chat_available_condition,
116
+ chat_available_group=chat_available_group,
117
+ allow_subscriber_in_follower_mode=allow_subscriber_in_follower_mode,
118
+ min_follower_minute=min_follower_minute,
119
+ chat_emoji_mode=chat_emoji_mode,
120
+ chat_slow_mode_sec=chat_slow_mode_sec,
121
+ )
122
+ self._http.put(
123
+ CHAT_SETTINGS_URL,
124
+ json=request.model_dump(by_alias=True, exclude_none=True),
125
+ headers=self._get_token_headers(),
126
+ )
127
+
128
+
129
+ class AsyncChatService(AsyncBaseService):
130
+ """Asynchronous Chat API service.
131
+
132
+ Provides access to chat-related API endpoints.
133
+ """
134
+
135
+ async def send_message(self, message: str) -> ChatMessageResponse:
136
+ """Send a chat message.
137
+
138
+ Args:
139
+ message: The message to send.
140
+
141
+ Returns:
142
+ ChatMessageResponse containing the message ID.
143
+
144
+ Raises:
145
+ InvalidTokenError: If the access token is invalid.
146
+ ChzzkAPIError: If the API request fails.
147
+ """
148
+ data = await self._http.post(
149
+ CHAT_SEND_URL,
150
+ json={"message": message},
151
+ headers=await self._get_token_headers(),
152
+ )
153
+ return ChatMessageResponse.model_validate(data)
154
+
155
+ async def register_notice(
156
+ self,
157
+ *,
158
+ message: str | None = None,
159
+ message_id: str | None = None,
160
+ ) -> None:
161
+ """Register a chat notice.
162
+
163
+ Either message or message_id must be provided.
164
+
165
+ Args:
166
+ message: The notice message content.
167
+ message_id: The message ID to use as notice.
168
+
169
+ Raises:
170
+ InvalidTokenError: If the access token is invalid.
171
+ ChzzkAPIError: If the API request fails.
172
+ ValueError: If neither message nor message_id is provided.
173
+ """
174
+ if message is None and message_id is None:
175
+ msg = "Either message or message_id must be provided"
176
+ raise ValueError(msg)
177
+
178
+ payload: dict[str, str] = {}
179
+ if message is not None:
180
+ payload["message"] = message
181
+ if message_id is not None:
182
+ payload["messageId"] = message_id
183
+
184
+ await self._http.post(
185
+ CHAT_NOTICE_URL,
186
+ json=payload,
187
+ headers=await self._get_token_headers(),
188
+ )
189
+
190
+ async def get_settings(self) -> ChatSettings:
191
+ """Get chat settings.
192
+
193
+ Returns:
194
+ ChatSettings object containing the chat configuration.
195
+
196
+ Raises:
197
+ InvalidTokenError: If the access token is invalid.
198
+ ChzzkAPIError: If the API request fails.
199
+ """
200
+ data = await self._http.get(CHAT_SETTINGS_URL, headers=await self._get_token_headers())
201
+ return ChatSettings.model_validate(data)
202
+
203
+ async def update_settings(
204
+ self,
205
+ *,
206
+ chat_available_condition: ChatAvailableCondition | None = None,
207
+ chat_available_group: ChatAvailableGroup | None = None,
208
+ allow_subscriber_in_follower_mode: bool | None = None,
209
+ min_follower_minute: int | None = None,
210
+ chat_emoji_mode: bool | None = None,
211
+ chat_slow_mode_sec: int | None = None,
212
+ ) -> None:
213
+ """Update chat settings.
214
+
215
+ Args:
216
+ chat_available_condition: Chat availability condition.
217
+ chat_available_group: Chat availability group.
218
+ allow_subscriber_in_follower_mode: Allow subscribers in follower-only mode.
219
+ min_follower_minute: Minimum follower minutes required.
220
+ chat_emoji_mode: Enable emoji-only mode.
221
+ chat_slow_mode_sec: Slow mode delay in seconds.
222
+
223
+ Raises:
224
+ InvalidTokenError: If the access token is invalid.
225
+ ChzzkAPIError: If the API request fails.
226
+ """
227
+ request = UpdateChatSettingsRequest(
228
+ chat_available_condition=chat_available_condition,
229
+ chat_available_group=chat_available_group,
230
+ allow_subscriber_in_follower_mode=allow_subscriber_in_follower_mode,
231
+ min_follower_minute=min_follower_minute,
232
+ chat_emoji_mode=chat_emoji_mode,
233
+ chat_slow_mode_sec=chat_slow_mode_sec,
234
+ )
235
+ await self._http.put(
236
+ CHAT_SETTINGS_URL,
237
+ json=request.model_dump(by_alias=True, exclude_none=True),
238
+ headers=await self._get_token_headers(),
239
+ )
chzzk/api/live.py ADDED
@@ -0,0 +1,212 @@
1
+ """Live API service for Chzzk."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from chzzk.api.base import AsyncBaseService, BaseService
6
+ from chzzk.http import LIVE_SETTING_URL, LIVES_URL, STREAM_KEY_URL
7
+ from chzzk.models.common import CategoryType
8
+ from chzzk.models.live import (
9
+ LiveInfo,
10
+ LiveListResponse,
11
+ LiveSetting,
12
+ StreamKey,
13
+ UpdateLiveSettingRequest,
14
+ )
15
+
16
+
17
+ class LiveService(BaseService):
18
+ """Synchronous Live API service.
19
+
20
+ Provides access to live broadcast-related API endpoints.
21
+ """
22
+
23
+ def get_lives(
24
+ self,
25
+ *,
26
+ size: int = 20,
27
+ next_token: str | None = None,
28
+ ) -> LiveListResponse:
29
+ """Get a list of live broadcasts.
30
+
31
+ Args:
32
+ size: Number of results per page.
33
+ next_token: Pagination token for the next page.
34
+
35
+ Returns:
36
+ LiveListResponse containing list of LiveInfo and pagination info.
37
+
38
+ Raises:
39
+ ChzzkAPIError: If the API request fails.
40
+ """
41
+ params: dict[str, str | int] = {"size": size}
42
+ if next_token:
43
+ params["next"] = next_token
44
+
45
+ data = self._http.get(
46
+ LIVES_URL,
47
+ params=params,
48
+ headers=self._get_client_headers(),
49
+ )
50
+
51
+ lives = [LiveInfo.model_validate(item) for item in data.get("data", [])]
52
+ page_data = data.get("page", {})
53
+ from chzzk.models.common import Page
54
+
55
+ return LiveListResponse(data=lives, page=Page.model_validate(page_data))
56
+
57
+ def get_stream_key(self) -> StreamKey:
58
+ """Get the stream key for the authenticated user's channel.
59
+
60
+ Returns:
61
+ StreamKey object containing the stream key.
62
+
63
+ Raises:
64
+ InvalidTokenError: If the access token is invalid.
65
+ ChzzkAPIError: If the API request fails.
66
+ """
67
+ data = self._http.get(STREAM_KEY_URL, headers=self._get_token_headers())
68
+ return StreamKey.model_validate(data)
69
+
70
+ def get_setting(self) -> LiveSetting:
71
+ """Get the live broadcast setting for the authenticated user's channel.
72
+
73
+ Returns:
74
+ LiveSetting object containing the broadcast settings.
75
+
76
+ Raises:
77
+ InvalidTokenError: If the access token is invalid.
78
+ ChzzkAPIError: If the API request fails.
79
+ """
80
+ data = self._http.get(LIVE_SETTING_URL, headers=self._get_token_headers())
81
+ return LiveSetting.model_validate(data)
82
+
83
+ def update_setting(
84
+ self,
85
+ *,
86
+ default_live_title: str | None = None,
87
+ category_type: CategoryType | None = None,
88
+ category_id: str | None = None,
89
+ tags: list[str] | None = None,
90
+ ) -> None:
91
+ """Update the live broadcast setting.
92
+
93
+ Args:
94
+ default_live_title: Default title for the broadcast.
95
+ category_type: Category type.
96
+ category_id: Category ID.
97
+ tags: List of tags for the broadcast.
98
+
99
+ Raises:
100
+ InvalidTokenError: If the access token is invalid.
101
+ ChzzkAPIError: If the API request fails.
102
+ """
103
+ request = UpdateLiveSettingRequest(
104
+ default_live_title=default_live_title,
105
+ category_type=category_type,
106
+ category_id=category_id,
107
+ tags=tags,
108
+ )
109
+ self._http.patch(
110
+ LIVE_SETTING_URL,
111
+ json=request.model_dump(by_alias=True, exclude_none=True),
112
+ headers=self._get_token_headers(),
113
+ )
114
+
115
+
116
+ class AsyncLiveService(AsyncBaseService):
117
+ """Asynchronous Live API service.
118
+
119
+ Provides access to live broadcast-related API endpoints.
120
+ """
121
+
122
+ async def get_lives(
123
+ self,
124
+ *,
125
+ size: int = 20,
126
+ next_token: str | None = None,
127
+ ) -> LiveListResponse:
128
+ """Get a list of live broadcasts.
129
+
130
+ Args:
131
+ size: Number of results per page.
132
+ next_token: Pagination token for the next page.
133
+
134
+ Returns:
135
+ LiveListResponse containing list of LiveInfo and pagination info.
136
+
137
+ Raises:
138
+ ChzzkAPIError: If the API request fails.
139
+ """
140
+ params: dict[str, str | int] = {"size": size}
141
+ if next_token:
142
+ params["next"] = next_token
143
+
144
+ data = await self._http.get(
145
+ LIVES_URL,
146
+ params=params,
147
+ headers=self._get_client_headers(),
148
+ )
149
+
150
+ lives = [LiveInfo.model_validate(item) for item in data.get("data", [])]
151
+ page_data = data.get("page", {})
152
+ from chzzk.models.common import Page
153
+
154
+ return LiveListResponse(data=lives, page=Page.model_validate(page_data))
155
+
156
+ async def get_stream_key(self) -> StreamKey:
157
+ """Get the stream key for the authenticated user's channel.
158
+
159
+ Returns:
160
+ StreamKey object containing the stream key.
161
+
162
+ Raises:
163
+ InvalidTokenError: If the access token is invalid.
164
+ ChzzkAPIError: If the API request fails.
165
+ """
166
+ data = await self._http.get(STREAM_KEY_URL, headers=await self._get_token_headers())
167
+ return StreamKey.model_validate(data)
168
+
169
+ async def get_setting(self) -> LiveSetting:
170
+ """Get the live broadcast setting for the authenticated user's channel.
171
+
172
+ Returns:
173
+ LiveSetting object containing the broadcast settings.
174
+
175
+ Raises:
176
+ InvalidTokenError: If the access token is invalid.
177
+ ChzzkAPIError: If the API request fails.
178
+ """
179
+ data = await self._http.get(LIVE_SETTING_URL, headers=await self._get_token_headers())
180
+ return LiveSetting.model_validate(data)
181
+
182
+ async def update_setting(
183
+ self,
184
+ *,
185
+ default_live_title: str | None = None,
186
+ category_type: CategoryType | None = None,
187
+ category_id: str | None = None,
188
+ tags: list[str] | None = None,
189
+ ) -> None:
190
+ """Update the live broadcast setting.
191
+
192
+ Args:
193
+ default_live_title: Default title for the broadcast.
194
+ category_type: Category type.
195
+ category_id: Category ID.
196
+ tags: List of tags for the broadcast.
197
+
198
+ Raises:
199
+ InvalidTokenError: If the access token is invalid.
200
+ ChzzkAPIError: If the API request fails.
201
+ """
202
+ request = UpdateLiveSettingRequest(
203
+ default_live_title=default_live_title,
204
+ category_type=category_type,
205
+ category_id=category_id,
206
+ tags=tags,
207
+ )
208
+ await self._http.patch(
209
+ LIVE_SETTING_URL,
210
+ json=request.model_dump(by_alias=True, exclude_none=True),
211
+ headers=await self._get_token_headers(),
212
+ )
@@ -0,0 +1,147 @@
1
+ """Restriction API service for Chzzk."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from chzzk.api.base import AsyncBaseService, BaseService
6
+ from chzzk.http import RESTRICT_CHANNELS_URL
7
+ from chzzk.models.restriction import RestrictedChannel
8
+
9
+
10
+ class RestrictionService(BaseService):
11
+ """Synchronous Restriction API service.
12
+
13
+ Provides access to restriction-related API endpoints.
14
+ """
15
+
16
+ def get_list(
17
+ self,
18
+ *,
19
+ size: int = 20,
20
+ next_token: str | None = None,
21
+ ) -> list[RestrictedChannel]:
22
+ """Get the list of restricted channels.
23
+
24
+ Args:
25
+ size: Number of results per page.
26
+ next_token: Pagination token for the next page.
27
+
28
+ Returns:
29
+ List of RestrictedChannel objects.
30
+
31
+ Raises:
32
+ InvalidTokenError: If the access token is invalid.
33
+ ChzzkAPIError: If the API request fails.
34
+ """
35
+ params: dict[str, str | int] = {"size": size}
36
+ if next_token:
37
+ params["next"] = next_token
38
+
39
+ data = self._http.get(
40
+ RESTRICT_CHANNELS_URL,
41
+ params=params,
42
+ headers=self._get_token_headers(),
43
+ )
44
+ channels = data.get("data", [])
45
+ return [RestrictedChannel.model_validate(item) for item in channels]
46
+
47
+ def add(self, target_channel_id: str) -> None:
48
+ """Add a channel to the restriction list.
49
+
50
+ Args:
51
+ target_channel_id: The channel ID to restrict.
52
+
53
+ Raises:
54
+ InvalidTokenError: If the access token is invalid.
55
+ ChzzkAPIError: If the API request fails.
56
+ """
57
+ self._http.post(
58
+ RESTRICT_CHANNELS_URL,
59
+ json={"targetChannelId": target_channel_id},
60
+ headers=self._get_token_headers(),
61
+ )
62
+
63
+ def remove(self, target_channel_id: str) -> None:
64
+ """Remove a channel from the restriction list.
65
+
66
+ Args:
67
+ target_channel_id: The channel ID to unrestrict.
68
+
69
+ Raises:
70
+ InvalidTokenError: If the access token is invalid.
71
+ ChzzkAPIError: If the API request fails.
72
+ """
73
+ self._http.delete(
74
+ RESTRICT_CHANNELS_URL,
75
+ json={"targetChannelId": target_channel_id},
76
+ headers=self._get_token_headers(),
77
+ )
78
+
79
+
80
+ class AsyncRestrictionService(AsyncBaseService):
81
+ """Asynchronous Restriction API service.
82
+
83
+ Provides access to restriction-related API endpoints.
84
+ """
85
+
86
+ async def get_list(
87
+ self,
88
+ *,
89
+ size: int = 20,
90
+ next_token: str | None = None,
91
+ ) -> list[RestrictedChannel]:
92
+ """Get the list of restricted channels.
93
+
94
+ Args:
95
+ size: Number of results per page.
96
+ next_token: Pagination token for the next page.
97
+
98
+ Returns:
99
+ List of RestrictedChannel objects.
100
+
101
+ Raises:
102
+ InvalidTokenError: If the access token is invalid.
103
+ ChzzkAPIError: If the API request fails.
104
+ """
105
+ params: dict[str, str | int] = {"size": size}
106
+ if next_token:
107
+ params["next"] = next_token
108
+
109
+ data = await self._http.get(
110
+ RESTRICT_CHANNELS_URL,
111
+ params=params,
112
+ headers=await self._get_token_headers(),
113
+ )
114
+ channels = data.get("data", [])
115
+ return [RestrictedChannel.model_validate(item) for item in channels]
116
+
117
+ async def add(self, target_channel_id: str) -> None:
118
+ """Add a channel to the restriction list.
119
+
120
+ Args:
121
+ target_channel_id: The channel ID to restrict.
122
+
123
+ Raises:
124
+ InvalidTokenError: If the access token is invalid.
125
+ ChzzkAPIError: If the API request fails.
126
+ """
127
+ await self._http.post(
128
+ RESTRICT_CHANNELS_URL,
129
+ json={"targetChannelId": target_channel_id},
130
+ headers=await self._get_token_headers(),
131
+ )
132
+
133
+ async def remove(self, target_channel_id: str) -> None:
134
+ """Remove a channel from the restriction list.
135
+
136
+ Args:
137
+ target_channel_id: The channel ID to unrestrict.
138
+
139
+ Raises:
140
+ InvalidTokenError: If the access token is invalid.
141
+ ChzzkAPIError: If the API request fails.
142
+ """
143
+ await self._http.delete(
144
+ RESTRICT_CHANNELS_URL,
145
+ json={"targetChannelId": target_channel_id},
146
+ headers=await self._get_token_headers(),
147
+ )