🚧 autopyvideothumbnailer
This commit is contained in:
parent
3872b5ed0d
commit
144e755e41
1 changed files with 38 additions and 18 deletions
|
@ -7,21 +7,24 @@ import math
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import click
|
import click
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
|
|
||||||
|
from addict import Dict
|
||||||
from pymediainfo import MediaInfo
|
from pymediainfo import MediaInfo
|
||||||
|
|
||||||
|
|
||||||
VERBOSE = False
|
def is_video_file(video_file_path):
|
||||||
|
type_ = mimetypes.guess_type(video_file_path)[0]
|
||||||
|
return type_ is not None and type_.startswith("video/")
|
||||||
|
|
||||||
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):
|
def find_video_files(directory):
|
||||||
# Recursively walk through directory
|
# Recursively walk through directory
|
||||||
for dirpath, dirs, files in os.walk(directory):
|
for dirpath, dirs, files in os.walk(directory):
|
||||||
for filename in files:
|
for filename in files:
|
||||||
filename_path = os.path.join(dirpath, filename)
|
filename_path = os.path.join(dirpath, filename)
|
||||||
if is_video_file(filename_path, video_extensions):
|
if is_video_file(filename_path):
|
||||||
yield os.path.abspath(filename_path)
|
yield os.path.abspath(filename_path)
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,60 +45,77 @@ def get_video_duration(video_file_path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def call_thumbnailer(video_file, width, rows, *, skip_seconds=10):
|
def call_thumbnailer(video_file, width, columns, rows, *, skip_seconds=10):
|
||||||
# Call external thumbnailer program
|
# Call external thumbnailer program
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
"pyvideothumbnailer",
|
"pyvideothumbnailer",
|
||||||
"--width",
|
"--width",
|
||||||
str(width),
|
str(width),
|
||||||
|
"--columns",
|
||||||
|
str(columns),
|
||||||
"--rows",
|
"--rows",
|
||||||
str(rows),
|
str(rows),
|
||||||
"--jpeg-quality",
|
"--jpeg-quality",
|
||||||
str(90),
|
str(90),
|
||||||
|
"--header-font",
|
||||||
|
config.font,
|
||||||
"--skip-seconds",
|
"--skip-seconds",
|
||||||
str(skip_seconds),
|
str(skip_seconds),
|
||||||
video_file,
|
video_file,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def process(searchdir):
|
def process(searchdir):
|
||||||
VIDEO_FILE_EXT = [".mp4", ".mkv", ".avi", ".mov", ".wmv"]
|
video_files = find_video_files(searchdir)
|
||||||
video_files = find_video_files(searchdir, VIDEO_FILE_EXT)
|
|
||||||
|
|
||||||
for video_file in video_files:
|
for video_file in video_files:
|
||||||
# Skip if .jpg file already exists
|
# Skip if .jpg file already exists
|
||||||
thumbnails_file = video_file + ".jpg"
|
thumbnails_file = video_file + ".jpg"
|
||||||
if os.path.exists(thumbnails_file):
|
if os.path.exists(thumbnails_file):
|
||||||
if VERBOSE:
|
if config.verbose:
|
||||||
print(f"Skipping: {video_file} (thumbnails already exist)")
|
print(f"Skipping: {video_file} (thumbnails already exist)")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
duration = get_video_duration(video_file)
|
duration = get_video_duration(video_file)
|
||||||
if duration is not None:
|
if duration is not None:
|
||||||
# Calculate rows
|
rows = math.ceil(duration / config.every / config.columns)
|
||||||
COLS = 4 # pyvideothumbnailer default
|
|
||||||
EVERY = 5 * 60 # seconds
|
|
||||||
rows = math.ceil(duration / EVERY / COLS)
|
|
||||||
|
|
||||||
skip_seconds = 10
|
skip_seconds = 10
|
||||||
if duration < 60:
|
if duration < 60:
|
||||||
skip_seconds = 0
|
skip_seconds = 0
|
||||||
|
|
||||||
# Call the thumbnailer
|
# Call the thumbnailer
|
||||||
WIDTH = 1600
|
call_thumbnailer(
|
||||||
call_thumbnailer(video_file, WIDTH, rows, skip_seconds=skip_seconds)
|
video_file,
|
||||||
|
config.width,
|
||||||
|
config.columns,
|
||||||
|
rows,
|
||||||
|
skip_seconds=skip_seconds,
|
||||||
|
)
|
||||||
except (TypeError, UnicodeEncodeError, FileNotFoundError) as e:
|
except (TypeError, UnicodeEncodeError, FileNotFoundError) as e:
|
||||||
print(f"Error for {video_file}: {e}")
|
print(f"Error for {video_file}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
config = Dict()
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument('searchdirs', nargs=-1)
|
@click.argument("searchdirs", nargs=-1)
|
||||||
def main(searchdirs):
|
@click.option("-v", "--verbose", is_flag=True, default=False)
|
||||||
|
def main(searchdirs, verbose):
|
||||||
"""Run pyvideothumbnailer for every video file found"""
|
"""Run pyvideothumbnailer for every video file found"""
|
||||||
|
|
||||||
|
config.verbose = verbose
|
||||||
|
config.width = 1600
|
||||||
|
config.columns = 4 # pyvideothumbnailer default
|
||||||
|
config.every = 5 * 60 # seconds
|
||||||
|
config.font = "DejaVuSansMono.ttf"
|
||||||
|
|
||||||
if not searchdirs:
|
if not searchdirs:
|
||||||
searchdirs=["."]
|
searchdirs = ["."]
|
||||||
for searchdir in searchdirs:
|
for searchdir in searchdirs:
|
||||||
process(searchdir)
|
process(searchdir)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue