feat: enhance chat downloading with stream monitoring and improved file paths
This commit is contained in:
parent
22a1f5b600
commit
b47641feaa
3 changed files with 87 additions and 30 deletions
|
|
@ -505,6 +505,16 @@ class ContentDownloader:
|
|||
if not self.download_live_chat:
|
||||
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}')
|
||||
|
|
|
|||
|
|
@ -129,51 +129,60 @@ class FileManager:
|
|||
os.makedirs(os.path.dirname(upload_list_path), exist_ok=True)
|
||||
|
||||
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")
|
||||
|
||||
# Add pre-merge videos (original LIVE and VOD files)
|
||||
|
||||
# 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"))
|
||||
|
||||
# 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):
|
||||
os.remove(upload_list_path)
|
||||
|
||||
|
||||
if result == 0:
|
||||
print(f'{Fore.GREEN}✓ Upload complete{Style.RESET_ALL}')
|
||||
if notification_callback:
|
||||
|
|
@ -186,7 +195,7 @@ class FileManager:
|
|||
notification_callback(f'✗ Upload Failed - {filename_base}',
|
||||
f'Upload failed with code {result}. Files preserved locally.')
|
||||
return False
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f'{Fore.RED}✗ Upload error: {str(e)}{Style.RESET_ALL}')
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue