APM

>Agent Skill

@jeffvincent/video-clipper

skillcode-quality

Create video clips from chapter timestamps using ffmpeg. Use when given a video file and timestamps/chapters to split into separate clips.

code-quality
apm::install
$apm install @jeffvincent/video-clipper
apm::allowed-tools
BashRead
apm::skill.md
---
name: Video Clipper
description: Create video clips from chapter timestamps using ffmpeg. Use when given a video file and timestamps/chapters to split into separate clips.
version: 1.0.0
dependencies: ffmpeg
allowed-tools: [Bash, Read]
---

# Video Clipper

## Overview
This Skill uses ffmpeg to create video clips from a source video file. It supports two modes:
1. **Multi-chapter mode**: Split a video into multiple clips based on chapter timestamps
2. **Single snippet mode**: Extract one clip from a time range (e.g., "55s to 2m35s")

Supports multiple video formats (MP4, MOV, AVI, MKV) and offers both fast stream copy mode and re-encode mode for consistent quality.

## When to Apply
Use this Skill when:
- User has a video file and wants to split it into clips
- User provides chapter markers or timestamps with topic names
- User wants to extract a specific segment with a time range (e.g., "55s to 2m35s", "1:30 to 5:45")
- User wants to create a single clip snippet from a time range
- User has completed Video Transcript Analyzer skill and now wants to create clips from those timestamps
- User asks to "split video by chapters", "create clips from timestamps", "extract video segments", or "create a clip from X to Y"

Do NOT use this Skill for:
- Video editing (adding effects, transitions, etc.)
- Audio-only files (use audio processing tools instead)
- Combining/merging multiple videos
- Format conversion only (use ffmpeg directly)

## Inputs

**For Multi-Chapter Mode:**
1. **Video file path** - Full path to source video (MP4, MOV, AVI, MKV, etc.)
2. **Chapter list with timestamps** - One of these formats:
   - `00:00:00 - Chapter Name`
   - `00:05:30 - Another Chapter`
   - `HH:MM:SS - Chapter Name`
   - `MM:SS - Chapter Name` (for videos under 1 hour)
3. **Output directory** (optional) - Where to save clips
4. **Encoding preference** (optional) - "copy" or "encode"

**For Single Snippet Mode:**
1. **Video file path** - Full path to source video
2. **Time range** - Natural language or standard formats:
   - `55s to 2m35s` (natural language)
   - `1:30 to 5:45` (MM:SS format)
   - `00:01:30 to 00:05:45` (HH:MM:SS format)
   - Start and end time in any mix of formats
3. **Output filename** (optional) - Name for the clip file
4. **Encoding preference** (optional) - "copy" or "encode"

## Outputs

**For Multi-Chapter Mode:**
- Individual video clip file for each chapter with sanitized filename
- Format: `01-Chapter_Name.mp4` (numbered, spaces replaced with underscores)
- Summary report with all clips, durations, sizes, and commands used

**For Single Snippet Mode:**
- One video clip file with specified or auto-generated name
- Format: `[video_name]_[start]-[end].mp4` or custom filename
- Brief report with clip duration, size, and command used

## Instructions for Claude

### Step 1: Validate Prerequisites

First, check if ffmpeg is installed:
```bash
which ffmpeg && ffmpeg -version
```

If not installed, provide installation instructions:
- **macOS**: `brew install ffmpeg`
- **Linux (Ubuntu/Debian)**: `sudo apt-get install ffmpeg`
- **Linux (RHEL/CentOS)**: `sudo yum install ffmpeg`

Ask user to install ffmpeg before proceeding if missing.

### Step 2: Detect Mode (Single Snippet vs Multi-Chapter)

Check the user's request to determine which mode to use:

**Single Snippet Mode indicators:**
- User provides a time range: "55s to 2m35s", "from 1:30 to 5:45", "extract 0:55 to 2:35"
- User says: "create a clip from X to Y", "extract segment", "get the part between X and Y"
- User provides start and end times without chapter names
- Only ONE time range is mentioned

**Multi-Chapter Mode indicators:**
- User provides multiple timestamps with names/descriptions
- User says: "split into chapters", "create clips from these timestamps"
- User has a list of timestamps with chapter names
- Multiple time ranges or chapter markers

**If Single Snippet Mode detected**, skip to **Step 2a: Single Snippet Workflow** below.
**If Multi-Chapter Mode detected**, continue to **Step 2b: Multi-Chapter Workflow** below.
**If unclear**, ask user: "Would you like to create (1) a single clip from a time range, or (2) multiple clips from chapter timestamps?"

### Step 2a: Single Snippet Workflow

For creating one clip from a time range:

1. **Get video file path**:
   - If not provided, ask: "Please provide the full path to your video file"
   - Validate file exists: `ls -lh [filepath]`
   - Show file size and duration

2. **Parse time range**:
   - Look for patterns like:
     - `55s to 2m35s` → convert to seconds: 55 to 155
     - `1:30 to 5:45` → convert to seconds: 90 to 345
     - `00:01:30 to 00:05:45` → already in HH:MM:SS format
   - Support formats:
     - `Xs` (seconds): 55s = 55 seconds
     - `Xm` or `XmYs` (minutes): 2m35s = 155 seconds, 5m = 300 seconds
     - `XhYm` or `XhYmZs` (hours): 1h30m = 5400 seconds
     - `MM:SS`: 1:30 = 90 seconds
     - `HH:MM:SS`: 00:01:30 = 90 seconds
   - If time range not clear, ask: "What time range would you like to extract? (e.g., '55s to 2m35s' or '1:30 to 5:45')"

3. **Get output filename**:
   - If not provided, generate: `[video_name]_[start]-[end].mp4`
   - Example: `customer-call_00-55_02-35.mp4`
   - Ask: "What would you like to name this clip? (Press Enter for: [suggested_name])"

4. **Get encoding preference**:
   - Ask: "Encoding mode: 'copy' (fast) or 'encode' (precise)? Default: copy"

5. **Convert times to HH:MM:SS format** for ffmpeg:
   ```python
   def seconds_to_timestamp(seconds):
       h = seconds // 3600
       m = (seconds % 3600) // 60
       s = seconds % 60
       return f"{h:02d}:{m:02d}:{s:02d}"
   ```

6. **Generate ffmpeg command**:
   - Copy mode: `ffmpeg -i [video] -ss [start] -to [end] -c copy -avoid_negative_ts 1 "[output]"`
   - Encode mode: `ffmpeg -i [video] -ss [start] -to [end] -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k "[output]"`

7. **Execute command**:
   - Show command to user
   - Execute and capture output
   - Verify clip was created

8. **Report results**:
   ```markdown
   # Video Clip Created

   **Source:** [video_path]
   **Time Range:** [start] to [end] ([duration])
   **Output:** [output_path]
   **Size:** [file_size]
   **Encoding:** [copy/encode]

   **Command used:**
   ```bash
   [ffmpeg command]
   ```
   ```

9. **Skip to Step 9 (Quality Checks)**

### Step 2b: Multi-Chapter Workflow

For creating multiple clips from chapter timestamps:

(Continue with existing workflow below...)

### Step 3: Gather Required Information (Multi-Chapter Mode)

Check what information is provided. If missing, prompt for:

1. **Video file path**:
   - Ask: "Please provide the full path to your video file (e.g., /Users/name/video.mp4)"
   - Validate file exists using `ls -lh [filepath]`
   - Show file size and confirm with user

2. **Chapter timestamps**:
   - Ask: "Please provide your chapter list with timestamps in this format:
     ```
     00:00:00 - Introduction
     00:05:30 - Main Topic
     00:15:45 - Q&A
     ```
     (Tip: If you have a video transcript, try the Video Transcript Analyzer skill first to generate timestamps)"
   - Wait for user to provide timestamps

3. **Output directory**:
   - Ask: "Where would you like to save the clips? (Press Enter for default: same folder as source video with '_clips' suffix)"
   - Default: `[video_directory]/[video_name]_clips/`

4. **Encoding mode**:
   - Ask: "Choose encoding mode:
     - 'copy' (fast, no re-encode, may have keyframe issues at boundaries)
     - 'encode' (slower, consistent quality, precise cuts)
     Default: copy"

### Step 4: Parse and Validate Timestamps (Multi-Chapter Mode)

1. **Parse timestamp format**:
   ```python
   import re
   from datetime import datetime, timedelta

   def parse_timestamp(ts_str):
       """Convert HH:MM:SS or MM:SS to seconds"""
       parts = ts_str.strip().split(':')
       if len(parts) == 3:  # HH:MM:SS
           h, m, s = map(int, parts)
           return h * 3600 + m * 60 + s
       elif len(parts) == 2:  # MM:SS
           m, s = map(int, parts)
           return m * 60 + s
       else:
           raise ValueError(f"Invalid timestamp format: {ts_str}")

   def parse_chapter_line(line):
       """Parse '00:05:30 - Chapter Name' format"""
       match = re.match(r'(\d{1,2}:\d{2}:\d{2}|\d{1,2}:\d{2})\s*-\s*(.+)', line.strip())
       if match:
           timestamp, name = match.groups()
           return parse_timestamp(timestamp), name.strip()
       return None
   ```

2. **Validate timestamps**:
   - Check all timestamps are in ascending order
   - Warn if any timestamps are out of order
   - Check for duplicate timestamps
   - Ensure first timestamp is 00:00:00 or close to start

3. **Get video duration**:
   ```bash
   ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 [video_file]
   ```

4. **Calculate end times**:
   - For each chapter, end time = next chapter's start time
   - For last chapter, end time = video duration
   - Validate no chapter extends beyond video duration

### Step 5: Sanitize Filenames (Multi-Chapter Mode)

Create safe filenames from chapter names:
```python
import re

def sanitize_filename(name):
    """Convert chapter name to safe filename"""
    # Remove or replace special characters
    name = re.sub(r'[<>:"/\\|?*]', '', name)
    # Replace spaces with underscores
    name = name.replace(' ', '_')
    # Replace multiple underscores with single
    name = re.sub(r'_+', '_', name)
    # Remove leading/trailing underscores
    name = name.strip('_')
    # Limit length to 100 chars
    if len(name) > 100:
        name = name[:100]
    return name
```

Generate filenames:
- Format: `{number:02d}-{sanitized_name}.{extension}`
- Example: `01-Introduction.mp4`, `02-Main_Topic.mp4`
- Number chapters sequentially starting from 01

### Step 6: Create Output Directory (Multi-Chapter Mode)

```bash
mkdir -p [output_directory]
```

Show user where clips will be saved.

### Step 7: Generate ffmpeg Commands (Multi-Chapter Mode)

**For "copy" mode (fast, no re-encode):**
```bash
ffmpeg -i [input_video] -ss [start_time] -to [end_time] -c copy -avoid_negative_ts 1 "[output_file]"
```

**For "encode" mode (slower, precise):**
```bash
ffmpeg -i [input_video] -ss [start_time] -to [end_time] -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k "[output_file]"
```

**Key parameters:**
- `-ss [start_time]`: Start time in HH:MM:SS format
- `-to [end_time]`: End time in HH:MM:SS format
- `-c copy`: Stream copy (no re-encode)
- `-c:v libx264`: Video codec for encoding
- `-preset medium`: Encoding speed/quality balance
- `-crf 23`: Quality level (18-28, lower is better)
- `-c:a aac`: Audio codec
- `-avoid_negative_ts 1`: Fix timestamp issues in copy mode

### Step 8: Execute Clipping Commands (Multi-Chapter Mode)

1. **Show execution plan**:
   ```
   Creating [N] clips from [video_name]:
   1. [00:00:00 - 00:05:30] → 01-Introduction.mp4
   2. [00:05:30 - 00:15:45] → 02-Main_Topic.mp4
   ...
   ```

2. **Execute commands sequentially**:
   - Run one ffmpeg command at a time
   - Show progress: "Creating clip 1 of N..."
   - Capture any errors or warnings
   - Validate each output file was created and has size > 0

3. **For parallel execution** (optional, if user wants speed):
   - Can run multiple ffmpeg commands in background
   - Monitor all processes
   - Wait for all to complete before reporting
   - Only use if system has multiple cores and user approves

### Step 9: Verify and Report Results (Both Modes)

1. **Check each output file**:
   ```bash
   ls -lh [output_directory]/*.mp4
   ```

2. **Get clip durations**:
   ```bash
   for file in [output_directory]/*.mp4; do
     ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file"
   done
   ```

3. **Generate summary report**:
   ```markdown
   # Video Clipping Complete

   ## Source Video
   - File: [path]
   - Duration: [HH:MM:SS]
   - Size: [size]

   ## Created Clips

   | # | Clip Name | Duration | Size | Time Range |
   |---|-----------|----------|------|------------|
   | 1 | 01-Introduction.mp4 | 05:30 | 15.2 MB | 00:00:00 - 00:05:30 |
   | 2 | 02-Main_Topic.mp4 | 10:15 | 28.4 MB | 00:05:30 - 00:15:45 |

   ## Summary
   - Total clips created: [N]
   - Total size: [total_size]
   - Output location: [directory]
   - Encoding mode: [copy/encode]

   ## Warnings/Errors
   [List any issues encountered]

   ## Commands Used
   ```bash
   [Show all ffmpeg commands for reference]
   ```
   ```

### Step 10: Quality Checks (Both Modes)

Before finalizing:
- [ ] All expected clip files exist
- [ ] Each file has size > 0 bytes
- [ ] Clip durations match expected ranges (within 1-2 seconds)
- [ ] Filenames are properly sanitized (no special characters) [Multi-chapter only]
- [ ] No ffmpeg errors in output
- [ ] Summary report shows all clips

If using "copy" mode, warn user:
> Note: Copy mode may result in clips that don't start exactly at the specified timestamp due to keyframe positions. If precise cuts are needed, re-run with "encode" mode.

### Error Handling

**Common errors and solutions:**

1. **ffmpeg not found**:
   - Error: `command not found: ffmpeg`
   - Solution: Provide installation instructions

2. **Invalid timestamp**:
   - Error: Timestamp parsing fails
   - Solution: Show expected format, ask user to correct

3. **Timestamp beyond video duration**:
   - Error: End time > video length
   - Solution: Adjust last chapter to end at video duration

4. **File not found**:
   - Error: Input video doesn't exist
   - Solution: Ask user to verify path, suggest using tab completion

5. **Permission denied**:
   - Error: Cannot write to output directory
   - Solution: Check directory permissions, suggest alternative location

6. **Codec errors in copy mode**:
   - Error: "Non-monotonous DTS in output stream"
   - Solution: Re-run with encode mode or add `-avoid_negative_ts 1`

7. **Overlapping timestamps**:
   - Error: Timestamps out of order
   - Solution: Sort timestamps, ask user to confirm order

## Examples

### Example 1: Single Snippet from Time Range

**User says:** "Create a clip from 55s to 2m35s"
**User provides:** `/Users/alice/videos/customer-call.mp4`

**Workflow:**
1. Validate ffmpeg installed ✓
2. Detect Single Snippet Mode (time range provided)
3. Parse time range: 55s = 55 seconds, 2m35s = 155 seconds
4. Convert to HH:MM:SS: 00:00:55 to 00:02:35
5. Suggest filename: `customer-call_00-55_02-35.mp4`
6. User accepts default filename
7. Ask encoding preference: user chooses "copy"
8. Generate ffmpeg command:
   ```bash
   ffmpeg -i /Users/alice/videos/customer-call.mp4 -ss 00:00:55 -to 00:02:35 -c copy -avoid_negative_ts 1 "customer-call_00-55_02-35.mp4"
   ```
9. Execute command
10. Report results:
    ```
    # Video Clip Created

    **Source:** /Users/alice/videos/customer-call.mp4
    **Time Range:** 00:00:55 to 00:02:35 (1m 40s)
    **Output:** /Users/alice/videos/customer-call_00-55_02-35.mp4
    **Size:** 8.2 MB
    **Encoding:** copy
    ```

**Output file:**
```
/Users/alice/videos/customer-call_00-55_02-35.mp4 (8.2 MB, 1m 40s)
```

### Example 2: Basic Usage with SRT Timestamps (Multi-Chapter)

**User provides:**
```
Video: /Users/alice/videos/customer-call.mp4
Chapters:
00:00:00 - Introduction
00:02:57 - Memberships & Registration
00:09:41 - Lists vs Views
00:15:30 - API Limitations
```

**Workflow:**
1. Validate ffmpeg installed
2. Check video file exists (352 MB, 18:45 duration)
3. Parse 4 chapters with timestamps
4. Ask for encoding preference (user chooses "copy")
5. Create output directory: `/Users/alice/videos/customer-call_clips/`
6. Generate 4 ffmpeg commands
7. Execute sequentially
8. Verify all 4 clips created

**Output files:**
```
/Users/alice/videos/customer-call_clips/
  01-Introduction.mp4 (15.2 MB, 02:57)
  02-Memberships_Registration.mp4 (28.4 MB, 06:44)
  03-Lists_vs_Views.mp4 (24.1 MB, 05:49)
  04-API_Limitations.mp4 (12.8 MB, 03:15)
```

### Example 3: From Video Transcript Analyzer Output (Multi-Chapter)

**User says:** "I just ran Video Transcript Analyzer on my interview. Can you create clips from those chapters?"

**Workflow:**
1. Ask user: "Please share the video file path and the chapter timestamps from the analysis"
2. User provides video path and copies the "Topical Breakdown" section timestamps
3. Parse timestamps:
   ```
   00:02:57 - Memberships & Registration Management
   00:09:41 - Lists vs Views Disconnect
   00:15:30 - API Limitations
   00:20:15 - Workflow Automation Issues
   ```
4. Get video duration: 25:42
5. Calculate last chapter ends at 25:42
6. Ask encoding preference (user chooses "encode" for precise cuts)
7. Create clips with re-encoding
8. Report: 4 clips created, 156 MB total

### Example 4: Simple Timestamps - MM:SS format (Multi-Chapter)

**User provides:**
```
Video: /home/user/videos/tutorial.mp4
Chapters:
0:00 - Intro
5:30 - Setup
12:45 - Demo
18:20 - Q&A
```

**Workflow:**
1. Parse MM:SS format timestamps (convert to seconds)
2. Validate video is 22:15 long
3. Calculate end times:
   - Intro: 0:00 - 5:30
   - Setup: 5:30 - 12:45
   - Demo: 12:45 - 18:20
   - Q&A: 18:20 - 22:15
4. Create 4 clips in encode mode (user requested precise cuts)
5. Success: All clips created

## Testing Checklist

- [ ] ffmpeg detection works correctly
- [ ] Handles both HH:MM:SS and MM:SS timestamp formats
- [ ] Validates timestamps are in ascending order
- [ ] Correctly calculates end times from next chapter start
- [ ] Last chapter uses video duration as end time
- [ ] Sanitizes filenames (removes special chars, replaces spaces)
- [ ] Creates output directory if it doesn't exist
- [ ] Both "copy" and "encode" modes work
- [ ] Generates proper ffmpeg commands
- [ ] Verifies all output files created
- [ ] Reports file sizes and durations accurately
- [ ] Handles errors gracefully (missing video, invalid timestamps)
- [ ] Warns about copy mode keyframe limitations
- [ ] Provides summary report with all details

## Security and Privacy

**File Access:**
- Only reads user-specified video file
- Only writes to user-specified output directory
- Does not modify source video file
- Validates all paths before execution

**Command Execution:**
- All ffmpeg commands shown to user before execution
- No arbitrary command injection
- Filenames sanitized to prevent shell injection
- Uses absolute paths to prevent directory traversal

**Privacy:**
- Video content never sent to external services
- All processing done locally with ffmpeg
- Chapter names may contain sensitive info - handle appropriately
- Output files remain in user's filesystem

## Resources

See `resources/` folder for:
- **EXAMPLES.md**: Detailed examples with full input/output
- **REFERENCE.md**: ffmpeg command reference, timestamp formats, troubleshooting guide
- **README.md**: User-facing documentation

## Related Skills (Workflow Chain)

This skill is part of the **video processing workflow**:

```
┌─────────────────────┐
│   wistia-uploader   │  → Upload video, get transcript
└──────────┬──────────┘


┌─────────────────────────────┐
│  video-transcript-analyzer  │  → Analyze transcript, get timestamps
└──────────┬──────────────────┘


┌─────────────────────┐
│    video-clipper    │  ← YOU ARE HERE
│   (create clips)    │
└──────────┬──────────┘


┌─────────────────────┐
│   wistia-uploader   │  → (Optional) Upload clips to Wistia
└─────────────────────┘
```

**Preceding skill:** `video-transcript-analyzer` - Use this first to generate chapter timestamps from a transcript

**Following skill:** `wistia-uploader` - Optionally upload the created clips to Wistia for hosting