import pytchat import sys import os import time import re import json from datetime import datetime from rich.console import Console from rich.style import Style console = Console() # Define the emoji pattern and coloring function emoji_pattern = re.compile( r""" ( U0001F600-U0001F64F # emoticons U0001F300-U0001F5FF # symbols & pictographs U0001F680-U0001F6FF # transport & map symbols U0001F1E0-U0001F1FF # flags (iOS) U2702-U27B0 # Dingbats U24C2-U2B55 # Enclosed characters U0001F900-U0001F9FF # Supplemental Symbols & Pictographs U200D # ZWJ UFE0F # VS-16 )+""" , re.UNICODE | re.VERBOSE) def colour_emoji(txt): return emoji_pattern.sub(r'[magenta]\1[/magenta]', txt) # --- User Color Management --- USER_COLORS_FILE = "user_colors.json" # A palette of distinct colors for usernames COLOR_PALETTE = [ "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#00FFFF", "#FF00FF", "#FFA500", "#800080", "#008000", "#FFC0CB", "#808000", "#008080", "#C0C0C0", "#800000", "#000080", "#FFD700", "#ADFF2F", "#FF69B4" ] user_color_map = {} def load_user_colors(): global user_color_map if os.path.exists(USER_COLORS_FILE): with open(USER_COLORS_FILE, 'r') as f: user_color_map = json.load(f) def save_user_colors(): with open(USER_COLORS_FILE, 'w') as f: json.dump(user_color_map, f, indent=4) def get_user_color(author_id): global user_color_map if author_id not in user_color_map: # Assign a new color from the palette # Cycle through colors, or pick randomly if palette is exhausted next_color_index = len(user_color_map) % len(COLOR_PALETTE) user_color_map[author_id] = COLOR_PALETTE[next_color_index] save_user_colors() # Save immediately after assigning a new color return user_color_map[author_id] # --- Main Script Logic --- def main(): # Clear the terminal screen os.system('clear') video_id = input("Enter the YouTube Live Stream Video ID: ") # Setup chat logging log_dir = "chat_logs" os.makedirs(log_dir, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") log_filename = os.path.join(log_dir, f"chat_{video_id}_{timestamp}.log") log_file = open(log_filename, "w", encoding="utf-8") console.print(f"[green]Chat will be logged to {log_filename}[/green]") # Load existing user colors load_user_colors() try: livechat = pytchat.create(video_id=video_id) console.print(f"[green]Listening to live chat for video ID: {video_id}[/green]") console.print(f"[green]Video ID accepted: {video_id}[/green]") # Wait for 5 seconds, then clear the screen time.sleep(5) os.system('clear') message_count = 0 while livechat.is_alive(): for c in livechat.get().sync_items(): author_display_name = c.author.name # pytchat provides author.channelId, which is perfect for unique identification author_channel_id = c.author.channelId message_text = c.message # Process text-based emotes (e.g., :face-purple-sweating:) message_text = re.sub(r'(:[a-zA-Z0-9_-]+:)', r'[blue]\1[/blue]', message_text) # Apply emoji coloring using the new function message_text = colour_emoji(message_text) # Get persistent color for the user user_color = get_user_color(author_channel_id) username_style = Style(color=user_color, bold=True) # Format message for terminal formatted_message = f"[{username_style}]{author_display_name}[/]: {message_text}" # Calculate padding to fill terminal width rendered_length = console.measure(formatted_message).maximum padding = max(0, console.width - rendered_length) padded_message = f"{formatted_message}{' ' * padding}" # Alternate background styles background_style = Style(bgcolor="#2B2B2B") if message_count % 2 == 0 else Style(bgcolor="#3A3A3A") console.print(padded_message, style=background_style, overflow="crop") log_file.write(f"{datetime.now().strftime("%H:%M:%S")} {formatted_message}\n") message_count += 1 except Exception as e: console.print(f"[red]An error occurred: {e}[/red]") finally: log_file.close() save_log = input(f"\nDo you want to save the chat log to {log_filename}? (y/n): ").lower() if save_log != 'y' and save_log != 'yes': os.remove(log_filename) console.print(f"[red]Chat log not saved. {log_filename} deleted.[/red]") else: console.print(f"[green]Chat log saved to {log_filename}[/green]") if __name__ == '__main__': main()