TwitchDownloader/run_chat_only.py

147 lines
6.2 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""
Start chat downloader standalone for testing without recording video.
Usage:
python run_chat_only.py --username vinesauce [--output path] [--max-messages N] [--timeout S] [--verbose]
This script uses the project's `ConfigManager` and `FileManager` to create
appropriate directories and then starts the chat downloader in a background
thread. Press Ctrl+C to stop.
"""
import argparse
import time
from datetime import datetime
import os
from colorama import Fore, Style
from modules.config import ConfigManager
from modules.file_manager import FileManager
from modules.utils import get_ffmpeg_executable, get_twitch_downloader_executable, detect_operating_system
from modules.downloader import ContentDownloader
from modules.stream_monitor import StreamMonitor
def main():
parser = argparse.ArgumentParser(description='Run chat downloader standalone for testing')
parser.add_argument('--username', '-u', required=True, help='Twitch username/channel name')
parser.add_argument('--output', '-o', help='Output JSON path (optional)')
parser.add_argument('--max-messages', type=int, default=None, help='Max messages to capture')
parser.add_argument('--timeout', type=float, default=None, help='Timeout in seconds')
parser.add_argument('--verbose', action='store_true', help='Show verbose/chat previews')
parser.add_argument('--foreground', action='store_true', help='Run downloader in foreground (blocking)')
parser.add_argument('--use-chat-downloader-primary', action='store_true', help='Use chat_downloader as primary method')
parser.add_argument('--use-chat-downloader-fallback', dest='use_chat_downloader_fallback', action='store_true', help='Allow chat_downloader as fallback (default)')
parser.add_argument('--no-chat-downloader-fallback', dest='use_chat_downloader_fallback', action='store_false', help='Disable chat_downloader fallback')
args = parser.parse_args()
cfg = ConfigManager()
config = cfg.load_streamer_config(args.username)
# Apply overrides from CLI
if args.use_chat_downloader_primary:
config['useChatDownloaderPrimary'] = True
if args.use_chat_downloader_fallback is not None:
config['useChatDownloaderFallback'] = bool(args.use_chat_downloader_fallback)
# Ensure directories exist (use configured archive root path)
fm = FileManager(root_path=config.get('root_path', 'archive'), username=args.username, config=config)
fm.initialize_directories()
# Build default output path if not provided
if args.output:
json_path = args.output
else:
ts = datetime.now().strftime('%Y%m%d_%Hh%Mm%Ss')
json_path = str(fm.chat_json_path / f"CHAT_TEST_{args.username}_{ts}.json")
# Initialize downloader
os_type = detect_operating_system()
twitch_downloader_path = get_twitch_downloader_executable(os_type)
ffmpeg_path = get_ffmpeg_executable(os_type)
downloader = ContentDownloader(twitch_downloader_path=twitch_downloader_path,
ffmpeg_path=ffmpeg_path,
config=config)
print(f"{Fore.CYAN}Starting standalone chat downloader for {args.username}{Style.RESET_ALL}")
print(f"Output path: {json_path}")
stop_requested = {'stop': False}
def shutdown_check():
return stop_requested['stop']
# Prepare stream monitor
stream_monitor = StreamMonitor(args.username)
# If chat downloads are disabled in config, enter monitoring mode instead
if not downloader.download_live_chat:
print(f"{Fore.YELLOW}⚠ downloadLiveCHAT is disabled in config - entering monitoring mode for {args.username}{Style.RESET_ALL}")
try:
while True:
try:
is_live = stream_monitor.is_user_live()
if is_live:
print(f"{Fore.GREEN}{args.username} is live! Exiting monitor. Run the archiver to record video.{Style.RESET_ALL}")
break
else:
print(f"{Fore.CYAN}{args.username} is offline - checking again in 30s...{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}⚠ Could not check stream status: {e}{Style.RESET_ALL}")
time.sleep(30)
except KeyboardInterrupt:
print('\nKeyboard interrupt received; stopping monitor...')
return
# If chat download is enabled, but the stream is currently offline, wait until it goes live
try:
try:
if not stream_monitor.is_user_live():
print(f"{Fore.CYAN}{args.username} is currently offline - waiting for live stream to start...{Style.RESET_ALL}")
while not stream_monitor.is_user_live():
time.sleep(10)
except Exception:
# If we cannot determine live status, proceed to start chat downloader anyway
pass
except KeyboardInterrupt:
print('\nKeyboard interrupt received; exiting...')
return
# Start thread (stream_monitor passed so downloader can stop when stream ends)
thread = downloader.start_chat_downloader_thread(
args.username,
json_path,
shutdown_check=shutdown_check,
stream_monitor=stream_monitor,
verbose=args.verbose
)
try:
if args.foreground:
# Run download directly in foreground
print('Running in foreground; this will block until download completes or interrupted')
success = downloader.download_live_chat_with_chat_downloader(
args.username,
json_path,
max_messages=args.max_messages,
timeout=args.timeout,
shutdown_check=shutdown_check,
stream_monitor=None,
verbose=args.verbose
)
print('Done, success=' + str(success))
else:
# Wait for thread to finish or until interrupted
while thread.is_alive():
time.sleep(0.5)
except KeyboardInterrupt:
print('\nKeyboard interrupt received; stopping downloader...')
stop_requested['stop'] = True
thread.join(timeout=5)
if __name__ == '__main__':
main()