#!/usr/bin/env python3 # call pyvideothumbnailer for every video file found # # calculates rows based on the duration of the video import math import os import subprocess import click from pymediainfo import MediaInfo VERBOSE = False def is_video_file(video_file_path, video_extensions): return video_file_path.lower().endswith(tuple(video_extensions)) def find_video_files(directory, video_extensions): # Recursively walk through directory for dirpath, dirs, files in os.walk(directory): for filename in files: filename_path = os.path.join(dirpath, filename) if is_video_file(filename_path, video_extensions): yield os.path.abspath(filename_path) def get_video_duration(video_file_path): # Get media information media_info = MediaInfo.parse(video_file_path) # Iterate through tracks in the media file for track in media_info.tracks: # If the track type is video if track.track_type == "Video": # Get duration and return it duration_str = track.duration duration_sec = float(duration_str) / 1000 # Convert to seconds return duration_sec # Return None if no video track found return None def call_thumbnailer(video_file, width, rows, *, skip_seconds=10): # Call external thumbnailer program subprocess.run( [ "pyvideothumbnailer", "--width", str(width), "--rows", str(rows), "--jpeg-quality", str(90), "--skip-seconds", str(skip_seconds), video_file, ] ) def process(searchdir): VIDEO_FILE_EXT = [".mp4", ".mkv", ".avi", ".mov", ".wmv"] video_files = find_video_files(searchdir, VIDEO_FILE_EXT) for video_file in video_files: # Skip if .jpg file already exists thumbnails_file = video_file + ".jpg" if os.path.exists(thumbnails_file): if VERBOSE: print(f"Skipping: {video_file} (thumbnails already exist)") continue try: duration = get_video_duration(video_file) if duration is not None: # Calculate rows COLS = 4 # pyvideothumbnailer default EVERY = 5 * 60 # seconds rows = math.ceil(duration / EVERY / COLS) skip_seconds = 10 if duration < 60: skip_seconds = 0 # Call the thumbnailer WIDTH = 1600 call_thumbnailer(video_file, WIDTH, rows, skip_seconds=skip_seconds) except (TypeError, UnicodeEncodeError, FileNotFoundError) as e: print(f"Error for {video_file}: {e}") @click.command() @click.argument('searchdirs', nargs=-1) def main(searchdirs): """Run pyvideothumbnailer for every video file found""" if not searchdirs: searchdirs=["."] for searchdir in searchdirs: process(searchdir) if __name__ == "__main__": main()