This commit includes major additions and updates to the frontend and backend architectures, introducing new dataset management, live counting features, batch processing, and triage logic. Includes new UI pages, components, and API routes.
67 lines
2.4 KiB
Python
Executable File
67 lines
2.4 KiB
Python
Executable File
#!/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)
|