From 865330db76c8eb311b5620319c7de484a0740900 Mon Sep 17 00:00:00 2001 From: Ramforth Date: Thu, 30 Oct 2025 19:26:29 +0100 Subject: [PATCH] Implement persistent unique colors for chatters --- pytchat_listener.py | 72 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/pytchat_listener.py b/pytchat_listener.py index bcf94b2..a2d27a7 100644 --- a/pytchat_listener.py +++ b/pytchat_listener.py @@ -3,6 +3,7 @@ import sys import os import time import re +import json from datetime import datetime from rich.console import Console from rich.style import Style @@ -11,21 +12,56 @@ console = Console() # Define the emoji pattern and coloring function emoji_pattern = re.compile( - r'(' - r'\U0001F600-\U0001F64F' # emoticons - r'\U0001F300-\U0001F5FF' # symbols & pictographs - r'\U0001F680-\U0001F6FF' # transport & map symbols - r'\U0001F1E0-\U0001F1FF' # flags (iOS) - r'\u2702-\u27B0' # Dingbats - r'\u24C2-\u2B55' # Enclosed characters - r'\U0001F900-\U0001F9FF' # Supplemental Symbols & Pictographs - r'\u200D' # ZWJ - r'\uFE0F' # VS-16 - r')+', flags=re.UNICODE) + 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') @@ -40,6 +76,9 @@ def main(): 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]") @@ -53,6 +92,8 @@ def main(): 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:) @@ -61,15 +102,14 @@ def main(): # Apply emoji coloring using the new function message_text = colour_emoji(message_text) - # Simple color for username (can be expanded to unique colors per user) - username_style = Style(color="#4CAF50", bold=True) + # 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 - # rich handles rendering, so we need to calculate the visible width of the string - # and pad it. This is a simplified approach, rich's Panel might be better for complex layouts. rendered_length = console.measure(formatted_message).maximum padding = max(0, console.width - rendered_length) padded_message = f"{formatted_message}{' ' * padding}" @@ -93,4 +133,4 @@ def main(): console.print(f"[green]Chat log saved to {log_filename}[/green]") if __name__ == '__main__': - main() \ No newline at end of file + main()