| |
| """ |
| Video Clipping Script |
| |
| This script clips a video file to exactly 19 seconds starting from the beginning. |
| Uses ffmpeg for efficient video processing. |
| """ |
|
|
| import os |
| import sys |
| import subprocess |
| from pathlib import Path |
| from typing import Optional, Tuple |
| import argparse |
|
|
| def _validate_video_file(file_path: str) -> bool: |
| """ |
| Validate that the input file exists and is a readable video file. |
| |
| Args: |
| file_path: Path to the video file |
| |
| Returns: |
| True if file is valid, False otherwise |
| """ |
| if not os.path.exists(file_path): |
| print(f"Error: File '{file_path}' does not exist.") |
| return False |
| |
| if not os.path.isfile(file_path): |
| print(f"Error: '{file_path}' is not a file.") |
| return False |
| |
| if not os.access(file_path, os.R_OK): |
| print(f"Error: File '{file_path}' is not readable.") |
| return False |
| |
| return True |
|
|
| def _get_video_duration(file_path: str) -> Optional[float]: |
| """ |
| Get the duration of a video file using ffprobe. |
| |
| Args: |
| file_path: Path to the video file |
| |
| Returns: |
| Duration in seconds, or None if ffprobe fails |
| """ |
| try: |
| cmd = [ |
| 'ffprobe', |
| '-v', 'quiet', |
| '-show_entries', 'format=duration', |
| '-of', 'csv=p=0', |
| file_path |
| ] |
| |
| result = subprocess.run(cmd, capture_output=True, text=True, check=True) |
| duration = float(result.stdout.strip()) |
| return duration |
| except (subprocess.CalledProcessError, ValueError, FileNotFoundError) as e: |
| print(f"Error getting video duration: {e}") |
| return None |
|
|
| def _generate_output_filename(input_path: str) -> str: |
| """ |
| Generate output filename by adding '_19s' suffix before the extension. |
| |
| Args: |
| input_path: Path to the input video file |
| |
| Returns: |
| Output filename with '_19s' suffix |
| """ |
| input_path_obj = Path(input_path) |
| stem = input_path_obj.stem |
| suffix = input_path_obj.suffix |
| |
| |
| output_filename = f"{stem}_19s{suffix}" |
| |
| |
| if output_filename == input_path_obj.name: |
| from datetime import datetime |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
| output_filename = f"{stem}_19s_{timestamp}{suffix}" |
| |
| return output_filename |
|
|
| def _clip_video(input_path: str, output_path: str, duration: int = 19) -> bool: |
| """ |
| Clip the video to the specified duration using ffmpeg. |
| |
| Args: |
| input_path: Path to the input video file |
| output_path: Path for the output video file |
| duration: Duration to clip to in seconds (default: 19) |
| |
| Returns: |
| True if clipping was successful, False otherwise |
| """ |
| try: |
| cmd = [ |
| 'ffmpeg', |
| '-i', input_path, |
| '-t', str(duration), |
| '-c', 'copy', |
| '-avoid_negative_ts', 'make_zero', |
| '-y', |
| output_path |
| ] |
| |
| print(f"Cliping video to {duration} seconds...") |
| print(f"Input: {input_path}") |
| print(f"Output: {output_path}") |
| |
| |
| result = subprocess.run(cmd, capture_output=True, text=True, check=True) |
| |
| print("Video clipping completed successfully!") |
| return True |
| |
| except subprocess.CalledProcessError as e: |
| print(f"Error during video clipping: {e}") |
| if e.stderr: |
| print(f"FFmpeg error: {e.stderr}") |
| return False |
| except Exception as e: |
| print(f"Unexpected error: {e}") |
| return False |
|
|
| def clip_video_to_19s(video_path: str) -> bool: |
| """ |
| Main function to clip a video file to 19 seconds. |
| |
| Args: |
| video_path: Path to the input video file |
| |
| Returns: |
| True if clipping was successful, False otherwise |
| """ |
| |
| if not _validate_video_file(video_path): |
| return False |
| |
| |
| original_duration = _get_video_duration(video_path) |
| if original_duration is None: |
| return False |
| |
| print(f"Original video duration: {original_duration:.2f} seconds") |
| |
| |
| if original_duration <= 19: |
| print(f"Video is already {original_duration:.2f} seconds long (≤ 19s). No clipping needed.") |
| return True |
| |
| |
| output_filename = _generate_output_filename(video_path) |
| output_path = os.path.join(os.path.dirname(video_path), output_filename) |
| |
| |
| success = _clip_video(video_path, output_path, 19) |
| |
| if success: |
| |
| if os.path.exists(output_path): |
| output_duration = _get_video_duration(output_path) |
| if output_duration: |
| print(f"Output video duration: {output_duration:.2f} seconds") |
| print(f"Output saved to: {output_path}") |
| else: |
| print("Warning: Could not verify output video duration") |
| else: |
| print("Warning: Output file was not created") |
| |
| return success |
|
|
| def main(): |
| """Main entry point for command line usage.""" |
| parser = argparse.ArgumentParser( |
| description="Clip a video file to 19 seconds", |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| epilog=""" |
| Examples: |
| python clip_video.py video.mp4 |
| python clip_video.py /path/to/video.mov |
| python clip_video.py "video with spaces.avi" |
| """ |
| ) |
| |
| parser.add_argument( |
| 'video_path', |
| help='Path to the input video file' |
| ) |
| |
| args = parser.parse_args() |
| |
| |
| success = clip_video_to_19s(args.video_path) |
| |
| |
| sys.exit(0 if success else 1) |
|
|
| if __name__ == "__main__": |
| main() |