#! /usr/bin/env python3 import argparse import sys import logging import subprocess from datetime import datetime from pathlib import Path logger = logging.getLogger(__name__) def main() -> int: # Handle program arguments ap = argparse.ArgumentParser( prog="blink-timelapse", description="Generates timelapses from blink image captures", ) ap.add_argument("--camera-id", help="Camera ID", default="155295") ap.add_argument("--image-dir", help="Image directory", default="~/Pictures/blink") ap.add_argument( "--output-dir", help="Output directory", default="~/Videos/BlinkTimelapse" ) ap.add_argument( "--delete-frames", help="Delete frames after processing", action="store_true" ) ap.add_argument("--frame-rate", help="Frame rate", default="5") ap.add_argument( "-v", "--verbose", help="Enable verbose logging", action="store_true" ) args = ap.parse_args() # Configure logging logging.basicConfig( level=logging.DEBUG if args.verbose else logging.INFO, format="%(levelname)s: %(message)s", ) # Find all frames image_dir = Path(args.image_dir).expanduser() frames = image_dir.glob(f"camera_{args.camera_id}.*.jpg") frames = sorted(frames, key=lambda frame: frame.stat().st_mtime) logger.info(f"Found {len(frames)} frames") logger.info( f"Oldest frame is from: {datetime.fromtimestamp(frames[0].stat().st_mtime)}" ) logger.info( f"Newest frame is from: {datetime.fromtimestamp(frames[-1].stat().st_mtime)}" ) # Create output directory output_dir = Path(args.output_dir).expanduser() output_file = output_dir / f"camera_{args.camera_id}.{datetime.now().strftime('%Y%m%d-%H%M%S')}.mp4" output_dir.mkdir(parents=True, exist_ok=True) # Generate timelapse logger.info(f"Generating timelapse: {output_file}") subprocess.run( [ "ffmpeg", "-r", args.frame_rate, "-pattern_type", "glob", "-i", f"{str(image_dir)}/camera_{args.camera_id}.*.jpg", "-c:v", "libx264", "-pix_fmt", "yuv420p", str(output_file), ], check=True, ) # Delete frames if needed if args.delete_frames: logger.info("Deleting frames") for frame in frames: frame.unlink() return 0 if __name__ == "__main__": sys.exit(main())