Not sure how useful this will be, in the same way I’m not sure how useful the Resync script will be, but I figured since I made it for myself I’d upload here as well. I created a full directory scanner that can tell you which video files are VFR/Variable Frame-Rate and which are CFR. If you don’t know what that is read about it here:
There are two versions.
Lightweight: Scans just the metadata for information that indicates VFR. Can run on thousands of files relatively quickly. NOT super accurate, and will definitely miss some VFR files because it doesn’t actually scan any of the video frames.
Hardcore: Scans each frame of every video in the directory to determine if the video is VFR. Pretty much 100% accurate, but super slow and resource intensive. Good for pointing at a small folder of videos (maybe videos you just downloaded?) that you want to be certain are/are-not VFR.
You need python installed and ffmpeg on your path… blah blah blah
Here they are:
import subprocess
from pathlib import Path
import tkinter as tk
from tkinter import filedialog
def get_directory_path():
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
print("Opening file explorer... Select a directory containing video files.")
path = filedialog.askdirectory(title="Select Directory to Scan")
return Path(path) if path else None
def check_vfr(video_path: Path):
cmd = [
"ffprobe",
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=avg_frame_rate,r_frame_rate",
"-of",
"default=noprint_wrappers=1:nokey=1",
str(video_path),
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
lines = [line.strip() for line in result.stdout.strip().splitlines()]
if len(lines) < 2:
return None
avg_str, r_str = lines[0], lines[1]
def parse_frac(f):
num, den = map(int, f.split("/")) if "/" in f else (int(float(f)), 1)
return num, den
avg_num, avg_den = parse_frac(avg_str)
r_num, r_den = parse_frac(r_str)
is_vfr = (avg_str != r_str) or any(val > 100000 for val in (avg_num, avg_den, r_num, r_den))
return is_vfr
except Exception:
return None
def scan_directory(dir_path: Path):
if not dir_path or not dir_path.exists():
print("You didn't fucking pick anything. Exiting.")
return
video_extensions = {".mp4", ".mkv", ".avi", ".mov", ".flv", ".webm", ".m4v"}
video_files = [f for f in dir_path.rglob("*") if f.suffix.lower() in video_extensions]
if not video_files:
print(f"\nNo supported video files found in: {dir_path}")
return
print(f"\nScanning directory: {dir_path}")
print(f"Found {len(video_files)} video file(s). Processing...\n")
vfr_results = []
cfr_count = 0
error_count = 0
for idx, video_path in enumerate(video_files, 1):
relative_path = video_path.relative_to(dir_path)
print(f"[{idx}/{len(video_files)}] Checking: {relative_path}")
vfr_status = check_vfr(video_path)
if vfr_status is True:
vfr_results.append(relative_path)
elif vfr_status is False:
cfr_count += 1
else:
error_count += 1
print("\n" + "=" * 50)
print("--- Beep Bopp, SCAN RESULTS ---")
print("=" * 50)
if vfr_results:
print(f"\nThese are FUCKING VFR Videos ({len(vfr_results)} found):")
for vfr_file in vfr_results:
print(f" - {vfr_file}")
else:
print("\nResult:Congratulations! No VFR videos found. All checked files are CFR (Constant Frame Rate) or unreadable. Yipeeee!")
print(f"\nSummary:")
print(f" - Total Scanned: {len(video_files)}")
print(f" - VFR Flagged: {len(vfr_results)}")
print(f" - CFR (Wahoo and shit): {cfr_count}")
print(f" - Errors/Failed: {error_count}")
if __name__ == "__main__":
scan_directory(get_directory_path())
input("\nPress Enter to exit...")
Reminder, don’t run this version on 3000 videos because it will take till the heat death of the universe to scan them.
import re
import subprocess
from pathlib import Path
import tkinter as tk
from tkinter import filedialog
def get_directory_path():
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
print("Opening file explorer... Select a directory containing video files.")
path = filedialog.askdirectory(title="Pick a fucking directory")
return Path(path) if path else None
def analyze_video(video_path: Path):
try:
probe_cmd = [
"ffprobe",
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=avg_frame_rate,r_frame_rate",
"-of",
"default=noprint_wrappers=1:nokey=1",
str(video_path),
]
probe_res = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
lines = [line.strip() for line in probe_res.stdout.strip().splitlines()]
avg_str = lines[0] if len(lines) > 0 else "30/1"
def parse_frac(f):
return tuple(map(int, f.split("/"))) if "/" in f else (int(float(f)), 1)
avg_num, avg_den = parse_frac(avg_str)
avg_fps = avg_num / avg_den if avg_den != 0 else 0.0
cmd = ["ffmpeg", "-i", str(video_path), "-vf", "vfrdet", "-f", "null", "-"]
result = subprocess.run(cmd, capture_output=True, text=True)
stderr_output = result.stderr
match = re.search(r"VFR:\s*([0-9.]+)", stderr_output)
if not match:
return None, avg_fps
vfr_ratio = float(match.group(1))
is_vfr = vfr_ratio > 0.0
return is_vfr, avg_fps
except Exception:
return None, 0.0
def scan_directory(dir_path: Path):
if not dir_path or not dir_path.exists():
print("You didn't fucking pick anything. Exiting.")
return
video_extensions = {".mp4", ".mkv", ".avi", ".mov", ".flv", ".webm", ".m4v"}
video_files = [f for f in dir_path.rglob("*") if f.suffix.lower() in video_extensions]
if not video_files:
print(f"\nNo supported video files found in: {dir_path}")
return
print(f"\nScanning directory: {dir_path}")
print(f"Found {len(video_files)} video file(s). Processing with deep vfrdet analysis...")
print("This is gonna take a while. Place your thumb up your ass while you wait :)\n")
vfr_results = []
cfr_count = 0
error_count = 0
for idx, video_path in enumerate(video_files, 1):
relative_path = video_path.relative_to(dir_path)
print(f"[{idx}/{len(video_files)}] Analyzing: {relative_path}")
vfr_status, avg_fps = analyze_video(video_path)
if vfr_status is True:
vfr_results.append((relative_path, avg_fps))
elif vfr_status is False:
cfr_count += 1
else:
error_count += 1
print("\n" + "=" * 50)
print("--- HARDCORE SCAN RESULTS ---")
print("=" * 50)
if vfr_results:
print(f"\nFlagged VFR Videos ({len(vfr_results)} found):")
for vfr_file, fps in vfr_results:
print(f" - {vfr_file} (Avg FPS: {fps:.2f})")
else:
print("\nResult: Congrats. No VFR videos found. All checked files are CFR (Constant Frame Rate). That's neat.")
print(f"\nSummary:")
print(f" - Total Scanned: {len(video_files)}")
print(f" - VFR Flagged: {len(vfr_results)}")
print(f" - CFR (Clean): {cfr_count}")
print(f" - Errors/Failed: {error_count}")
if __name__ == "__main__":
scan_directory(get_directory_path())
input("\nPress Enter to exit...")
Download the two versions here:

