From 15a376416bc0c3c1e83480ed487862a772d83b52 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Mon, 27 Nov 2023 16:54:37 -0500 Subject: [PATCH] Add a timelapse script --- scripts/blink-fetch | 1 + scripts/blink-timelapse | 84 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100755 scripts/blink-timelapse diff --git a/scripts/blink-fetch b/scripts/blink-fetch index 2eda59e..31d9312 100755 --- a/scripts/blink-fetch +++ b/scripts/blink-fetch @@ -1,4 +1,5 @@ #! /usr/bin/env python3 +# Installation: pip install exif asyncio blinkpy import argparse import sys import logging diff --git a/scripts/blink-timelapse b/scripts/blink-timelapse new file mode 100755 index 0000000..a1e0c4a --- /dev/null +++ b/scripts/blink-timelapse @@ -0,0 +1,84 @@ +#! /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="/tmp/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 + frames = Path(args.image_dir).expanduser().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"{args.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())