Skip to content

Instantly share code, notes, and snippets.

@wotori
Created May 31, 2025 13:41
Show Gist options
  • Save wotori/fd82bb2c790f48c313970d6788d6c592 to your computer and use it in GitHub Desktop.
Save wotori/fd82bb2c790f48c313970d6788d6c592 to your computer and use it in GitHub Desktop.
ffmpeg, python: split video by metadata
#!/usr/bin/env python3
import subprocess
import json
import re
import sys
from pathlib import Path
def extract_chapters(input_file):
"""
Returns a list of tuples (start_sec, end_sec, title)
for all chapters in the input video. Uses ffprobe
with JSON output — this eliminates omissions and parsing errors.
"""
cmd = [
"ffprobe",
"-v", "quiet",
"-print_format", "json",
"-show_chapters",
input_file,
]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
data = json.loads(result.stdout)
chapters = []
for idx, ch in enumerate(data.get("chapters", []), start=1):
start_sec = float(ch["start_time"])
end_sec = float(ch["end_time"])
title = (
ch.get("tags", {}).get("title", f"Chapter_{idx}")
.strip()
.replace(" ", "_")
)
chapters.append((start_sec, end_sec, title))
return chapters
def split_video(input_file, chapters):
input_path = Path(input_file)
for idx, (start, end, title) in enumerate(chapters):
output_file = f"{input_path.stem}_{idx+1:02d}_{title}.mp4"
cmd = [
"ffmpeg", "-y", "-i", input_file,
"-ss", f"{start:.3f}", "-to", f"{end:.3f}",
"-vf", "scale=1920:1080",
"-c:v", "libx264", "-crf", "23", "-preset", "veryfast",
"-c:a", "aac", "-b:a", "192k",
output_file
]
print(f"Exporting: {output_file}")
subprocess.run(cmd)
def main():
if len(sys.argv) != 2:
print("Usage: python split_by_chapters.py <video_file>")
sys.exit(1)
input_file = sys.argv[1]
chapters = extract_chapters(input_file)
if not chapters:
print("No chapters found.")
sys.exit(1)
split_video(input_file, chapters)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment