From 17335cc9543abd3805453f809fc3a5bcac1c0c80 Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sun, 10 Nov 2024 10:41:40 +0000 Subject: [PATCH 01/12] [Feat] (Enhance Developer Experience) When a client used ChatClient, live_status, live_detail method didn't need channel_id argument --- chzzkpy/chat/chat_client.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 067bac8..7bd552d 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -29,6 +29,8 @@ import aiohttp +from chzzkpy.live import LiveDetail, LiveStatus + from .enums import ChatCmd from .error import ChatConnectFailed from .gateway import ChzzkWebSocket, ReconnectWebsocket @@ -411,3 +413,13 @@ async def blind_message(self, message: ChatMessage) -> None: streaming_channel_id=message.extras.streaming_channel_id, ) return + + async def live_status(self, channel_id: Optional[str] = None) -> Optional[LiveStatus]: + if channel_id is None: + channel_id = self.channel_id + return await super().live_status(channel_id) + + async def live_detail(self, channel_id: Optional[str] = None) -> Optional[LiveDetail]: + if channel_id is None: + channel_id = self.channel_id + return await super().live_detail(channel_id) From 428b385277549b8e97f56187d806dc55691432ff Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 04:33:36 +0000 Subject: [PATCH 02/12] [Fix] #31 - (WIP) Check chat_channel_id --- chzzkpy/chat/chat_client.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 7bd552d..33b0c5d 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -23,14 +23,12 @@ from __future__ import annotations +import aiohttp import asyncio +import datetime import logging from typing import Any, Optional, Callable, Coroutine, TYPE_CHECKING -import aiohttp - -from chzzkpy.live import LiveDetail, LiveStatus - from .enums import ChatCmd from .error import ChatConnectFailed from .gateway import ChzzkWebSocket, ReconnectWebsocket @@ -38,6 +36,7 @@ from .state import ConnectionState from ..client import Client from ..error import LoginRequired +from ..live import LiveDetail, LiveStatus from ..http import ChzzkAPISession if TYPE_CHECKING: @@ -153,9 +152,24 @@ async def polling(self) -> None: user_id=self.user_id, ) session_id = self._gateway.session_id + + last_check_time = datetime.datetime.now() while True: await self._gateway.poll_event() + + # Confirm chat-channel-id with live_status() method. + # When a streamer starts a new broadcast, a chat-channel-id will regenrated. + # + # https://github.com/gunyu1019/chzzkpy/issues/31 + relative_time = datetime.datetime.now() - last_check_time + if relative_time.total_seconds() >= 60: + live_status = await self.live_status(channel_id=self.channel_id) + + if live_status.chat_channel_id != self.chat_channel_id: + # need re-generation + session_id = None + continue except ReconnectWebsocket: self.dispatch("disconnect") continue From bdec01557ec4c7429ed05dd5f7a41809d99f37be Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 04:34:34 +0000 Subject: [PATCH 03/12] [Fix] #31 - Add close method at gateway --- chzzkpy/chat/gateway.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chzzkpy/chat/gateway.py b/chzzkpy/chat/gateway.py index 27b020e..c18834d 100644 --- a/chzzkpy/chat/gateway.py +++ b/chzzkpy/chat/gateway.py @@ -64,6 +64,10 @@ def set_hook(self, cmd: ChatCmd, coro_func: Callable[..., Any]): def remove_hook(self, cmd: ChatCmd): self._event_hook[cmd] = None + + async def close(self): + self.session_id = None + await self.socket.close() @classmethod async def new_session( From 3dd43718a04642e3e9375babbb4a16d7eb119622 Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 04:55:35 +0000 Subject: [PATCH 04/12] [Fix] #31 - When chat-channel-id is diffreent, a websocket makes reconnection --- chzzkpy/chat/chat_client.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 33b0c5d..7ee3610 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -131,7 +131,7 @@ async def close(self): self._ready.clear() if self._gateway is not None: - await self._gateway.socket.close() + await self._gateway.close() await self.ws_session.close() await super().close() @@ -164,12 +164,21 @@ async def polling(self) -> None: # https://github.com/gunyu1019/chzzkpy/issues/31 relative_time = datetime.datetime.now() - last_check_time if relative_time.total_seconds() >= 60: + last_check_time = datetime.datetime.now() live_status = await self.live_status(channel_id=self.channel_id) + if live_status is None: + continue - if live_status.chat_channel_id != self.chat_channel_id: - # need re-generation - session_id = None + if live_status.chat_channel_id == self.chat_channel_id: continue + + _log.debug("A chat_channel_id has been updated. Reconnect websocket.") + session_id = None + await self._gateway.close() + + self.chat_channel_id = live_status.chat_channel_id + raise ReconnectWebsocket() + except ReconnectWebsocket: self.dispatch("disconnect") continue From 0a622ea805f5ac1ffe7f1a983d2b2294ef4c33be Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:05:22 +0000 Subject: [PATCH 05/12] [Feat] Divide feature to _confirm_live_status method --- chzzkpy/chat/chat_client.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 7ee3610..ba84f20 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -27,7 +27,7 @@ import asyncio import datetime import logging -from typing import Any, Optional, Callable, Coroutine, TYPE_CHECKING +from typing import Any, Optional, Callable, Coroutine, Literal, TYPE_CHECKING from .enums import ChatCmd from .error import ChatConnectFailed @@ -85,6 +85,7 @@ def __init__( dispatch=self.dispatch, handler=handler, client=self ) self._gateway: Optional[ChzzkWebSocket] = None + self._status: Literal["OPEN", "CLOSE"] def _session_initial_set(self): self._api_session = ChzzkAPISession(loop=self.loop) @@ -135,6 +136,20 @@ async def close(self): await self.ws_session.close() await super().close() + async def _confirm_live_status(self): + live_status = await self.live_status(channel_id=self.channel_id) + if live_status is None: + return + + if live_status.chat_channel_id == self.chat_channel_id: + return + + _log.debug("A chat_channel_id has been updated. Reconnect websocket.") + await self._gateway.close() + + self.chat_channel_id = live_status.chat_channel_id + raise ReconnectWebsocket() + async def polling(self) -> None: session_id: Optional[str] = None while not self.is_closed: @@ -165,22 +180,10 @@ async def polling(self) -> None: relative_time = datetime.datetime.now() - last_check_time if relative_time.total_seconds() >= 60: last_check_time = datetime.datetime.now() - live_status = await self.live_status(channel_id=self.channel_id) - if live_status is None: - continue - - if live_status.chat_channel_id == self.chat_channel_id: - continue - - _log.debug("A chat_channel_id has been updated. Reconnect websocket.") - session_id = None - await self._gateway.close() - - self.chat_channel_id = live_status.chat_channel_id - raise ReconnectWebsocket() - + await self._confirm_live_status() except ReconnectWebsocket: self.dispatch("disconnect") + session_id = None continue # Event Handler From 65c82b2abf5427317f25a7c4168e12b55da0ceb7 Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:05:50 +0000 Subject: [PATCH 06/12] [Feat] Add broadcast_open and broadcast_close event handler --- chzzkpy/chat/chat_client.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index ba84f20..3e74611 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -140,6 +140,13 @@ async def _confirm_live_status(self): live_status = await self.live_status(channel_id=self.channel_id) if live_status is None: return + + if self._status != live_status.status: + self._status = live_status.status + if self._status == "OPEN": + self.dispatch("broadcast_open") + elif self._status == "CLOSE": + self.dispatch("broadcast_close") if live_status.chat_channel_id == self.chat_channel_id: return From 9142f35cc80b541f1ec6fa460a2a856a1e017351 Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:16:18 +0000 Subject: [PATCH 07/12] [Fix] #31 - Adjust relative_time condition. --- chzzkpy/chat/chat_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 3e74611..c2b0b87 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -85,7 +85,7 @@ def __init__( dispatch=self.dispatch, handler=handler, client=self ) self._gateway: Optional[ChzzkWebSocket] = None - self._status: Literal["OPEN", "CLOSE"] + self._status: Literal["OPEN", "CLOSE"] = None def _session_initial_set(self): self._api_session = ChzzkAPISession(loop=self.loop) @@ -185,7 +185,7 @@ async def polling(self) -> None: # # https://github.com/gunyu1019/chzzkpy/issues/31 relative_time = datetime.datetime.now() - last_check_time - if relative_time.total_seconds() >= 60: + if relative_time.total_seconds() >= 59: last_check_time = datetime.datetime.now() await self._confirm_live_status() except ReconnectWebsocket: From e3e8fb6746b35d1f315e67d0328a19b39119a9bc Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:17:43 +0000 Subject: [PATCH 08/12] [Fix] Set _status default value --- chzzkpy/chat/chat_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index c2b0b87..90f0916 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -117,6 +117,7 @@ async def connect(self) -> None: if status is None: raise ChatConnectFailed(self.channel_id) self.chat_channel_id = status.chat_channel_id + self._status = status.status if self._game_session.has_login: user = await self.user() From b978d21612fc1b33b9d999a2f5653746b7862daf Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:19:57 +0000 Subject: [PATCH 09/12] [Fix] Add SubscriptionExtra, SystemExtraParameter at __init__ --- chzzkpy/chat/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chzzkpy/chat/__init__.py b/chzzkpy/chat/__init__.py index 3d40e41..6c9a3e4 100644 --- a/chzzkpy/chat/__init__.py +++ b/chzzkpy/chat/__init__.py @@ -41,8 +41,10 @@ ChatDonationExtra, VideoDonationExtra, MissionDonationExtra, + SubscriptionExtra, NoticeExtra, SystemExtra, + SystemExtraParameter, ) from .profile import Profile, ActivityBadge, StreamingProperty, Badge from .recent_chat import RecentChat From 04211fdc34d630f147a987a86f41095b6fcdb53c Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:24:21 +0000 Subject: [PATCH 10/12] [Deploy] bump to v1.0.4 --- chzzkpy/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chzzkpy/__init__.py b/chzzkpy/__init__.py index ce0e76a..da98eaf 100644 --- a/chzzkpy/__init__.py +++ b/chzzkpy/__init__.py @@ -39,7 +39,7 @@ __author__ = "gunyu1019" __license__ = "MIT" __copyright__ = "Copyright 2024-present gunyu1019" -__version__ = "1.0.3" # version_info.to_string() +__version__ = "1.0.4" # version_info.to_string() class VersionInfo(NamedTuple): @@ -57,5 +57,5 @@ def to_string(self) -> str: version_info: VersionInfo = VersionInfo( - major=1, minor=0, micro=3, release_level=None, serial=0 + major=1, minor=0, micro=4, release_level=None, serial=0 ) From 42702a1d312fd5719fcab97015dd305d7d8900ad Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:24:45 +0000 Subject: [PATCH 11/12] [Formatting] Re-formatting with black --- chzzkpy/chat/chat_client.py | 20 ++++++++++++-------- chzzkpy/chat/gateway.py | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/chzzkpy/chat/chat_client.py b/chzzkpy/chat/chat_client.py index 90f0916..7b2f33b 100644 --- a/chzzkpy/chat/chat_client.py +++ b/chzzkpy/chat/chat_client.py @@ -140,8 +140,8 @@ async def close(self): async def _confirm_live_status(self): live_status = await self.live_status(channel_id=self.channel_id) if live_status is None: - return - + return + if self._status != live_status.status: self._status = live_status.status if self._status == "OPEN": @@ -175,7 +175,7 @@ async def polling(self) -> None: user_id=self.user_id, ) session_id = self._gateway.session_id - + last_check_time = datetime.datetime.now() while True: @@ -183,7 +183,7 @@ async def polling(self) -> None: # Confirm chat-channel-id with live_status() method. # When a streamer starts a new broadcast, a chat-channel-id will regenrated. - # + # # https://github.com/gunyu1019/chzzkpy/issues/31 relative_time = datetime.datetime.now() - last_check_time if relative_time.total_seconds() >= 59: @@ -447,13 +447,17 @@ async def blind_message(self, message: ChatMessage) -> None: streaming_channel_id=message.extras.streaming_channel_id, ) return - - async def live_status(self, channel_id: Optional[str] = None) -> Optional[LiveStatus]: + + async def live_status( + self, channel_id: Optional[str] = None + ) -> Optional[LiveStatus]: if channel_id is None: channel_id = self.channel_id return await super().live_status(channel_id) - - async def live_detail(self, channel_id: Optional[str] = None) -> Optional[LiveDetail]: + + async def live_detail( + self, channel_id: Optional[str] = None + ) -> Optional[LiveDetail]: if channel_id is None: channel_id = self.channel_id return await super().live_detail(channel_id) diff --git a/chzzkpy/chat/gateway.py b/chzzkpy/chat/gateway.py index c18834d..e78ea8f 100644 --- a/chzzkpy/chat/gateway.py +++ b/chzzkpy/chat/gateway.py @@ -64,7 +64,7 @@ def set_hook(self, cmd: ChatCmd, coro_func: Callable[..., Any]): def remove_hook(self, cmd: ChatCmd): self._event_hook[cmd] = None - + async def close(self): self.session_id = None await self.socket.close() From 446278513829080cac0e612b460c5d033cb631cd Mon Sep 17 00:00:00 2001 From: gunyu1019 Date: Sat, 23 Nov 2024 05:35:14 +0000 Subject: [PATCH 12/12] [Formatting] Re-formatting with black --- chzzkpy/error.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chzzkpy/error.py b/chzzkpy/error.py index 3bd7475..7c21d43 100644 --- a/chzzkpy/error.py +++ b/chzzkpy/error.py @@ -31,6 +31,7 @@ class ChzzkpyException(Exception): class LoginRequired(ChzzkpyException): """Exception that’s raised when a method need login.""" + def __init__(self): super(LoginRequired, self).__init__( "This method(feature) needs to login. Please use `login()` method." @@ -39,6 +40,7 @@ def __init__(self): class NotFound(ChzzkpyException): """Exception that’s raised for when status code 404 occurs.""" + def __init__(self, message: Optional[str] = None): if message is None: message = "Not Found" @@ -47,6 +49,7 @@ def __init__(self, message: Optional[str] = None): class HTTPException(ChzzkpyException): """Exception that’s raised when an HTTP request operation fails.""" + def __init__(self, code: int, message: Optional[str] = None): if message is None: message = f"Reponsed error code ({code})"