from twitchio.ext import commands import os from dotenv import load_dotenv import threading import asyncio import streamlit as st import datetime load_dotenv() TAG_INDICATOR_CHAR = "#" MAX_NUM_TAGS_TO_SEND = 5 TAG_SEND_INTERVAL = 30 NUM_LEADERBOARD_TAGS = 10 class SongBot(commands.Bot): def __init__(self): # Get token from environment variable token = os.getenv("TWITCH_TOKEN") if not token: raise ValueError("TWITCH_TOKEN environment variable is not set") # Bot configuration super().__init__( token=token, prefix="!", initial_channels=["djsuno"], # Channel to join ) # Song list to store requests self.pending_tags = {} self.sent_tag_history = [] async def event_ready(self): """Called when the bot is ready""" print(f"Bot is ready! Logged in as {self.nick}") print(f"Connected to channels: {self.connected_channels}") async def event_message(self, message): """Called for every message in chat""" # Ignore messages from the bot itself if message.echo: return # Print all messages for debugging (optional) print(f"{message.author.name}: {message.content}") if message.content.startswith(TAG_INDICATOR_CHAR): new_tag = message.content[1:] if not new_tag: return if new_tag not in self.pending_tags: self.pending_tags[new_tag] = 0 self.pending_tags[new_tag] += 1 print(f"Current tags: {self.pending_tags}") await message.channel.send(f"Added tag: {new_tag}") def get_and_reset_tags(self): print(f"Getting {MAX_NUM_TAGS_TO_SEND} most requested tags...") if len(self.pending_tags) < MAX_NUM_TAGS_TO_SEND: tags_to_send = list(self.pending_tags.keys()) else: tags_to_send = [] for i in range(MAX_NUM_TAGS_TO_SEND): max_count_tag = None max_count = 0 for tag in self.pending_tags: if tag not in tags_to_send and self.pending_tags[tag] > max_count: max_count = self.pending_tags[tag] max_count_tag = tag tags_to_send.append(max_count_tag) print(f"Tags to send: {tags_to_send}") self.sent_tag_history.append(tags_to_send[:]) self.pending_tags = {} print("Pending tags has been reset.") return tags_to_send def write_to_streamlit(self, string): print(f"Printed to Streamlit: {string}") st.write(string) def thread_main(thing1): asyncio.run(async_thread_main(thing1)) async def async_thread_main(thing1): bot = SongBot() thing1.append(bot) await bot.start() async def main(): thing1 = [] threading.Thread(target=thread_main, daemon=True, args=(thing1,)).start() st.write("# LET'S A-GOOOOO!") col1, col2 = st.columns(2) tags = col1.empty() tag_history = col1.empty() instructions = col2.empty() pending_tags_leaderboard = col2.empty() instructions.markdown( f""" **Welcome to the greatest unending playlist in existence!** * Control the style of the music by sending tags in chat. * Send a tag by typing #TAGNAME in chat! For example: #pop, #rock, #happy, #kawaii future bass, #metal, etc. * Every {TAG_SEND_INTERVAL} seconds, the top {MAX_NUM_TAGS_TO_SEND} most requested tags will be sent to Suno and used to continue the song. * Sit back and enjoy the music! """ ) timestamp = datetime.datetime.now() timestamp2 = datetime.datetime.now() while True: # Send top 5 tags on a time interval if datetime.datetime.now() - timestamp > datetime.timedelta( seconds=TAG_SEND_INTERVAL ): assert len(thing1) > 0 # makes sure our bot exists # TODO: this is where we should send the tags to backend sent_tags = thing1[0].get_and_reset_tags() tags_joined = f"{', '.join(sent_tags)}" if not tags_joined: tags_joined = "(no tags sent)" tags.markdown( f"**Most recent {MAX_NUM_TAGS_TO_SEND} tags sent:** {tags_joined}" ) if len(thing1[0].sent_tag_history) > 1: tag_history_str = "" for tag_list in thing1[0].sent_tag_history[-2::-1]: tags_joined = f"{', '.join(tag_list)}" if not tags_joined: tags_joined = "(no tags sent)" tag_history_str += f"{tags_joined} \n" tag_history.markdown(f"**History:** \n {tag_history_str.strip()}") timestamp = datetime.datetime.now() # Update leaderboard every second elif datetime.datetime.now() - timestamp2 > datetime.timedelta(seconds=1): leaderboard_tags = [] leaderboard_counts = [] for i in range(min(NUM_LEADERBOARD_TAGS, len(thing1[0].pending_tags))): max_count_tag = None max_count = 0 for tag in thing1[0].pending_tags: if ( tag not in leaderboard_tags and thing1[0].pending_tags[tag] > max_count ): max_count = thing1[0].pending_tags[tag] max_count_tag = tag leaderboard_tags.append(max_count_tag) leaderboard_counts.append(max_count) leaderboard_str = "" for i in range(len(leaderboard_tags)): leaderboard_str += ( f"{leaderboard_tags[i]} ({leaderboard_counts[i]} votes) \n" ) if not leaderboard_str: leaderboard_str = "(no tags requested yet)" pending_tags_leaderboard.markdown( f"**Top {NUM_LEADERBOARD_TAGS} tags:** \n {leaderboard_str.strip()}" ) timestamp2 = datetime.datetime.now() # Run the bot if __name__ == "__main__": # bot = SongBot() # threading.Thread(target=thread_main, daemon=True, args=(bot,)).start() # asyncio.run(bot.start()) asyncio.run(main())