diff --git a/channel.py b/channel.py index 1f8028f..4087164 100644 --- a/channel.py +++ b/channel.py @@ -2,6 +2,7 @@ from __future__ import annotations import re import json +import asyncio import logging from copy import copy from base64 import b64encode @@ -10,7 +11,7 @@ from typing import Any, Optional, Dict, TYPE_CHECKING from inventory import Game from exceptions import MinerException -from constants import BASE_URL, GQL_OPERATIONS +from constants import BASE_URL, GQL_OPERATIONS, ONLINE_DELAY if TYPE_CHECKING: from twitch import Twitch @@ -50,6 +51,7 @@ class Channel: self.url: str = f"{BASE_URL}/{channel_name}" self._spade_url: str = await self.get_spade_url() self.stream: Optional[Stream] = None + self._pending_stream_up: Optional[asyncio.Task[Any]] = None await self.get_stream() def __eq__(self, other: object): @@ -67,6 +69,15 @@ class Channel: """ return self.stream is not None + @property + def pending_online(self) -> bool: + """ + Returns True if the streamer is about to go online (most likely), False otherwise. + This is because 'stream-up' event is received way before + stream information becomes available. + """ + return self._pending_stream_up is not None + async def get_spade_url(self) -> str: """ To get this monstrous thing, you have to walk a chain of requests. @@ -109,6 +120,19 @@ class Channel: return False return True + async def _online_delay(self): + await asyncio.sleep(ONLINE_DELAY.total_seconds()) + await self.get_stream() + self._pending_stream_up = None + + def set_online(self): + if self.online or self.pending_online: + # we're already online, or about to be + return + # stream-up is sent before the stream actually goes online, so just wait a bit + # and check if it's actually online by then + self._pending_stream_up = asyncio.create_task(self._online_delay()) + def set_offline(self): # to be called externally, if we receive an event about this happening self.stream = None diff --git a/constants.py b/constants.py index a9285e7..ca2e5ea 100644 --- a/constants.py +++ b/constants.py @@ -14,6 +14,7 @@ USER_AGENT = "Twitch Drops App" SETTINGS_PATH = "settings.json" COOKIES_PATH = "cookies.pickle" PING_INTERVAL = timedelta(minutes=3) +ONLINE_DELAY = timedelta(seconds=30) class GQLOperation(Dict[str, Any]): diff --git a/twitch.py b/twitch.py index a933bb8..83ae15f 100644 --- a/twitch.py +++ b/twitch.py @@ -74,9 +74,8 @@ class Twitch: await self.websocket.close() await asyncio.sleep(1) # allows aiohttp to safely close the session - @property - def currently_watching(self) -> Optional[Channel]: - return self._watching_channel + def is_currently_watching(self, channel: Channel) -> bool: + return self._watching_channel is not None and self._watching_channel == channel async def run(self, channels: List[str] = []): """ @@ -189,29 +188,21 @@ class Twitch: if msg_type == "stream-down": logger.info(f"{channel.name} goes OFFLINE") channel.set_offline() - if self._watching_channel is not None and self._watching_channel.id == channel_id: + if self.is_currently_watching(channel): # change the channel if we're currently watching it self._channel_change.set() elif msg_type == "stream-up": logger.info(f"{channel.name} goes ONLINE") - - # stream_up is sent before the stream actually goes online, so just wait a bit - # and check if it's actually online by then - async def online_delay(channel: Channel): - await asyncio.sleep(10) - await channel.check_online() - - asyncio.create_task(online_delay(channel)) + channel.set_online() elif msg_type == "viewcount": - if channel.stream is None: - # check if we've got a view count for a stream that just started - await channel.check_online() - if channel.stream is not None: + if not channel.online: + # if it's not online for some reason, set it so + channel.set_online() + else: + assert channel.stream is not None viewers = message["viewers"] channel.stream.viewer_count = viewers logger.info(f"{channel.name} viewers: {viewers}") - else: - logger.error(f"Channel viewcount update for an offline stream: {channel.name}") async def _validate_password(self, password: str) -> bool: """