# bot_twitch.py import os import requests import asyncio from twitchio.ext import commands import importlib import cmd_twitch class TwitchBot(commands.Bot): def __init__(self, config, log_func): self.client_id = os.getenv("TWITCH_CLIENT_ID") self.client_secret = os.getenv("TWITCH_CLIENT_SECRET") self.token = os.getenv("TWITCH_BOT_TOKEN") self.refresh_token = os.getenv("TWITCH_REFRESH_TOKEN") self.log = log_func # Use the logging function from bots.py self.config = config # 1) Initialize the parent Bot FIRST super().__init__( token=self.token, prefix="!", initial_channels=config["twitch_channels"] ) # 2) Then load commands self.load_commands() async def refresh_access_token(self): """ Refreshes the Twitch access token using the stored refresh token. Retries up to 2 times before logging a fatal error. """ self.log("Attempting to refresh Twitch token...", "INFO") url = "https://id.twitch.tv/oauth2/token" params = { "client_id": self.client_id, "client_secret": self.client_secret, "refresh_token": self.refresh_token, "grant_type": "refresh_token" } for attempt in range(3): # Attempt up to 3 times try: response = requests.post(url, params=params) data = response.json() if "access_token" in data: self.token = data["access_token"] self.refresh_token = data.get("refresh_token", self.refresh_token) os.environ["TWITCH_BOT_TOKEN"] = self.token os.environ["TWITCH_REFRESH_TOKEN"] = self.refresh_token self.update_env_file() self.log("Twitch token refreshed successfully.", "INFO") return # Success, exit function else: self.log(f"Twitch token refresh failed (Attempt {attempt+1}/3): {data}", "WARNING") except Exception as e: self.log(f"Twitch token refresh error (Attempt {attempt+1}/3): {e}", "ERROR") await asyncio.sleep(10) # Wait before retrying # If all attempts fail, log error self.log("Twitch token refresh failed after 3 attempts.", "FATAL") def update_env_file(self): """ Updates the .env file with the new Twitch token. """ try: with open(".env", "r") as file: lines = file.readlines() with open(".env", "w") as file: for line in lines: if line.startswith("TWITCH_BOT_TOKEN="): file.write(f"TWITCH_BOT_TOKEN={self.token}\n") elif line.startswith("TWITCH_REFRESH_TOKEN="): file.write(f"TWITCH_REFRESH_TOKEN={self.refresh_token}\n") else: file.write(line) self.log("Updated .env file with new Twitch token.", "INFO") except Exception as e: self.log(f"Failed to update .env file: {e}", "ERROR") def load_commands(self): """ Load all commands dynamically from cmd_twitch.py. """ try: importlib.reload(cmd_twitch) cmd_twitch.setup(self) self.log("Twitch commands loaded successfully.", "INFO") except Exception as e: self.log(f"Error loading Twitch commands: {e}", "ERROR") async def run(self): """ Run the Twitch bot, refreshing tokens if needed. """ try: self.log(f"Twitch bot connecting...", "INFO") self.log(f"...Consider online if no further messages", "INFO") await self.start() #while True: # await self.refresh_access_token() # await asyncio.sleep(10800) # Refresh every 3 hours except Exception as e: self.log(f"Twitch bot failed to start: {e}", "CRITICAL") if "Invalid or unauthorized Access Token passed." in str(e): try: await self.refresh_access_token() except Exception as e: self.log(f"Unable to refresh Twitch token! Twitch bot will be offline!", "CRITICAL")