#!/usr/bin/env python import math import sys from os import name from pathlib import Path from subprocess import Popen from typing import Dict, NoReturn # Reddit pipeline disabled — Threads is the active source. # from reddit.subreddit import get_subreddit_threads from threads.threads_api import get_threads_posts from utils import settings from utils.cleanup import cleanup from utils.checkpoint import run_step, save_checkpoint, load_checkpoint, clear_checkpoint, print_resume_status from utils.console import print_markdown, print_step, print_substep from utils.ffmpeg_install import ffmpeg_install from utils.id import extract_id from utils.version import checkversion from video_creation.background import ( chop_background, download_background_audio, download_background_video, get_background_config, ) from video_creation.final_video import make_final_video from video_creation.screenshot_downloader import get_screenshots_of_reddit_posts from video_creation.voices import save_text_to_mp3 __VERSION__ = "3.4.0" print( """ ██████╗ ███████╗██████╗ ██████╗ ██╗████████╗ ██╗ ██╗██╗██████╗ ███████╗ ██████╗ ███╗ ███╗ █████╗ ██╗ ██╗███████╗██████╗ ██╔══██╗██╔════╝██╔══██╗██╔══██╗██║╚══██╔══╝ ██║ ██║██║██╔══██╗██╔════╝██╔═══██╗ ████╗ ████║██╔══██╗██║ ██╔╝██╔════╝██╔══██╗ ██████╔╝█████╗ ██║ ██║██║ ██║██║ ██║ ██║ ██║██║██║ ██║█████╗ ██║ ██║ ██╔████╔██║███████║█████╔╝ █████╗ ██████╔╝ ██╔══██╗██╔══╝ ██║ ██║██║ ██║██║ ██║ ╚██╗ ██╔╝██║██║ ██║██╔══╝ ██║ ██║ ██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗ ██║ ██║███████╗██████╔╝██████╔╝██║ ██║ ╚████╔╝ ██║██████╔╝███████╗╚██████╔╝ ██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗██║ ██║ ╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ """ ) print_markdown( "### Thanks for using this tool! Feel free to contribute to this project on GitHub! If you have any questions, feel free to join my Discord server or submit a GitHub issue. You can find solutions to many common problems in the documentation: https://reddit-video-maker-bot.netlify.app/" ) checkversion(__VERSION__) reddit_id: str reddit_object: Dict[str, str | list] def main(POST_URL=None) -> None: global reddit_id, reddit_object # Step 1: Fetch Threads post (no checkpoint — thread_id unknown yet) reddit_object = get_threads_posts(POST_URL) reddit_id = extract_id(reddit_object) print_substep(f"Thread ID is {reddit_id}", style="bold blue") save_checkpoint(reddit_id, "fetch_thread", {"result": None}) print_resume_status(reddit_id) # Step 2: Generate TTS audio tts_result = run_step( reddit_id, "generate_tts", save_text_to_mp3, reddit_object, ) length, number_of_comments = tts_result[0], tts_result[1] length = math.ceil(length) # Step 3: Take screenshots run_step( reddit_id, "take_screenshots", get_screenshots_of_reddit_posts, reddit_object, number_of_comments, ) # Step 4: Download background video & audio bg_config = { "video": get_background_config("video"), "audio": get_background_config("audio"), } run_step( reddit_id, "download_background", _download_backgrounds, bg_config, ) # Step 5: Chop background run_step( reddit_id, "chop_background", chop_background, bg_config, length, reddit_object, ) # Step 6: Make final video run_step( reddit_id, "make_final_video", make_final_video, number_of_comments, length, reddit_object, bg_config, ) # Pipeline complete — clear checkpoint clear_checkpoint(reddit_id) print_step("Pipeline completed successfully! Checkpoint cleared.") def _download_backgrounds(bg_config): download_background_video(bg_config["video"]) download_background_audio(bg_config["audio"]) def run_many(times) -> None: for x in range(1, times + 1): print_step( f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")[x % 10]} iteration of {times}' ) main() Popen("cls" if name == "nt" else "clear", shell=True).wait() def shutdown() -> NoReturn: if "reddit_id" in globals(): print_markdown("## Clearing temp files") cleanup(reddit_id) print("Exiting...") sys.exit() if __name__ == "__main__": if sys.version_info.major != 3 or sys.version_info.minor not in [10, 11, 12]: print( "Hey! Congratulations, you've made it so far (which is pretty rare with no Python 3.10). Unfortunately, this program only works on Python 3.10. Please install Python 3.10 and try again." ) sys.exit() ffmpeg_install() directory = Path().absolute() config = settings.check_toml( f"{directory}/utils/.config.template.toml", f"{directory}/config.toml" ) config is False and sys.exit() if ( not settings.config["settings"]["tts"]["tiktok_sessionid"] or settings.config["settings"]["tts"]["tiktok_sessionid"] == "" ) and config["settings"]["tts"]["voice_choice"] == "tiktok": print_substep( "TikTok voice requires a sessionid! Check our documentation on how to obtain one.", "bold red", ) sys.exit() try: threads_post_id = ( config.get("threads", {}).get("thread", {}).get("post_id", "") if isinstance(config.get("threads", {}), dict) else "" ) if threads_post_id: for index, post_id in enumerate(threads_post_id.split("+")): index += 1 print_step( f'on the {index}{("st" if index % 10 == 1 else ("nd" if index % 10 == 2 else ("rd" if index % 10 == 3 else "th")))} post of {len(threads_post_id.split("+"))}' ) main(post_id) Popen("cls" if name == "nt" else "clear", shell=True).wait() elif config["settings"]["times_to_run"]: run_many(config["settings"]["times_to_run"]) else: main() except KeyboardInterrupt: shutdown() except Exception as err: config["settings"]["tts"]["tiktok_sessionid"] = "REDACTED" config["settings"]["tts"]["elevenlabs_api_key"] = "REDACTED" config["settings"]["tts"]["openai_api_key"] = "REDACTED" print_step( f"Sorry, something went wrong with this version! Try again, and feel free to report this issue at GitHub or the Discord community.\n" f"Version: {__VERSION__} \n" f"Error: {err} \n" f'Config: {config["settings"]}' ) raise err