直播切片
Use this skill to convert a local livestream video into transcript-backed short-video clip plans and exports. Local media work uses direct ffmpeg/ffprobe commands only; MCP tools handle OSS upload, TingWu analysis, and LLM JSON planning.
Default Artifacts
Use one output directory per source video:
| File |
Purpose |
metadata.json |
ffprobe metadata |
cover.jpg |
first-frame global cover (fallback) |
cover-NN.jpg |
per-clip smart keyframe cover (scene-change) |
decision-log.md |
auto-decision log (orientation, fill, loudnorm, padding) |
audio.mp3 |
extracted audio for TingWu |
analysis.json |
normalized TingWu result |
invalid-sentences.json |
unusable sentence indexes |
segments.json |
slicing plan |
clip-plan.json |
deterministic clip timings and ffmpeg commands |
subject-clip-plan.json |
deterministic topic-script clip parts and concat commands |
clip_results.json |
local ffmpeg execution results |
clip-manifest.json |
JSON array of delivered clips |
clip-draft-results.json |
CapCut draft creation results (optional) |
exports/ |
cut videos and text exports |
Workflow
Check media tools:
command -v ffmpeg && command -v ffprobe
If either command is missing, tell the operator to install FFmpeg. Python is not required.
Prepare artifacts:
mkdir -p "$DIR" "$DIR/exports"
ffprobe -v error -show_format -show_streams -of json "$VIDEO" > "$DIR/metadata.json"
ffmpeg -y -i "$VIDEO" -vn -ac 1 -ar 16000 -codec:a libmp3lame -q:a 4 "$DIR/audio.mp3"
ffmpeg -y -ss 0 -i "$VIDEO" -frames:v 1 -q:v 2 "$DIR/cover.jpg"
Upload audio:
Call upload_live_audio(file_path="$DIR/audio.mp3").
If storage is local, ask the operator to configure OSS or provide a direct audio_url.
Create TingWu task:
Call create_live_analysis_task(audio_url=..., auto_chapters_enabled=true, summarization_enabled=true, meeting_assistance_enabled=true, diarization_enabled=false, script_template_enable=true).
Poll analysis:
Call query_live_analysis_task(task_id=...) until status is COMPLETED, then save the JSON to analysis.json.
Plan cleanup and cuts:
- Call
recognize_live_invalid_sentences(sentences=analysis.sentences) and save invalid-sentences.json.
- Remove invalid indexes from
analysis.sentences.
- Call
recognize_live_segments(sentences=valid_sentences, ask=optional_user_goal) and save segments.json.
- Detect source orientation with
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$VIDEO" (store $SRC_W/$SRC_H; $SRC_W > $SRC_H is landscape).
- Call
build_live_clip_plan(sentences=analysis.sentences, segments=segments.segments, invalid=invalid.invalid, video_path="$VIDEO", output_dir="$DIR", target_mode="vertical", vertical_fill="blur", source_width=$SRC_W, source_height=$SRC_H, target_width=1080, target_height=1920, normalize_audio_loudness=true, head_padding_seconds=0.15, tail_padding_seconds=0.30, min_duration_seconds=5, max_duration_seconds=120) and save clip-plan.json.
- Use
recognize_live_subjects and complete_live_subject when the user wants topic-driven clips instead of broad segments, then call build_live_subject_clip_plan(sentences=analysis.sentences, completions=subject_completions, invalid=invalid.invalid, video_path="$VIDEO", output_dir="$DIR", target_mode="vertical", vertical_fill="blur", source_width=$SRC_W, source_height=$SRC_H, target_width=1080, target_height=1920, normalize_audio_loudness=true, head_padding_seconds=0.15, tail_padding_seconds=0.30, min_duration_seconds=5, max_duration_seconds=120) and save subject-clip-plan.json.
- Never hand-convert non-contiguous subject scripts into
segments.json; use build_live_subject_clip_plan.
Cut clips:
Read each item in the selected plan (clip-plan.json or subject-clip-plan.json). Before each command, create parent directories for planned output, parts[].output, and concat_list_path. For single-part clips, run fast_cut_shell first, then use ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$OUT" to read output duration. If the command fails, the output is missing or empty, ffprobe fails, or actual duration differs from planned duration by more than max(1.0s, duration*0.05), run accurate_cut_shell and read duration again. For multi-part clips, run every parts[].accurate_cut_shell, write concat_list_content to concat_list_path, run concat_shell, then read the final duration. Save one execution result per clip to clip_results.json with actual_duration_seconds; include part_results only for multi-part clips. When fast_cut_shell is empty (the tool set method="encode" because the source is landscape and must be verticalized with a filter), skip straight to accurate_cut_shell — the vertical blur/scale filter requires re-encoding and -c copy is invalid. The tool-generated accurate_cut_args already include -pix_fmt yuv420p, -crf 20, -movflags +faststart, the vertical -vf filter, and -af loudnorm.
Build delivery files:
Call build_live_clip_manifest(source_video="$VIDEO", tingwu_task_id="$TINGWU_TASK_ID", analysis_title=analysis.title, sentences=analysis.sentences, invalid=invalid.invalid, warnings=plan.warnings, rejected=plan.rejected, clips=plan.clips, clip_results=clip_results) and write:
clip_manifest to clip-manifest.json as a JSON array with each clip transcript.
transcript_markdown to transcript.md.
summary_markdown to summary.md.
clip_notes_markdown[].markdown to clip_notes_markdown[].markdown_path.
Export to CapCut (optional):
For each successful clip in clip_results.json, create a CapCut/JianYing draft using the capcut-draft skill. Each clip becomes its own draft with:
- Video segment: the clip's MP4 file (
type: "video"). The exported MP4 is already 1080×1920, so place it at scale=1.0 (no hard upscale).
- Subtitles: from the clip's
transcript array, applying the Short-Video Captions style from the capcut-draft skill (font_size≈10, bold_width=0.1 for weight, white with #FFD60A for selling points/numbers, 0.12 black stroke, 0.8 shadow, transform.y=-0.78 lower-third, <size=10.0>...</size> content — do NOT use <b> tags, they render literally). Split sentences >8 chars into ≤2 chunks at natural pauses, each its own text segment; time offsets are relative to the clip's start (subtitle_start = (chunk.start - clip.start) × 1,000,000 microseconds).
- Cover: the clip's smart keyframe
cover-NN.jpg (see Smart Cover below), falling back to $DIR/cover.jpg.
- Canvas: vertical 9:16 (1080×1920) for short videos
- No effects, transitions, or background music added automatically (audio is already loudness-normalized)
Save results to
clip-draft-results.json. Skip this step entirely if CapCut draft root directory is not found.
Cutting Commands
Fast cut:
ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c copy "$OUT"
Accurate fallback when copy-mode cuts poorly or fails:
ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c:v libx264 -c:a aac "$OUT"
The templates above are the conceptual minimums. In practice, prefer the accurate_cut_args returned by build_live_clip_plan/build_live_subject_clip_plan — when the source is landscape and target_mode="vertical", the tool emits a full re-encode: the chosen vertical -vf filter (blur-fill by default), -c:v libx264 -preset veryfast -crf 20 -pix_fmt yuv420p, -c:a aac -b:a 128k, -af loudnorm=I=-16:TP=-1.5:LRA=11, and -movflags +faststart. In that case fast_cut_shell is empty and method="encode"; run accurate_cut_shell directly (filtering is incompatible with -c copy). The multi-part concat final pass stays -c copy because every part is already yuv420p.
Single clip example:
START="12.300"
DURATION="38.700"
OUT="$DIR/exports/01-product-proof.mp4"
ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c copy "$OUT"
For automated batches, prefer the fast_cut_shell and accurate_cut_shell fields returned by build_live_clip_plan; do not hand-calculate durations.
Multi-part subject clips use planned part commands and concat fields:
# for each part
ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c:v libx264 -c:a aac "$PART_OUT"
# after writing concat_list_content to concat_list_path
ffmpeg -y -f concat -safe 0 -i "$CONCAT_LIST" -c copy "$OUT"
Duration probe:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$OUT"
Smart Cover
cover.jpg is the global first-frame fallback. For each clip, grab a representative keyframe instead of frame 0: sample near the clip's ~40% point with scene-change detection, falling back to the midpoint:
PIVOT=$(awk 'BEGIN{printf "%.2f", '"$CLIP_START"' + '"$CLIP_DURATION"' * 0.4}')
ffmpeg -y -ss "$PIVOT" -i "$CLIP_PATH" -vf "select=gt(scene\,0.3)" -frames:v 1 -q:v 2 "$DIR/cover-NN.jpg" || \
ffmpeg -y -ss "$(awk 'BEGIN{printf "%.2f", '"$CLIP_DURATION"' / 2}')" -i "$CLIP_PATH" -frames:v 1 -q:v 2 "$DIR/cover-NN.jpg"
NN is the two-digit clip index. Use cover-NN.jpg as that clip's CapCut draft cover; fall back to cover.jpg if generation fails.
Text Export
For Markdown transcript exports, write the content directly from analysis.sentences:
# {analysis.title}
- [1] 0.00-3.20s 字幕
- [2] 3.20-7.80s 字幕
For clip notes, write the clip_notes_markdown returned by build_live_clip_manifest; do not invent note content by hand.
JSON Shapes
analysis.json uses:
chapters, sentences, subjects, segments, invalid, qas, topics, words, silents, keywords, key_sentences, templates, audio_info.
Sentence objects:
{"index":1,"start":0.0,"end":3.2,"text":"字幕"}
Segment objects:
{"title":"片段标题","description":"说明","thoughts":"剪辑思路","start":1,"end":8}
Invalid objects:
{"index":1,"reason":"直播间欢迎语"}
Clip plan objects:
{"index":1,"title":"片段标题","sentence_start":1,"sentence_end":8,"start":12.3,"end":51.0,"duration":38.7,"output":"...mp4","fast_cut_shell":"ffmpeg ...","accurate_cut_shell":"ffmpeg ...","parts":[...],"transcript":[...]}
Multi-part subject clip fields:
parts, concat_list_path, concat_list_content, concat_shell, concat_args, script_notes.
Clip manifest is a JSON array of delivered clip objects with status, method, output, duration, actual_duration_seconds, transcript, and optional error fields. clip_notes_markdown contains ready-to-write Markdown notes for each clip: {"index":1,"title":"片段","markdown_path":"...md","markdown":"..."}.
Cutting Rules
- Keep transcript index boundaries intact; never invent timestamps.
- Prefer valid sentences after removing
invalid indexes.
- Pass
head_padding_seconds=0.15, tail_padding_seconds=0.30 to the plan tools so cuts don't clip the first or last word.
- Target short-video sweet spots: pass
max_duration_seconds=120 (15-60s is ideal for livestream hooks). Treat clips >120s as too long and record a warning; drop clips shorter than 5s — the MIN is 5s everywhere (draft-skip and red-flag thresholds agree).
- Aim for semantic diversity across clips (distinct sentence ranges or topics) so the batch is not a set of near-duplicates.
- Favor segments whose first sentence is a conclusion, opinion, pain-point, or contrast (a hook);
complete_live_subject already forces a 3-5s opening hook for subject clips.
- Verticalize for the target platform: pass
target_mode="vertical" and vertical_fill="blur". Landscape sources get a blur-fill re-encode; already-vertical sources get only scale. Audio is loudness-normalized (EBU R128) on re-encode paths, never on -c copy.
- Use
-c copy first for speed only when fast_cut_shell is non-empty; retry with re-encoding (or go straight to it) if a filter is needed or timestamp accuracy is poor.
- For subject clips, preserve selected sentence order unless the LLM explicitly provides a better narrative order.
- Do not cut live-only greetings, thanks, countdowns, real-time stock claims, or room-specific promos into short videos unless the user explicitly asks.
1---2name: live-slice3description: Use when working on live video slicing, 直播切片, 剪直播, 智能切片, 听悟 transcription, or live video slicing workflows that turn long livestream videos into transcript-backed short-video clips.4---56# 直播切片78Use this skill to convert a local livestream video into transcript-backed short-video clip plans and exports. Local media work uses direct `ffmpeg`/`ffprobe` commands only; MCP tools handle OSS upload, TingWu analysis, and LLM JSON planning.910## Default Artifacts1112Use one output directory per source video:1314| File | Purpose |15| --- | --- |16| `metadata.json` | `ffprobe` metadata |17| `cover.jpg` | first-frame global cover (fallback) |18| `cover-NN.jpg` | per-clip smart keyframe cover (scene-change) |19| `decision-log.md` | auto-decision log (orientation, fill, loudnorm, padding) |20| `audio.mp3` | extracted audio for TingWu |21| `analysis.json` | normalized TingWu result |22| `invalid-sentences.json` | unusable sentence indexes |23| `segments.json` | slicing plan |24| `clip-plan.json` | deterministic clip timings and ffmpeg commands |25| `subject-clip-plan.json` | deterministic topic-script clip parts and concat commands |26| `clip_results.json` | local ffmpeg execution results |27| `clip-manifest.json` | JSON array of delivered clips |28| `clip-draft-results.json` | CapCut draft creation results (optional) |29| `exports/` | cut videos and text exports |3031## Workflow32331. Check media tools:34 `command -v ffmpeg && command -v ffprobe`3536 If either command is missing, tell the operator to install FFmpeg. Python is not required.37382. Prepare artifacts:3940 ```bash41 mkdir -p "$DIR" "$DIR/exports"42 ffprobe -v error -show_format -show_streams -of json "$VIDEO" > "$DIR/metadata.json"43 ffmpeg -y -i "$VIDEO" -vn -ac 1 -ar 16000 -codec:a libmp3lame -q:a 4 "$DIR/audio.mp3"44 ffmpeg -y -ss 0 -i "$VIDEO" -frames:v 1 -q:v 2 "$DIR/cover.jpg"45 ```46473. Upload audio:48 Call `upload_live_audio(file_path="$DIR/audio.mp3")`.49 If storage is local, ask the operator to configure OSS or provide a direct `audio_url`.50514. Create TingWu task:52 Call `create_live_analysis_task(audio_url=..., auto_chapters_enabled=true, summarization_enabled=true, meeting_assistance_enabled=true, diarization_enabled=false, script_template_enable=true)`.53545. Poll analysis:55 Call `query_live_analysis_task(task_id=...)` until `status` is `COMPLETED`, then save the JSON to `analysis.json`.56576. Plan cleanup and cuts:58 - Call `recognize_live_invalid_sentences(sentences=analysis.sentences)` and save `invalid-sentences.json`.59 - Remove invalid indexes from `analysis.sentences`.60 - Call `recognize_live_segments(sentences=valid_sentences, ask=optional_user_goal)` and save `segments.json`.61 - Detect source orientation with `ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$VIDEO"` (store `$SRC_W`/`$SRC_H`; `$SRC_W > $SRC_H` is landscape).62 - Call `build_live_clip_plan(sentences=analysis.sentences, segments=segments.segments, invalid=invalid.invalid, video_path="$VIDEO", output_dir="$DIR", target_mode="vertical", vertical_fill="blur", source_width=$SRC_W, source_height=$SRC_H, target_width=1080, target_height=1920, normalize_audio_loudness=true, head_padding_seconds=0.15, tail_padding_seconds=0.30, min_duration_seconds=5, max_duration_seconds=120)` and save `clip-plan.json`.63 - Use `recognize_live_subjects` and `complete_live_subject` when the user wants topic-driven clips instead of broad segments, then call `build_live_subject_clip_plan(sentences=analysis.sentences, completions=subject_completions, invalid=invalid.invalid, video_path="$VIDEO", output_dir="$DIR", target_mode="vertical", vertical_fill="blur", source_width=$SRC_W, source_height=$SRC_H, target_width=1080, target_height=1920, normalize_audio_loudness=true, head_padding_seconds=0.15, tail_padding_seconds=0.30, min_duration_seconds=5, max_duration_seconds=120)` and save `subject-clip-plan.json`.64 - Never hand-convert non-contiguous subject scripts into `segments.json`; use `build_live_subject_clip_plan`.65667. Cut clips:67 Read each item in the selected plan (`clip-plan.json` or `subject-clip-plan.json`). Before each command, create parent directories for planned `output`, `parts[].output`, and `concat_list_path`. For single-part clips, run `fast_cut_shell` first, then use `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$OUT"` to read output duration. If the command fails, the output is missing or empty, `ffprobe` fails, or actual duration differs from planned duration by more than `max(1.0s, duration*0.05)`, run `accurate_cut_shell` and read duration again. For multi-part clips, run every `parts[].accurate_cut_shell`, write `concat_list_content` to `concat_list_path`, run `concat_shell`, then read the final duration. Save one execution result per clip to `clip_results.json` with `actual_duration_seconds`; include `part_results` only for multi-part clips. When `fast_cut_shell` is empty (the tool set `method="encode"` because the source is landscape and must be verticalized with a filter), skip straight to `accurate_cut_shell` — the vertical blur/scale filter requires re-encoding and `-c copy` is invalid. The tool-generated `accurate_cut_args` already include `-pix_fmt yuv420p`, `-crf 20`, `-movflags +faststart`, the vertical `-vf` filter, and `-af loudnorm`.68698. Build delivery files:70 Call `build_live_clip_manifest(source_video="$VIDEO", tingwu_task_id="$TINGWU_TASK_ID", analysis_title=analysis.title, sentences=analysis.sentences, invalid=invalid.invalid, warnings=plan.warnings, rejected=plan.rejected, clips=plan.clips, clip_results=clip_results)` and write:71 - `clip_manifest` to `clip-manifest.json` as a JSON array with each clip transcript.72 - `transcript_markdown` to `transcript.md`.73 - `summary_markdown` to `summary.md`.74 - `clip_notes_markdown[].markdown` to `clip_notes_markdown[].markdown_path`.75769. Export to CapCut (optional):77 For each successful clip in `clip_results.json`, create a CapCut/JianYing draft using the `capcut-draft` skill. Each clip becomes its own draft with:78 - Video segment: the clip's MP4 file (`type: "video"`). The exported MP4 is already 1080×1920, so place it at `scale=1.0` (no hard upscale).79 - Subtitles: from the clip's `transcript` array, applying the **Short-Video Captions** style from the `capcut-draft` skill (font_size≈10, `bold_width=0.1` for weight, white with `#FFD60A` for selling points/numbers, 0.12 black stroke, 0.8 shadow, `transform.y=-0.78` lower-third, `<size=10.0>...</size>` content — do NOT use `<b>` tags, they render literally). Split sentences >8 chars into ≤2 chunks at natural pauses, each its own text segment; time offsets are relative to the clip's start (`subtitle_start = (chunk.start - clip.start) × 1,000,000` microseconds).80 - Cover: the clip's smart keyframe `cover-NN.jpg` (see Smart Cover below), falling back to `$DIR/cover.jpg`.81 - Canvas: vertical 9:16 (1080×1920) for short videos82 - No effects, transitions, or background music added automatically (audio is already loudness-normalized)83 Save results to `clip-draft-results.json`. Skip this step entirely if CapCut draft root directory is not found.8485## Cutting Commands8687Fast cut:8889```bash90ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c copy "$OUT"91```9293Accurate fallback when copy-mode cuts poorly or fails:9495```bash96ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c:v libx264 -c:a aac "$OUT"97```9899The templates above are the conceptual minimums. In practice, prefer the `accurate_cut_args` returned by `build_live_clip_plan`/`build_live_subject_clip_plan` — when the source is landscape and `target_mode="vertical"`, the tool emits a full re-encode: the chosen vertical `-vf` filter (blur-fill by default), `-c:v libx264 -preset veryfast -crf 20 -pix_fmt yuv420p`, `-c:a aac -b:a 128k`, `-af loudnorm=I=-16:TP=-1.5:LRA=11`, and `-movflags +faststart`. In that case `fast_cut_shell` is empty and `method="encode"`; run `accurate_cut_shell` directly (filtering is incompatible with `-c copy`). The multi-part concat final pass stays `-c copy` because every part is already yuv420p.100101Single clip example:102103```bash104START="12.300"105DURATION="38.700"106OUT="$DIR/exports/01-product-proof.mp4"107ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c copy "$OUT"108```109110For automated batches, prefer the `fast_cut_shell` and `accurate_cut_shell` fields returned by `build_live_clip_plan`; do not hand-calculate durations.111112Multi-part subject clips use planned part commands and concat fields:113114```bash115# for each part116ffmpeg -y -ss "$START" -i "$VIDEO" -t "$DURATION" -c:v libx264 -c:a aac "$PART_OUT"117118# after writing concat_list_content to concat_list_path119ffmpeg -y -f concat -safe 0 -i "$CONCAT_LIST" -c copy "$OUT"120```121122Duration probe:123124```bash125ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$OUT"126```127128## Smart Cover129130`cover.jpg` is the global first-frame fallback. For each clip, grab a representative keyframe instead of frame 0: sample near the clip's ~40% point with scene-change detection, falling back to the midpoint:131132```bash133PIVOT=$(awk 'BEGIN{printf "%.2f", '"$CLIP_START"' + '"$CLIP_DURATION"' * 0.4}')134ffmpeg -y -ss "$PIVOT" -i "$CLIP_PATH" -vf "select=gt(scene\,0.3)" -frames:v 1 -q:v 2 "$DIR/cover-NN.jpg" || \135 ffmpeg -y -ss "$(awk 'BEGIN{printf "%.2f", '"$CLIP_DURATION"' / 2}')" -i "$CLIP_PATH" -frames:v 1 -q:v 2 "$DIR/cover-NN.jpg"136```137138`NN` is the two-digit clip index. Use `cover-NN.jpg` as that clip's CapCut draft cover; fall back to `cover.jpg` if generation fails.139140## Text Export141142For Markdown transcript exports, write the content directly from `analysis.sentences`:143144```markdown145# {analysis.title}146147- [1] 0.00-3.20s 字幕148- [2] 3.20-7.80s 字幕149```150151For clip notes, write the `clip_notes_markdown` returned by `build_live_clip_manifest`; do not invent note content by hand.152153## JSON Shapes154155`analysis.json` uses:156`chapters`, `sentences`, `subjects`, `segments`, `invalid`, `qas`, `topics`, `words`, `silents`, `keywords`, `key_sentences`, `templates`, `audio_info`.157158Sentence objects:159`{"index":1,"start":0.0,"end":3.2,"text":"字幕"}`160161Segment objects:162`{"title":"片段标题","description":"说明","thoughts":"剪辑思路","start":1,"end":8}`163164Invalid objects:165`{"index":1,"reason":"直播间欢迎语"}`166167Clip plan objects:168`{"index":1,"title":"片段标题","sentence_start":1,"sentence_end":8,"start":12.3,"end":51.0,"duration":38.7,"output":"...mp4","fast_cut_shell":"ffmpeg ...","accurate_cut_shell":"ffmpeg ...","parts":[...],"transcript":[...]}`169170Multi-part subject clip fields:171`parts`, `concat_list_path`, `concat_list_content`, `concat_shell`, `concat_args`, `script_notes`.172173Clip manifest is a JSON array of delivered clip objects with status, method, output, duration, actual_duration_seconds, transcript, and optional error fields. `clip_notes_markdown` contains ready-to-write Markdown notes for each clip: `{"index":1,"title":"片段","markdown_path":"...md","markdown":"..."}`.174175## Cutting Rules176177- Keep transcript index boundaries intact; never invent timestamps.178- Prefer valid sentences after removing `invalid` indexes.179- Pass `head_padding_seconds=0.15, tail_padding_seconds=0.30` to the plan tools so cuts don't clip the first or last word.180- Target short-video sweet spots: pass `max_duration_seconds=120` (15-60s is ideal for livestream hooks). Treat clips >120s as too long and record a warning; drop clips shorter than 5s — the MIN is 5s everywhere (draft-skip and red-flag thresholds agree).181- Aim for semantic diversity across clips (distinct sentence ranges or topics) so the batch is not a set of near-duplicates.182- Favor segments whose first sentence is a conclusion, opinion, pain-point, or contrast (a hook); `complete_live_subject` already forces a 3-5s opening hook for subject clips.183- Verticalize for the target platform: pass `target_mode="vertical"` and `vertical_fill="blur"`. Landscape sources get a blur-fill re-encode; already-vertical sources get only `scale`. Audio is loudness-normalized (EBU R128) on re-encode paths, never on `-c copy`.184- Use `-c copy` first for speed only when `fast_cut_shell` is non-empty; retry with re-encoding (or go straight to it) if a filter is needed or timestamp accuracy is poor.185- For subject clips, preserve selected sentence order unless the LLM explicitly provides a better narrative order.186- Do not cut live-only greetings, thanks, countdowns, real-time stock claims, or room-specific promos into short videos unless the user explicitly asks.