import subprocess import os from datetime import datetime import concurrent.futures formats = "18" cookies_file = "cookies.txt" output_template = "%(id)s/%(id)s.f%(format_id)s.%(ext)s" output_infojson = "infojson:%(id)s/%(id)s.t%(duration_string)s.%(ext)s" paths = "~/Downloads/staging" paths_temp = "temp:~/Downloads/temp" cache_dir = "~/Downloads/cache" ffmpeg_location = "~/" num_threads = 16 url_file = "video_urls.txt" log_file = "download_log.txt" successful_downloads_file = "successful_downloads.txt" failed_downloads_file = "failed_downloads.txt" def load_downloaded_urls(file): if os.path.exists(file): with open(file, "r") as f: return set(line.strip() for line in f if line.strip()) return set() def save_downloaded_url(file, url): with open(file, "a") as f: f.write(f"{url}\n") def download_video(url): if url in successful_downloads: print(f"Video {url} already downloaded. Skipping.") return if url in failed_downloads: print(f"Video {url} previously failed. Retrying.") start_time = datetime.now() try: command = [ "yt-dlp", "--paths", paths, "--paths", paths_temp, "--cache-dir", cache_dir, "--ffmpeg-location", ffmpeg_location, "--format", formats, "--cookies", cookies_file, "--output", output_template, "--output", output_infojson, "--ignore-config", "--no-progress", "--write-info-json", url ] print(f"Start: {' '.join(command)}") result = subprocess.run(command, check=True, capture_output=True, text=True) end_time = datetime.now() log_download(url, start_time, end_time) save_downloaded_url(successful_downloads_file, url) except subprocess.CalledProcessError as e: error_message = e.stderr if e.stderr else str(e) print(f"ERROR VIDEO {url}: {error_message}") if "This video has been removed" in error_message or "Video unavailable" in error_message: save_downloaded_url(failed_downloads_file, url) if "Sign in to confirm youre not a bot" in error_message: print("Critical error detected: Sign-in required. Stopping execution.") exit(1) def log_download(url, start_time, end_time): with open(log_file, "a") as log: log.write(f"{url} Download.\nStart: {start_time}\nEnd: {end_time}\n\n") if not os.path.exists(url_file): print(f"File {url_file} Empty.") exit(1) successful_downloads = load_downloaded_urls(successful_downloads_file) failed_downloads = load_downloaded_urls(failed_downloads_file) with open(url_file, "r") as file: video_urls = [line.strip() for line in file if line.strip()] video_urls = [url for url in video_urls if url not in successful_downloads] os.makedirs(os.path.expanduser("~/Downloads/staging"), exist_ok=True) os.makedirs(os.path.expanduser("~/Downloads/temp"), exist_ok=True) os.makedirs(os.path.expanduser("~/Downloads/cache"), exist_ok=True) with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor: futures = [executor.submit(download_video, url) for url in video_urls] for future in concurrent.futures.as_completed(futures): try: future.result() except Exception as e: print(f"ERROR: {e}")