Add more reliable way to recover from crashes
This commit is contained in:
@@ -9,7 +9,7 @@ from app.twitch_client import StreamInformation
|
|||||||
|
|
||||||
|
|
||||||
class DiscordClient:
|
class DiscordClient:
|
||||||
_notification_msg_id: str = ""
|
notification_msg_id: str = ""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._webhook_url = os.environ["DISCORD_WEBHOOK_URL"]
|
self._webhook_url = os.environ["DISCORD_WEBHOOK_URL"]
|
||||||
@@ -60,7 +60,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
self._notification_msg_id = response.json()["id"]
|
self.notification_msg_id = response.json()["id"]
|
||||||
logger.info("Stream information sent with ping to Discord.")
|
logger.info("Stream information sent with ping to Discord.")
|
||||||
except (exceptions.ConnectionError, exceptions.HTTPError) as err:
|
except (exceptions.ConnectionError, exceptions.HTTPError) as err:
|
||||||
logger.opt(exception=err).warning(
|
logger.opt(exception=err).warning(
|
||||||
@@ -85,7 +85,7 @@ class DiscordClient:
|
|||||||
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
||||||
try:
|
try:
|
||||||
response = requests.patch(
|
response = requests.patch(
|
||||||
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
url=f"{self._webhook_url}/messages/{self.notification_msg_id}",
|
||||||
json={
|
json={
|
||||||
"embeds": [
|
"embeds": [
|
||||||
{
|
{
|
||||||
@@ -127,7 +127,7 @@ class DiscordClient:
|
|||||||
self, streamer_name, vod_url: str | None, retry_count: int = 0
|
self, streamer_name, vod_url: str | None, retry_count: int = 0
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.info("Finalizing stream information on Discord...")
|
logger.info("Finalizing stream information on Discord...")
|
||||||
if not self._notification_msg_id:
|
if not self.notification_msg_id:
|
||||||
logger.info("Message ID not set, nothing to finalize.")
|
logger.info("Message ID not set, nothing to finalize.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.patch(
|
response = requests.patch(
|
||||||
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
url=f"{self._webhook_url}/messages/{self.notification_msg_id}",
|
||||||
json={
|
json={
|
||||||
"username": "Oak Tree",
|
"username": "Oak Tree",
|
||||||
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
||||||
|
|||||||
67
app/main.py
67
app/main.py
@@ -1,6 +1,6 @@
|
|||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from requests import HTTPError
|
from requests import HTTPError
|
||||||
@@ -11,14 +11,18 @@ from app.twitch_client import StreamInformation, TwitchClient
|
|||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
is_live: bool = False
|
is_live: bool = False
|
||||||
last_live_at = None
|
current_stream_id: str = ""
|
||||||
_previous_stream: StreamInformation = None
|
streams: dict[str, StreamInformation]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.twitch_client = TwitchClient(streamer=os.environ["STREAMER_NAME"])
|
self.twitch_client = TwitchClient(streamer=os.environ["STREAMER_NAME"])
|
||||||
self.twitch_client.update_access_token()
|
self.twitch_client.update_access_token()
|
||||||
self.profile_image = self.twitch_client.get_streamer_profile_picture()
|
self.profile_image = self.twitch_client.get_streamer_profile_picture()
|
||||||
self.discord_client = DiscordClient()
|
self.discord_client = DiscordClient()
|
||||||
|
with open("streams.json", "r") as file:
|
||||||
|
saved_streams = json.load(file)
|
||||||
|
for stream_id, saved_stream in saved_streams:
|
||||||
|
self.streams[stream_id] = StreamInformation(**saved_stream)
|
||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
try:
|
try:
|
||||||
@@ -28,41 +32,46 @@ class Main:
|
|||||||
if self.is_live:
|
if self.is_live:
|
||||||
logger.info("Streamer went offline.")
|
logger.info("Streamer went offline.")
|
||||||
self.is_live = False
|
self.is_live = False
|
||||||
self.discord_client.finalize_information_on_discord(
|
stream = self.streams.get(self.current_stream_id)
|
||||||
streamer_name=self._previous_stream.user_name,
|
if stream:
|
||||||
vod_url=self.twitch_client.get_vod(
|
self.discord_client.finalize_information_on_discord(
|
||||||
user_id=self._previous_stream.user_id
|
streamer_name=stream.user_name,
|
||||||
),
|
vod_url=self.twitch_client.get_vod(
|
||||||
)
|
user_id=stream.user_id
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.is_live:
|
if not self.is_live:
|
||||||
logger.info("Streamer went live.")
|
logger.info("Streamer went live.")
|
||||||
if (
|
existing_stream = self.streams.get(stream.id)
|
||||||
self.last_live_at
|
if existing_stream:
|
||||||
and (datetime.now() - self.last_live_at).total_seconds()
|
|
||||||
< 300
|
|
||||||
):
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"Streamer was already live once in the past 5 minutes. "
|
"Recovering from crash, updating discord if possible."
|
||||||
"This is probably due to a crash, not sending the Discord ping."
|
|
||||||
)
|
)
|
||||||
self.last_live_at = datetime.now()
|
|
||||||
self.is_live = True
|
self.is_live = True
|
||||||
|
if existing_stream.discord_message_id:
|
||||||
|
self.discord_client.notification_msg_id = (
|
||||||
|
existing_stream.discord_message_id
|
||||||
|
)
|
||||||
|
self.discord_client.update_information_on_discord(
|
||||||
|
stream=stream, profile_image=self.profile_image
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.is_live = True
|
||||||
|
self.current_stream_id = stream.id
|
||||||
|
self.streams[stream.id] = stream
|
||||||
self.discord_client.send_information_to_discord(
|
self.discord_client.send_information_to_discord(
|
||||||
stream=stream, profile_image=self.profile_image
|
stream=stream, profile_image=self.profile_image
|
||||||
)
|
)
|
||||||
self.last_live_at = datetime.now()
|
self.streams[
|
||||||
self.is_live = True
|
stream.id
|
||||||
|
].discord_message_id = self.discord_client.notification_msg_id
|
||||||
else:
|
else:
|
||||||
logger.info("Streamer still live.")
|
|
||||||
self.discord_client.update_information_on_discord(
|
self.discord_client.update_information_on_discord(
|
||||||
stream=stream, profile_image=self.profile_image
|
stream=stream, profile_image=self.profile_image
|
||||||
)
|
)
|
||||||
|
|
||||||
self._previous_stream = stream
|
|
||||||
except HTTPError as e:
|
except HTTPError as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
@@ -71,12 +80,12 @@ class Main:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.is_live = False
|
self.is_live = False
|
||||||
self.discord_client.finalize_information_on_discord(
|
stream = self.streams.get(self.current_stream_id)
|
||||||
streamer_name=self._previous_stream.user_login,
|
if stream:
|
||||||
vod_url=self.twitch_client.get_vod(
|
self.discord_client.finalize_information_on_discord(
|
||||||
user_id=self._previous_stream.user_id
|
streamer_name=stream.user_name,
|
||||||
),
|
vod_url=self.twitch_client.get_vod(user_id=stream.user_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
DELAY_SECONDS = 30.0
|
DELAY_SECONDS = 30.0
|
||||||
@@ -91,6 +100,8 @@ def entry() -> None:
|
|||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
main.update_status()
|
main.update_status()
|
||||||
|
with open("streams.json", "w") as file:
|
||||||
|
json.dump(main.streams, file)
|
||||||
time.sleep(
|
time.sleep(
|
||||||
DELAY_SECONDS - ((time.time() - start_time) % DELAY_SECONDS)
|
DELAY_SECONDS - ((time.time() - start_time) % DELAY_SECONDS)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class CachePrevent:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class StreamInformation:
|
class StreamInformation:
|
||||||
|
id: str
|
||||||
user_id: str
|
user_id: str
|
||||||
user_name: str
|
user_name: str
|
||||||
user_login: str
|
user_login: str
|
||||||
@@ -33,6 +34,7 @@ class StreamInformation:
|
|||||||
viewer_count: int
|
viewer_count: int
|
||||||
started_at: str
|
started_at: str
|
||||||
_thumbnail_url: str
|
_thumbnail_url: str
|
||||||
|
discord_message_id: str = ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def thumbnail_url(self):
|
def thumbnail_url(self):
|
||||||
@@ -140,6 +142,7 @@ class TwitchClient:
|
|||||||
|
|
||||||
stream_data = streams[0]
|
stream_data = streams[0]
|
||||||
return StreamInformation(
|
return StreamInformation(
|
||||||
|
id=stream_data.get("id"),
|
||||||
user_id=stream_data.get("user_id"),
|
user_id=stream_data.get("user_id"),
|
||||||
user_name=stream_data.get("user_name"),
|
user_name=stream_data.get("user_name"),
|
||||||
user_login=stream_data.get("user_login"),
|
user_login=stream_data.get("user_login"),
|
||||||
|
|||||||
Reference in New Issue
Block a user