studio / utils /clipper.py
Ava2lon's picture
Upload 115 files
59215bb verified
Raw
History Blame
3.52 kB
from moviepy.editor import VideoFileClip
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
# =====================================================
# SEGMENT NORMALIZER (CRITICAL V8 FIX)
# =====================================================
def normalize_segments(segments):
"""
Accepts:
- dict segments: {"start": x, "end": y}
- list segments: [{"start":x,"end":y}, ...]
- tuple/list segments: [(start,end), ...]
Returns:
- clean list of dicts
"""
if not segments:
return []
normalized = []
# Case 1: single dict
if isinstance(segments, dict):
segments = [segments]
for s in segments:
# dict format (preferred)
if isinstance(s, dict):
if "start" in s and "end" in s:
normalized.append({
"start": float(s["start"]),
"end": float(s["end"])
})
continue
# grouped word segments from detect_highlights()
if (
isinstance(s, (list, tuple))
and s
and isinstance(s[0], dict)
and isinstance(s[-1], dict)
and "start" in s[0]
and "end" in s[-1]
):
normalized.append({
"start": float(s[0]["start"]),
"end": float(s[-1]["end"]),
})
continue
# list/tuple format
if isinstance(s, (list, tuple)) and len(s) >= 2:
try:
normalized.append({
"start": float(s[0]),
"end": float(s[1])
})
except Exception:
continue
return normalized
# =====================================================
# CORE CLIP GENERATOR (SAFE VERSION)
# =====================================================
def create_clip(video_path, start, end, index):
"""
Creates a single clip safely with validation
"""
try:
start = float(start)
end = float(end)
if end <= start:
logger.warning(f"Invalid segment skipped: {start}-{end}")
return None
clip = VideoFileClip(video_path).subclip(start, end)
source = Path(video_path)
output = str(source.with_name(f"{source.stem}_clip_{index}.mp4"))
clip.write_videofile(
output,
codec="libx264",
audio_codec="aac",
preset="ultrafast",
threads=2,
logger=None # prevents HF log spam
)
return output
except Exception as e:
logger.error(f"Clip creation failed: {str(e)}")
return None
# =====================================================
# BATCH CLIP ENGINE (V8 AUTOCUT CORE FIX)
# =====================================================
def create_clips(video_path, segments):
"""
Main entry used by V8 Highlights / AutoClip engine
"""
segments = normalize_segments(segments)
if not segments:
logger.warning("No valid segments found")
return []
outputs = []
for i, seg in enumerate(segments):
try:
out = create_clip(
video_path,
seg["start"],
seg["end"],
i
)
if out:
outputs.append(out)
except Exception as e:
logger.error(f"Segment {i} failed: {str(e)}")
continue
return outputs