Spaces:
Running
Running
| from moviepy.editor import VideoFileClip | |
| import os | |
| import logging | |
| 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 | |
| # 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) | |
| output = video_path.replace( | |
| ".mp4", | |
| f"_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 |