captions
単語レベルの文字起こしからASS字幕ファイルを生成し、レンダリングに焼き込みます。
引数: $project スラグ、$preset は presets/captions/*.json から選択する名前。完全なリクエストは
$ARGUMENTS に格納されます。空の $プレースホルダは、このスキルがスラッシュ呼び出しではなく自動トリガーされたことを意味します。その場合、セッションコンテキストの PIPELINE_STATE からプロジェクトを取得し、選択したプロジェクトを明示します。動詞名はビルド契約に従います。python engine/ve.py --help が優先されます。
動作を左右する2つのドイツ語固有ルール
1. max_chars でグループ化しない
ドイツ語の複合名詞は分割不可能な1つのトークンであり、文字数上限を簡単に超えます。
Geschwindigkeitsbegrenzung は26文字で、90pxで1920フレームの**約60%**を占有します。
max_chars: 22 のルールではこれを分割できず、オーバーフローするか、グループ化処理が静かに制約を破ります。
代わりにピクセル幅予算でグループ化し、予算を超える単一の単語については自動縮小ルールを適用します。
estimate_text_width_px() が計測を担当し、group_words() が予算を管理します。詳細は docs/fonts.md および engine/vedit/captions.py のモジュールドキュメントに記載されています。
これは最も一般的なドイツ語字幕の失敗であり、完全に回避可能です。
2. フォントは静的で単一ウェイトのファイルを使用し、正確なnameID 1で指定する
可変フォントはASSからウェイトを選択できません。InterVariable.ttf はlibassを通じてArialとバイト単位で同一の出力を生成します。ファイルを読み込んだログは出力されますが、md5は同一になります。終了コード0、警告なし。Style: D,Inter,...,Bold=-1 と指定するとDirectWriteのArialが使用され、YouTubeにエクスポートされるまで誰も気づきません。
以下のフォントのみを使用し、正確な Fontname 文字列と Bold 値を指定してください。
| ファイル | ASS Fontname | Bold |
|---|---|---|
Inter-Regular.ttf | Inter | 0 |
Inter-Bold.ttf | Inter | -1 |
Inter-SemiBold.ttf | Inter SemiBold | 0 |
Inter-ExtraBold.ttf | Inter ExtraBold | 0 |
Montserrat-Bold.ttf | Montserrat | -1 |
Montserrat-ExtraBold.ttf | Montserrat ExtraBold | 0 |
assets/fonts/ にはフォントファイルのみを配置してください。 libassはこのディレクトリ内のすべてのファイルを読み込み、フォント以外のファイルがあるとエラーになります。たとえば、README.mdが置かれていると Error opening memory font 'README.md' が発生します。このディレクトリは、この理由から設定で ask 権限が設定されています。フォントに関するドキュメントが必要な場合は docs/fonts.md に配置してください。
ステップ1 - プリセットを選択する
presets/captions/*.json には、スタイル、グループ化予算、配置、ハイライト動作が定義されています。
好みではなく output.platform に基づいて選択してください。
- 縦型プラットフォームでは、大きく中央揃えで1~3単語、セーフエリアの高い位置に配置します。画面の下3分の1はプラットフォーム自身のUIで隠れます。
- YouTubeの長尺動画では、2行で下端に固定し、スマートフォンでも読みやすいサイズにします。
生成前に選択内容をユーザーに確認し、何が変更されるかを説明してください。
ステップ2 - ASSを生成する
python engine/ve.py captions $project --preset $preset
2つの構造要件があり、どちらも違反すると静かに失敗します。
- 23フィールドのV4+
Style: Format:行(Name..Encoding、libass自身のフィールドリスト。24番目のフィールドAlphaLevelはSSA v4でありASS V4+ではありません)と、10フィールドのEventsFormat:行は正規の形式である必要があり、各行の下の行は正確にその数のカラムを持つ必要があります。カラム数が一致しない場合、libassは終了コード0で終了し、レンダリングテキストに先頭に余分なカンマを挿入し、輪郭と太字を静かに削除します。 これは5フィールドのFormatに対して6フィールドのDialogueで再現されました。captions.validate_ass()は焼き込み前に両方のカラム数をチェックします。これは必須であり、burn_in()は失敗時に処理を拒否します。 - ファイルはUTF-8である必要があります。UTF-8の場合、ドイツ語のダイアクリティカルマークはlibassを通じて正しくラウンドトリップすることが確認されています。
Größe Straße Übermäßig äöüÄÖÜßはエンドツーエンドで検証済みです。
サイドカーファイルは projects/<slug>/out/captions.ass に書き込まれ、captions.sidecar_path から参照されます。
タイミングは、カットに使用されたものと同じ単語リストから取得され、_computed のタイムラインポジションにマッピングされます。したがって、字幕はカットの変更によって無効になります。パッチを当てるのではなく、カット後に再生成してください。
ステップ3 - テキストを修正する(文字起こしは修正しない)
数字は予測可能な問題です。文字起こし時に --suppress_numerals が必須であるため、話者が「20」と言った場合でも文字起こしは zwanzig と出力します。これを修正するには captions.overrides[] に {word_index, text} として追加し、文字起こし自体を決して編集しないでください。文字起こしはプロジェクト内のすべての単語範囲のアンカーであり、書き換えるとカットが同期しなくなります。
固有名詞、製品名、GmbH 形式の略語についても同様です。これらは score の低い単語をスキャンすることで一回のパスで収集します。アライメントスコアはフィラー信号としては役に立ちませんが、「アライナーがこの単語が何か確信を持てなかった」という信号としては優れており、これはまさに固有名詞の特徴です。
ステップ4 - 焼き込み
python engine/ve.py render $project
焼き込みは最終マルチプレクス時、連結された動画に対して1回だけ行われます。セグメントごとに焼き込むことはありません。セグメントごとの焼き込みは、カット境界ごとに同じ字幕を再レンダリングし、カットの両側に部分的な行が配置されることになります。
subtitles= と fontsdir= のエスケープは正確かつ非自明です。すべてスラッシュ(前方)を使用し、値は引用符で囲み、ドライブのコロンは単一エスケープします。
subtitles='C\:/Users/me/.../out/captions.ass':fontsdir='C\:/Users/me/.../assets/fonts'
vedit/ffmpeg.py の escape_filter_path() がこれを担当し、引用符を含めた文字列を返します。自分で引用符を追加しないでください。ネストの深さではなく、引用が重要です。引用符なしの単一エスケープ形式は No option name near '/Users/...' で失敗し、引用符で囲まれた形式のみがパス内のカンマ、セミコロン、括弧(Windowsではすべて有効)を正しく処理できます。escape_filter_path_nested() は、ダブルエスケープされた引用符なしの C\\:/... 形式を返します。この制限はドキュメント化されています。
すべてはPythonからのargvリストを経由します。Git Bashで同じパスを構築すると C\;C:\Program Files\Git\Users\... のようになります。これは実際に再現された問題です。
captions.enabled と captions.burn_in を設定し、stage を "captions" に設定します。
ステップ5 - フォントが実際に読み込まれたことを確認する
QCチェック(e)は必須であり、サイレントフォールバックを検出する唯一の方法です。 プロジェクトスタイルで1フレームのキャプションをレンダリングし、Arial コントロールスタイルで別の1フレームをレンダリングし、ハッシュが異なることを確認します。ハッシュが同一である場合、libassがフォールバックしたことを意味し、エクスポートは間違った書体で出力されます。
その後、さらに以下の項目も確認してください。Format: 行のフィールド数、ピクセル予算を超える行がないこと、セグメント境界をまたいで断片が残るようなキャプションがないこと。
障害モード
| 症状 | 原因 | 修正 |
|---|---|---|
| キャプションがArialのように見える | 可変フォント、または誤った Fontname | 静的ファイル + 正確なnameID 1の文字列を使用。QC(e)を実行 |
| テキストに先頭カンマ、輪郭なし | 不正な Format: 行 | 正規の23/10フィールド行を出力 |
Error opening memory font 'README.md' | assets/fonts/ にフォント以外のファイルが存在 | そのディレクトリにはフォントのみを配置 |
| 長い単語がフレームからはみ出る | max_chars でグループ化 | ピクセル幅予算 + 単一単語の自動縮小 |
No option name near '/Users/...' | fontsdir の単一エスケープ | コロンの前のバックスラッシュを二重にする |
| 数字がスペルアウトされる | --suppress_numerals(仕様通り) | captions.overrides エントリ |
| 再カット後に字幕が非同期になる | 古いASS | 再生成。手動でタイミングを修正しない |