Files
youtube-chat-webhook-v2/pytchat_listener.py

137 lines
4.9 KiB
Python

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()