---
name: video-parser
description: |
  Video deconstruction skill. Splits a video into reusable content assets — audio, ASR transcript, scene segments, keyframe images.

  Use this skill as soon as the user mentions any of these intents:
  - Deconstruct / split / analyze / parse a video
  - Extract keyframes, extract the script from a video, transcribe a video
  - Pull content assets or raw material out of a video

  Even when the user does not say "deconstruct" explicitly, use this skill whenever they want to extract script text, keyframes, or structured information from a video.
triggers:
  - Deconstruct / split / analyze / parse a video
  - Extract keyframes, extract the script from a video, transcribe a video
  - Pull content assets or raw material out of a video
---

# Video Deconstruction Skill

Splits a video into reusable content assets — audio, ASR transcript (with per-word timestamps), scene cuts, keyframe images — and returns a structured asset-manifest JSON.

The skill entry (`scripts/parse_via_render.py`) runs the deconstruction **through the ab-render HTTP service** (`POST /parse` → poll `POST /parseStatus`). It needs **no local ffmpeg** — the heavy lifting happens server-side and the manifest (with cloud-hosted asset URLs) comes back as JSON on stdout.

## Authentication & environment

No skill-local env file — the executing process inherits the system environment.

- **Enterprise OpenClaw**: auth + service address are injected; nothing to configure.
- **Other environments**: set `RENDER_API_URL` (the ab-render service) and `PRIV_TOKEN`. Without them the run fails fast with an actionable message.

| Env var | Description | Default |
|---------|-------------|---------|
| `RENDER_API_URL` | ab-render service base URL. Falls back to `REMOTION_RENDER_API_URL` (same value across skills), then the default. | `https://api-render.remixmate.ai` |
| `PRIV_TOKEN` | Tianyan token, sent as `X-Priv-Token`. | (none) |
| `CONVERSATION_ID` | Optional, sent as `x-conversation-id` for file association. | (none) |

## Steps

1. **Script path**: read the system-injected `Base directory for this skill: <path>` as `<SkillDir>`. The entry is always `<SkillDir>/scripts/parse_via_render.py`; never hard-code paths.
2. **Provide a direct video URL** (`--url`). Page links (Douyin / Xiaohongshu share pages) are not supported — pass a direct video file URL.
3. **Run and wait**: the script submits the task and polls until it finishes (up to ~10 minutes), printing progress lines.
4. **Consume the result**: a JSON asset-manifest is printed to stdout (audio / ASR / scenes / keyframes, with cloud URLs). Save or pipe it as needed.

### Deconstruct a video

```bash
python3 <SkillDir>/scripts/parse_via_render.py \
  --url "https://example.com/video.mp4"
```

### Custom scene-change threshold

```bash
python3 <SkillDir>/scripts/parse_via_render.py \
  --url "https://example.com/video.mp4" \
  --scene-threshold 0.4
```

Lower values are more sensitive (more cuts), higher values looser (fewer cuts). Default `0.3`.

### Skip ASR or keyframes

```bash
# audio + scenes only (skip keyframes)
python3 <SkillDir>/scripts/parse_via_render.py --url "https://example.com/video.mp4" --skip-keyframes

# keyframes + scenes only (skip ASR)
python3 <SkillDir>/scripts/parse_via_render.py --url "https://example.com/video.mp4" --skip-asr
```

### JSON pipeline mode

```bash
python3 <SkillDir>/scripts/parse_via_render.py \
  --url "https://example.com/video.mp4" \
  --json-output
```

Prints only the final manifest JSON to stdout — no progress lines — suitable for piping into downstream tools.

## Common CLI flags

| Flag | Description | Default |
|------|-------------|---------|
| `--url` | Direct remote video URL (required). | — |
| `--scene-threshold` | Scene-change sensitivity 0.0–1.0. | `0.3` |
| `--skip-asr` | Skip the ASR step. | off |
| `--skip-keyframes` | Skip the keyframe-extraction step. | off |
| `--json-output` | Pipeline mode — JSON-only stdout. | off |

## Result manifest shape

`parse_via_render.py` prints the service's `result` payload — a structured manifest whose top-level fields are:

```json
{
  "source":   { "url": "original URL", "durationMs": 12345 },
  "audio":    { "url": "cloud audio URL" },
  "asr":      { "text": "full transcript", "utterances": [ { "text": "...", "startTime": 0, "endTime": 1000, "words": [] } ] },
  "scenes":   [ { "index": 0, "startTimeSec": 0.0, "endTimeSec": 3.5, "keyframe": "cloud keyframe URL" } ],
  "keyframes":[ { "index": 0, "timestampSec": 0.0, "url": "cloud keyframe URL" } ]
}
```

(Exact fields are defined by the ab-render service; treat the above as representative.)

## Optional local tools (not the skill entry)

Two extra scripts ship alongside the entry for local / offline use. They are **not** invoked by the `video_parser` tool and are **not** the skill entry — call them directly with `python3` only when you specifically need local processing:

- **`scripts/deconstruct_video.py`** — a fully local deconstruction alternative that **requires ffmpeg** (`brew install ffmpeg`) and writes `audio.mp3` + `keyframes/` + `deconstruction.json` to an `--output-dir`. Use when there is no ab-render service available. Flags: `--url` / `--local`, `-o/--output-dir`, `--scene-threshold`, `--skip-asr`, `--skip-keyframes`, `--json-output`.
- **`scripts/analyze_video.py`** — a second stage that reads a `deconstruction.json` (or the manifest above saved to disk) and emits a structural-analysis report (hook, narrative structure, pacing, CTA, …). Flags: `-i/--input`, `-o/--output-dir`, `--json-output`.

  ```bash
  python3 <SkillDir>/scripts/analyze_video.py -i ./deconstruction.json
  ```

## Error handling

- **`RENDER_API_URL` not configured**: the script exits with a clear message; set the ab-render service URL.
- **401 / token missing** (non-OpenClaw): set `PRIV_TOKEN`.
- **Business `code != 0`**: read the `msg` printed on stderr.
- **Video download failed**: confirm the URL is a direct video link (share/page links are not supported).
- **Timeout**: very long videos may exceed the ~10-minute poll window; retry or pre-trim.
- **No scene change detected**: a too-high threshold yields zero cuts — lower `--scene-threshold`.
