67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Transcode video archive files to browser-compatible H.264 MP4 format."""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
VIDEO_EXTS = {".mp4", ".mkv", ".mov", ".avi", ".webm", ".m4v"}
|
|
|
|
def probe_codec(file_path: Path) -> str:
|
|
cmd = [
|
|
"ffprobe", "-v", "error", "-select_streams", "v:0",
|
|
"-show_entries", "stream=codec_name",
|
|
"-of", "default=noprint_wrappers=1:nokey=1", str(file_path)
|
|
]
|
|
res = subprocess.run(cmd, capture_output=True, text=True)
|
|
return res.stdout.strip().lower()
|
|
|
|
def transcode_video(file_path: Path):
|
|
tmp_path = file_path.with_name(f"_transcoded_{file_path.stem}.mp4")
|
|
cmd = [
|
|
"ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
|
|
"-i", str(file_path),
|
|
"-c:v", "libx264", "-preset", "fast", "-crf", "22",
|
|
"-c:a", "aac", "-b:a", "128k",
|
|
"-movflags", "+faststart",
|
|
str(tmp_path)
|
|
]
|
|
res = subprocess.run(cmd)
|
|
if res.returncode == 0 and tmp_path.exists() and tmp_path.stat().st_size > 0:
|
|
# Save as .mp4
|
|
target_path = file_path.with_suffix(".mp4")
|
|
if target_path != file_path and file_path.exists():
|
|
file_path.unlink()
|
|
shutil.move(str(tmp_path), str(target_path))
|
|
print(f" ✅ Transcoded -> {target_path}")
|
|
else:
|
|
if tmp_path.exists():
|
|
tmp_path.unlink()
|
|
print(f" ❌ Failed to transcode {file_path}")
|
|
|
|
def process_archive(archive_dir: Path):
|
|
if not archive_dir.exists():
|
|
print(f"Archive directory {archive_dir} does not exist.")
|
|
return
|
|
|
|
print(f"Scanning {archive_dir} for non-H.264 videos...")
|
|
for root, _, files in os.walk(archive_dir):
|
|
for file in sorted(files):
|
|
file_path = Path(root) / file
|
|
if file_path.suffix.lower() in VIDEO_EXTS and not file.startswith("_transcoded_"):
|
|
codec = probe_codec(file_path)
|
|
if not codec:
|
|
print(f"⚠️ Could not probe codec or unreadable: {file_path}")
|
|
continue
|
|
if codec != "h264":
|
|
print(f"🔄 Converting {file_path} (current codec: {codec})...")
|
|
transcode_video(file_path)
|
|
else:
|
|
print(f" ✓ Already H.264: {file_path}")
|
|
|
|
if __name__ == "__main__":
|
|
target = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("data/archive")
|
|
process_archive(target)
|