| from moviepy.editor import VideoFileClip |
| import os |
| import logging |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| |
| |
| |
|
|
| 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 = [] |
|
|
| |
| if isinstance(segments, dict): |
| segments = [segments] |
|
|
| for s in segments: |
|
|
| |
| if isinstance(s, dict): |
| if "start" in s and "end" in s: |
| normalized.append({ |
| "start": float(s["start"]), |
| "end": float(s["end"]) |
| }) |
| continue |
|
|
| |
| 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 |
|
|
|
|
| |
| |
| |
|
|
| 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) |
|
|
| output = video_path.replace( |
| ".mp4", |
| f"_clip_{index}.mp4" |
| ) |
|
|
| clip.write_videofile( |
| output, |
| codec="libx264", |
| audio_codec="aac", |
| preset="ultrafast", |
| threads=2, |
| logger=None |
| ) |
|
|
| return output |
|
|
| except Exception as e: |
| logger.error(f"Clip creation failed: {str(e)}") |
| return None |
|
|
|
|
| |
| |
| |
|
|
| 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 |