/video-subtitle — 動画字幕ツール
ローカルの Whisper モデルを使用して動画音声を SRT 字幕に書き起こし、動画に焼き付けます。
ユーザー呼び出し可能
ユーザーが /video-subtitle と入力したら、このスキルを実行します。
前提条件
このスキルには 2 つのツールが必要です。実行前に利用可能性を確認してください。
1. mlx-whisper(Apple Silicon)または openai-whisper
どちらが利用可能かを検出します:
which mlx_whisper whisper 2>/dev/null
どちらも見つからない場合、ユーザーにいずれかのインストールを案内してください:
- Apple Silicon Mac(推奨):
pip install mlx-whisper - 任意のプラットフォーム:
pip install openai-whisper
2. ffmpeg(libass 対応)
libass サポートを確認します:
ffmpeg -filters 2>&1 | grep subtitles
出力がない場合(libass がないと subtitles フィルタは利用不可):
- macOS:
brew install ffmpeg-full(keg-only なので/opt/homebrew/opt/ffmpeg-full/bin/ffmpegを使用) - Linux:
sudo apt install ffmpeg(通常 libass を含む) - 代替: ユーザーが libass なしの通常の ffmpeg しか持っていない場合、焼き付けではなく SRT を字幕トラックとしてソフト埋め込みします。
Whisper モデルの選択
キャッシュされたモデルを確認:
ls ~/.cache/huggingface/hub/ 2>/dev/null | grep whisper
最も大きな利用可能モデルを優先します。何もキャッシュされていない場合:
- mlx-whisper:
mlx-community/whisper-large-v3-mlx - openai-whisper:
large-v3
モード
/video-subtitle path/to/video.mov→ フルパイプライン(書き起こし + 修正 + 焼き付け)/video-subtitle srt path/to/video.mov→ SRT のみ(書き起こし、焼き付けなし)/video-subtitle burn path/to/video.mov path/to/sub.srt→ 焼き付けのみ(既存の SRT を使用)/video-subtitle(引数なし)→ 対話式、動画パスを尋ねます
フルパイプライン
ステップ 1: 動画の確認
パスが指定されていない場合は、AskUserQuestion で尋ねます。ファイルが存在することを確認し、メタデータを読み取ります:
ffmpeg -i "<video_path>" 2>&1 | grep -E "Duration|Stream.*(Video|Audio)"
再生時間、解像度、ファイルサイズをユーザーに報告します。
ステップ 2: 音声抽出
ffmpeg -i "<video_path>" -vn -acodec pcm_s16le -ar 16000 -ac 1 "<output_dir>/<basename>_audio.wav" -y
16kHz モノラル WAV は Whisper に最適な入力形式です。
ステップ 3: 言語の確認
AskUserQuestion でユーザーに尋ねます。一般的なオプション:
| 言語 | フラグ |
|---|---|
| 中国語 | --language zh |
| 英語 | --language en |
| 日本語 | --language ja |
| 自動検出 | --language を省略 |
ステップ 4: 書き起こし
mlx-whisper:
mlx_whisper --model "<model>" --language <lang> --output-format srt --output-dir "<output_dir>" "<audio_wav>"
openai-whisper:
whisper "<audio_wav>" --model large-v3 --language <lang> --output_format srt --output_dir "<output_dir>"
ユーザーに「書き起こし中です。お待ちください...」と伝えてください。
ステップ 5: SRT のクリーンアップ
生成された SRT を読み取り、以下の修正を行います:
- 幻覚除去: 再生時間がゼロのタイムスタンプ(例
00:00:57,640 --> 00:00:57,640)や空のテキストのエントリを削除 - 固有名詞修正: Whisper が誤認識しがちなブランド名や技術用語を会話の文脈から修正
- フラグメント統合: 0.5 秒未満の短いエントリで意味的につながっているものを結合
- 再採番: 以下の Python スニペットを実行してすべてのエントリを再採番:
python3 -c "
import re
with open('<srt_path>', 'r') as f:
content = f.read()
blocks = re.split(r'\n\n+', content.strip())
out = []
for i, block in enumerate(blocks, 1):
lines = block.strip().split('\n')
if len(lines) >= 2:
lines[0] = str(i)
out.append('\n'.join(lines))
with open('<srt_path>', 'w') as f:
f.write('\n\n'.join(out) + '\n')
"
修正した SRT をユーザーに提示し、焼き付け前に追加の編集が必要かどうかを尋ねます。
ステップ 6: 字幕の焼き付け
適切な ffmpeg バイナリを決定します(通常の ffmpeg に libass がない場合は ffmpeg-full を優先):
FFMPEG="ffmpeg"
if ! ffmpeg -filters 2>&1 | grep -q subtitles; then
if [ -x /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg ]; then
FFMPEG="/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
fi
fi
その後、焼き付け:
$FFMPEG \
-i "<video_path>" \
-vf "subtitles=<srt_path>:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,MarginV=30'" \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
-pix_fmt yuv420p \
"<output_dir>/<basename>_subtitled.mp4" -y
force_style オプション:
| パラメータ | デフォルト | 説明 |
|---|---|---|
| FontSize | 24 | フォントサイズ |
| PrimaryColour | &H00FFFFFF | 白文字 |
| OutlineColour | &H00000000 | 黒い輪郭 |
| Outline | 2 | 輪郭の太さ |
| MarginV | 30 | 下端余白 |
重要: SRT ファイルのパスに ffmpeg のフィルタパーサーを混乱させる特殊文字が含まれていないことを確認してください。必要に応じて相対パスまたはシンボリックリンクを使用してください。
ステップ 7: 完了
出力ファイルのパスとサイズを報告します。open <path> でプレビューするよう提案します。中間ファイル _audio.wav は削除可能であることをユーザーに通知します。
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
No such filter: 'subtitles' | ffmpeg に libass がない | ffmpeg-full を使用するか libass をインストール |
No such filter: 'drawtext' | ffmpeg に libfreetype がない | ffmpeg-full を使用 |
| SRT エントリの重複/空 | Whisper の幻覚 | ステップ 5 でクリーンアップ |
| 中国語の文字が四角く表示される | CJK フォントがない | macOS: 自動で PingFang にフォールバック。Linux: apt install fonts-noto-cjk |
Error parsing filterchain | SRT パスに特殊文字 | 相対パスを使い、スペースを避ける |
品質ルール
- 忠実な書き起こし: 実際に話された内容のみを書き起こし、意味を追加したり書き換えたりしない
- 固有名詞の修正: よくある Whisper の誤認識を修正するが、ユーザーに確認する
- 字幕のリズム: 1 エントリあたり最大 2 行、1 行あたり CJK 文字最大約 20 文字
- 後片付け: 完了後、中間ファイル(_audio.wav)を削除するようユーザーに通知する