feat: enhance chat downloading with stream monitoring and improved file paths

This commit is contained in:
MaddoScientisto 2026-02-18 18:11:53 +01:00
commit b47641feaa
3 changed files with 87 additions and 30 deletions

View file

@ -506,6 +506,16 @@ class ContentDownloader:
print(f'{Fore.YELLOW}⚠ downloadLiveCHAT is disabled in config{Style.RESET_ALL}')
return False
# If a stream monitor was provided, check that the user is currently live
if stream_monitor is not None:
try:
if not stream_monitor.is_user_live():
print(f'{Fore.YELLOW}⚠ Stream is not live; skipping chat download{Style.RESET_ALL}')
return False
except Exception as e:
# If we couldn't determine live status, continue and let chat_downloader handle it
print(f'{Fore.YELLOW}⚠ Could not determine live status: {e} - proceeding with chat download{Style.RESET_ALL}')
print(f'\n{Fore.CYAN}Starting live chat download (chat_downloader)...{Style.RESET_ALL}')
print(f'{Fore.MAGENTA}[VERBOSE] chat_downloader library version: {ChatDownloader.__module__}{Style.RESET_ALL}')

View file

@ -130,45 +130,54 @@ class FileManager:
files_to_upload = []
# Always include metadata and chat JSON
files_to_upload.append(f"{PREFIX_METADATA}{filename_base}.json")
files_to_upload.append(f"{PREFIX_CHAT}{filename_base}.json")
# Build files list relative to root_path so rclone can read them with --files-from
# Metadata and chat JSON
files_to_upload.append(os.path.join(self.username, 'metadata', f"{PREFIX_METADATA}{filename_base}.json"))
files_to_upload.append(os.path.join(self.username, 'chat', 'json', f"{PREFIX_CHAT}{filename_base}.json"))
# Add pre-merge videos (original LIVE and VOD files)
# Pre-merge videos (raw .ts in video/raw, mp4/mp3 in video)
if self.upload_pre_merge_video:
files_to_upload.extend([
f"{PREFIX_LIVE}{filename_base}.ts",
f"{PREFIX_LIVE}{filename_base}.mp4",
f"{PREFIX_LIVE}{filename_base}.mp3",
f"{PREFIX_VOD}{filename_base}.ts",
f"{PREFIX_VOD}{filename_base}.mp4",
f"{PREFIX_VOD}{filename_base}.mp3"
os.path.join(self.username, 'video', 'raw', f"{PREFIX_LIVE}{filename_base}.ts"),
os.path.join(self.username, 'video', f"{PREFIX_LIVE}{filename_base}.mp4"),
os.path.join(self.username, 'video', f"{PREFIX_LIVE}{filename_base}.mp3"),
os.path.join(self.username, 'video', 'raw', f"{PREFIX_VOD}{filename_base}.ts"),
os.path.join(self.username, 'video', f"{PREFIX_VOD}{filename_base}.mp4"),
os.path.join(self.username, 'video', f"{PREFIX_VOD}{filename_base}.mp3")
])
# Add merged videos
# Merged videos (in video folder)
if self.upload_merged_video:
files_to_upload.extend([
f"{PREFIX_MERGED}{filename_base}.mp4",
f"{PREFIX_MERGED}{filename_base}.mp3",
f"{PREFIX_MERGED}{PREFIX_VOD}{filename_base}.mp4",
f"{PREFIX_MERGED}{PREFIX_VOD}{filename_base}.mp3"
os.path.join(self.username, 'video', f"{PREFIX_MERGED}{filename_base}.mp4"),
os.path.join(self.username, 'video', f"{PREFIX_MERGED}{filename_base}.mp3"),
os.path.join(self.username, 'video', f"{PREFIX_MERGED}{PREFIX_VOD}{filename_base}.mp4"),
os.path.join(self.username, 'video', f"{PREFIX_MERGED}{PREFIX_VOD}{filename_base}.mp3")
])
# Add standalone chat video
# Standalone chat video (in chat folder)
if self.upload_chat_video:
files_to_upload.append(f"{PREFIX_CHAT}{filename_base}.mp4")
files_to_upload.append(os.path.join(self.username, 'chat', f"{PREFIX_CHAT}{filename_base}.mp4"))
with open(upload_list_path, 'w') as f:
f.write('\n'.join(files_to_upload))
# Run rclone
# Run rclone using --files-from so the listed paths (relative to root_path) are uploaded.
try:
result = subprocess.call([
cmd = [
'rclone', 'copy',
str(self.root_path.resolve()),
self.rclone_path,
'--include-from', upload_list_path
])
'--files-from', upload_list_path
]
# Stream rclone output to console so user can see progress/errors
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
if proc.stdout:
for line in proc.stdout:
print(line, end='')
proc.wait()
result = proc.returncode
# Clean up upload list
if os.path.exists(upload_list_path):

View file

@ -20,6 +20,7 @@ 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():
@ -72,12 +73,49 @@ def main():
def shutdown_check():
return stop_requested['stop']
# Start thread
# 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=None,
stream_monitor=stream_monitor,
verbose=args.verbose
)