# Batch Processor

> Download, transcribe, and clip multiple YouTube stream VODs by date range. Orchestrates the full pipeline from video download through clipping. Use when processing multiple videos at once.

- Skill: `aj47/batch-processor` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add aj47/batch-processor`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aj47/batch-processor/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: aj47 (https://skillmd.com/u/aj47)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/aj47/batch-processor

---


# Batch Video Processor Skill

Downloads stream VODs from a YouTube channel by date range, transcribes them, and runs the clipper skill on each one automatically.

**Default behavior**: Fetches from the `/streams` tab (VODs only), not regular uploads.

## Quick Start

```
User: "download and clip all of my vids from dec 16 to dec 21"
```

You will automatically:
1. List videos from the channel in that date range
2. For each video: download → transcribe → clip
3. Organize output in per-video folders
4. Report summary when complete

## Configuration

**Default Channel**: https://www.youtube.com/@techfren

**Shell Aliases Used** (from user's ~/.zshrc):
- `yt` = `yt-dlp -f "bv*+ba/b"` - downloads best video+audio
- `tr` = `transcribe-anything --prompt_file ~/vocab.txt --language en` - transcribes with custom vocabulary

## Execution Checklist

When user requests batch processing, follow this exact sequence:

### Phase 1: Parse Request & List Videos

- [ ] Parse date range from user's request (e.g., "dec 16 to dec 21" → 2024-12-16 to 2024-12-21)
- [ ] If year not specified, assume current year (or most recent occurrence)
- [ ] Run: `python .claude/skills/batch-processor/scripts/list_channel_videos.py --start <start> --end <end> --json`
- [ ] Parse JSON output to get list of videos
- [ ] Report to user: "Found N videos from [date range]"

### Phase 2: Process Each Video

For each video in the list (process in chronological order):

#### A. Create Working Directory
```bash
# Format: YYYY-MM-DD_Sanitized_Title
mkdir -p "20241216_Video_Title_Here"
cd "20241216_Video_Title_Here"
```

Sanitize title by:
- Replacing `/\:*?"<>|` with `_`
- Removing non-alphanumeric except spaces, hyphens, underscores
- Truncating to 50 characters
- Replacing spaces with `_`

#### B. Download Video
```bash
yt "<video_url>"
```

- The `yt` alias downloads best quality video+audio
- Output filename will be auto-generated by yt-dlp (usually `<title> [<id>].mp4` or similar)
- Detect the downloaded video file: `ls *.mp4 *.mkv *.webm 2>/dev/null | head -1`

#### C. Transcribe Video
```bash
tr "<video_file>"
```

- The `tr` alias runs transcribe-anything with the user's vocab file
- Output: `out.json` in current directory
- Wait for completion (can take several minutes for long videos)

#### D. Run Clipper Skill

Follow the clipper skill workflow:

1. **Parse transcription** (if `parsed.json` doesn't exist):
   ```bash
   python .claude/skills/clipper/scripts/parse_transcription.py out.json > parsed.json
   ```

2. **Analyze for clips**: Read `parsed.json` and identify segments following clipper skill instructions. Write `segments.json`.

3. **Extract clips**:
   ```bash
   python .claude/skills/clipper/scripts/extract_clips.py segments.json out.json <video_file> clips/
   ```

4. **Cleanup clips**:
   ```bash
   python .claude/skills/clipper/scripts/cleanup_clips.py segments.json out.json <video_file> clips/
   ```

#### E. Return to Parent Directory
```bash
cd ..
```

### Phase 3: Summary Report

After all videos are processed, provide a summary:

```
Batch Processing Complete!
==========================

Date Range: Dec 16 - Dec 21, 2024
Videos Processed: 5

Results:
  1. 2024-12-16_Morning_Stream/
     - Duration: 2h 15m
     - Clips found: 23
     - Clips extracted: 18

  2. 2024-12-17_Tech_Tutorial/
     - Duration: 45m
     - Clips found: 8
     - Clips extracted: 6

  ... (etc)

Total:
  - Videos: 5
  - Total clips found: 67
  - Total clips extracted: 52
  - Skipped (too short): 12
  - Skipped (too long): 3
```

## Output Structure

```
./
├── 2024-12-16_Morning_Stream/
│   ├── Morning Stream [abc123].mp4    # Original video
│   ├── out.json                        # Raw transcription
│   ├── parsed.json                     # Parsed sentences
│   ├── segments.json                   # Identified clips
│   └── clips/
│       ├── 001_OAuth_Setup.mp4
│       ├── 002_Redis_Config.mp4
│       └── cleaned/
│           ├── 001_OAuth_Setup.mp4
│           └── 002_Redis_Config.mp4
├── 2024-12-17_Evening_Stream/
│   ├── ...
└── 2024-12-18_Tutorial/
    └── ...
```

## Date Parsing Examples

The script handles various date formats:

| Input | Interpreted As |
|-------|----------------|
| `dec 16 to dec 21` | 2024-12-16 to 2024-12-21 |
| `December 16 to 21` | 2024-12-16 to 2024-12-21 |
| `12/16 to 12/21` | 2024-12-16 to 2024-12-21 |
| `last 7 days` | Use `--days 7` flag |
| `past week` | Use `--days 7` flag |
| `yesterday to today` | Yesterday to today |
| `2024-12-16 to 2024-12-21` | Explicit dates |

## Error Handling

- **No videos in range**: Report "No videos found" and exit gracefully
- **Download fails**: Log error, skip to next video, include in summary
- **Transcription fails**: Log error, skip to next video, include in summary
- **Clipping fails**: Still have video + transcription, note partial completion
- **Disk space**: Check available space before starting (videos can be large)

## Customization

### Different Channel
```
User: "download and clip videos from @otherchannel from dec 16 to dec 21"
```
Use: `python .../list_channel_videos.py "https://youtube.com/@otherchannel" --start ...`

### Skip Transcription (Already Have It)
```
User: "just clip the videos, I already have transcriptions"
```
Skip the `tr` step, look for existing `out.json` files.

### Skip Download (Local Videos)
```
User: "transcribe and clip all mp4s in this folder"
```
Skip listing/download, iterate over `*.mp4` files instead.

## Scripts Reference

### list_channel_videos.py

Lists YouTube channel stream VODs (or videos) filtered by date.

```bash
# Basic usage - stream VODs from default channel (default)
python .claude/skills/batch-processor/scripts/list_channel_videos.py --start "dec 16" --end "dec 21"

# JSON output for parsing
python .claude/skills/batch-processor/scripts/list_channel_videos.py --start "dec 16" --end "dec 21" --json

# Regular uploads instead of streams
python .claude/skills/batch-processor/scripts/list_channel_videos.py --videos -s "dec 16" -e "dec 21"

# Different channel
python .claude/skills/batch-processor/scripts/list_channel_videos.py "https://youtube.com/@channel" -s "dec 16" -e "dec 21"

# Last N days
python .claude/skills/batch-processor/scripts/list_channel_videos.py --days 7 --json
```

**Arguments:**
- `channel`: YouTube channel URL (default: https://www.youtube.com/@techfren)
- `--start, -s`: Start date
- `--end, -e`: End date
- `--days, -d`: Alternative: last N days
- `--max, -m`: Max videos to scan (default: 100)
- `--json, -j`: Output as JSON for parsing
- `--streams`: Fetch stream VODs only (default: True)
- `--videos`: Fetch regular uploads instead of streams

**JSON Output Format:**
```json
{
  "channel": "https://www.youtube.com/@techfren",
  "date_range": {
    "start": "2024-12-16",
    "end": "2024-12-21"
  },
  "videos": [
    {
      "id": "abc123",
      "title": "Morning Stream",
      "upload_date": "20241216",
      "url": "https://www.youtube.com/watch?v=abc123",
      "duration_seconds": 8100
    }
  ]
}
```

## Requirements

- **yt-dlp**: For listing and downloading videos (`brew install yt-dlp`)
- **transcribe-anything**: For transcription (already configured as `tr` alias)
- **ffmpeg**: For clip extraction (`brew install ffmpeg`)
- **Python 3.8+**: For all scripts

## Integration with Other Skills

This skill orchestrates:
1. **batch-processor** (this skill): Download + transcribe
2. **clipper**: Analyze + extract + cleanup clips
3. **media-fetcher** (optional): Fetch logos/GIFs for clips after clipping

To also fetch media after clipping, user can say:
```
"download and clip all my vids from dec 16 to dec 21, then fetch media for the clips"
```

