import sys import json import subprocess import os import argparse import traceback def download_and_crop(url, output_dir, start_time=None, end_time=None): print(f"[DEBUG Worker] Starting download job for URL={url}, start={start_time}, end={end_time}", file=sys.stderr) try: os.makedirs(output_dir, exist_ok=True) # Get video info info_cmd = ["yt-dlp", "-J", url] print(f"[DEBUG Worker] Running info command: {' '.join(info_cmd)}", file=sys.stderr) result = subprocess.run(info_cmd, capture_output=True, text=True, check=True) info = json.loads(result.stdout) # We will download the best single file with audio and video, or just let yt-dlp decide video_id = info.get("id", "unknown") title = info.get("title", "video").replace("/", "_").replace("\\", "_") # Ensure ascii or keep some safe unicode safe_title = "".join([c for c in title if c.isalpha() or c.isdigit() or c in (' ', '-', '_')]).rstrip() filename = f"{safe_title}_{video_id}.mp4" filepath = os.path.join(output_dir, filename) # Construct download options # We use ffmpeg to crop if start/end times are provided if start_time or end_time: # Using yt-dlp's native download range features to avoid full download if possible # OR pass postprocessor args download_args = [ "yt-dlp", "-f", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", "--merge-output-format", "mp4", "-o", filepath, ] post_args = [] if start_time: post_args.extend(["-ss", start_time]) if end_time: post_args.extend(["-to", end_time]) if post_args: download_args.extend(["--downloader", "ffmpeg", "--downloader-args", f"ffmpeg:{' '.join(post_args)}"]) download_args.append(url) else: download_args = [ "yt-dlp", "-f", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", "--merge-output-format", "mp4", "-o", filepath, url ] # Execute print(f"[DEBUG Worker] Executing download command: {' '.join(download_args)}", file=sys.stderr) subprocess.run(download_args, check=True) print(json.dumps({"status": "success", "filepath": filepath, "title": title})) return True except subprocess.CalledProcessError as e: print(f"[DEBUG Worker] Command Error Output: {e.stderr or e.output}", file=sys.stderr) print(json.dumps({"status": "error", "message": f"Command failed: {e.stderr or e.output}"})) return False except Exception as e: print(f"[DEBUG Worker] Unexpected Exception:", file=sys.stderr) traceback.print_exc() print(json.dumps({"status": "error", "message": str(e)})) return False if __name__ == "__main__": parser = argparse.ArgumentParser(description="Download and crop media via yt-dlp") parser.add_argument("--url", required=True, help="Media URL") parser.add_argument("--outdir", required=True, help="Output directory") parser.add_argument("--start", help="Start time (hh:mm:ss)") parser.add_argument("--end", help="End time (hh:mm:ss)") args = parser.parse_args() download_and_crop(args.url, args.outdir, args.start, args.end)