import argparse import glob from pathlib import Path import random import string import subprocess from typing import Any, Dict, List def get_args() -> Dict[str, Any]: parser = argparse.ArgumentParser( prog='video_to_gif.py', description='Use ffmpeg to make GIFs from videos', epilog='— Be gay and do crime') parser.add_argument('-i', '--input', type=str, required=True, help="Input pattern like '/users/MyName/Videos/*.mov'") parser.add_argument('-w', '--width', type=str, default='960', help='Width of the GIF in pixels, respecting aspect ratio') parser.add_argument('-r', '--framerate', type=str, default='12', help='Framerate of GIF') parser.add_argument('-t', '--tag', type=str, default=get_tag(), help='Optional tag included in file name') return vars(parser.parse_args()) def get_tag() -> str: return ''.join(random.choices(string.ascii_uppercase + string.digits, k=5)) def get_inputs(args: Dict[str, Any]) -> List[str]: return glob.glob(args['input']) def call_ffmpeg(command: str) -> str: print("ffmpeg", *command.split(' ')) return str(subprocess.run(["ffmpeg", '-hide_banner', '-loglevel', 'error', *command.split(' ')])) def generate_gif_files(inputs: List[str], args: Dict[str, Any]) -> Dict[str, str]: tag = args['tag'] width = args['width'] framerate = args['framerate'] output_map = {} for input in inputs: file_name = f"{Path(input).stem}_{tag}.gif" full_path = f"{Path(input).parent}/{file_name}" call_ffmpeg(f"-i {input} -f gif -r {framerate} -filter_complex scale={ \ width}:-1:flags=lanczos,split[v1][v2];[v1]palettegen[plt];[v2][plt]paletteuse {full_path}") output_map[input] = full_path return output_map def make_gifs(args: Dict[str, Any]) -> None: inputs = get_inputs(args) output_map = generate_gif_files(inputs, args) for input in output_map: print(f"Created {output_map[input]} from {input}") def main() -> None: make_gifs(get_args()) return if __name__ == '__main__': main()