videolabs サイトの公開
「公開」とは、すべてのラボを含むサイト全体が毎回デプロイされることを意味します。
サイトリポジトリ: /opt/opus/videolabs (github.com/bigzaqui/videolabs、main ブランチへのプッシュで https://videolabs.pages.dev にデプロイ。GitHub Actions が site/ フォルダを公開します)。
ラボ: /opt/opus/videolabs/labs/<slug>/ (同じリポジトリ内、スラッグごとに1フォルダ。スラッグは MP4 ファイル名 out/<slug>.mp4 に対応)。これらは videolabs_create-video スキル (node engine/cli.mjs <slug> ...) で構築されます。
動画はプライベート R2 バケット videolabs 内の <slug>/<slug>.mp4 に保存され、/media/<slug>/<slug>.mp4 を通じて配信されます。このパスは Turnstile セッションで保護されており(セッションなしのリクエストは 401 を返します)。
認証情報: /opt/opus/videolabs/.env (スクリプトから読み込まれます。テンプレートは .env.example)。シークレットを表示、コピー、コミットしてはいけません。GitHub リポジトリは 公開 です(ユーザーはナレーション音声、スクリプト、キャプチャ、ラボ出力について問題なく、破棄されたラボの使い捨てパスワードがそこに表示されても構いません)。そのため、いかなるファイルにも 実際の 認証情報が含まれてはいけません。このスキルのソースはリポジトリ内の skills/videolabs_publish/ にあり、scripts/setup.sh によって ~/.claude/skills にリンクされています。
ラボに必要なもの(スクリプトでチェック)
out/<slug>.mp4(fast-start 形式:moovがmdatより前にあること。修正するにはffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4を実行)、out/player/chapters.json(node engine/cli.mjs <slug> playerで生成)、out/spot.jpg(ポスター画像。ffmpeg -ss 425 -i out/<slug>.mp4 -frames:v 1 -q:v 3 out/spot.jpgでダイアグラムのフレームを取得)。- オプション:
out/player/lab.json(ラボにlab/lab-meta.json、lab/*.sh、lab/captures/がある場合、node engine/cli.mjs <slug> playerで生成)。これがある場合、site/lab.jsがラボページにラボリソースを表示します。キャプチャやlab-meta.jsonが変更された場合は、最初にnode engine/cli.mjs <slug> playerを再実行してください。 labs/<slug>/lab.config.jsonにはtitle、description、tagsが必要です。スクリプトはこのファイルからsite/labs.jsonのエントリを追加または更新し(minutesとlessonsも自動入力されるため)、カタログを手動で編集しないでください。新しいラボの場合、タイトル/説明/タグはラボのスクリプトから明らかであればそれを使用し、そうでなければユーザーに確認してください。黙ってでっち上げないでください。
手順
- 計画.
cd /opt/opus/videolabs && scripts/publish-all.sh --dry-runを実行します。各ラボに対して1行のPLAN(アップロードまたはスキップの内容、lab.jsonがあるかどうか)、公開できないラボに関するATTENTION行(ファイルがない、fast-start でない、lab.config.jsonがないなど)、プロジェクトがないカタログエントリに関するNOTE行が出力されます。終了コード2はATTENTIONが1つ以上あることを意味します。それぞれ修正し(lab.config.jsonを作成、node engine/cli.mjs <slug> playerを実行、ポスターを作成するなど)、ATTENTIONがなくなるまで繰り返すか、どのラボを除外するかとその理由をユーザーに伝えます。計画を数行でユーザーに表示し、どの動画がアップロードされるかとそのサイズを含めます。- アップロード記録がないラボ (
state/<slug>.sha256がない) はアップロードされます。ユーザーが R2 にすでに同じファイルがあると言った場合は、--adopt <slug>を使用してハッシュを記録し、アップロードをスキップします。--force-uploadはすべてを再アップロードします。ユーザーが動画の差し替えを依頼した場合のみ使用してください(再アップロード後、最大24時間キャッシュされる可能性があります)。
- アップロード記録がないラボ (
- 同期.
scripts/publish-all.sh(同じフラグ) を実行します。準備のできた各ラボについて、まずレンダリングをout/<slug>.web.mp4に圧縮します (scripts/compress-mp4.sh: モノラル AAC 64k + x264 CRF 28、サイズ約65%削減、動画12分あたり約5分、レンダリングが変更されていない間はキャッシュされます。レンダリング自体は変更されません)。次に、その Web コピーが変更されていれば R2 にアップロードし、lab.config.jsonからカタログエントリを追加/更新し、chapters.json、poster.jpg、lab.jsonをコピーします(ラボにない場合はサイトフォルダから削除)、新しいラボ用のページindex.htmlを作成し(共有テンプレートから、タイトルと説明を含む)、動画のハッシュをstate/<slug>.sha256に記録し、site/labs.jsonのminutes/lessonsを更新します。アップロードは何もプッシュされる前に行われるため、動画なしでページが公開されることはありません。再実行しても安全です。 - 確認とコミット. 最初に
scripts/check-secrets.shを実行します(.envの値がファイルに出現した場合、API キー、トークン、パスワード変数に値を代入している場合、または秘密鍵が存在する場合に失敗します)。報告された問題を修正してから進めてください。videolabs リポジトリのgit statusと差分サマリーをユーザーに表示します(新規/変更されたラボ、labs.json、state/、および共有プレイヤーコードの変更。以下参照)。ラボが GitHub の動画リクエスト(video-requestラベルが付いた Issue)に対応する場合は、コミットメッセージの本文にCloses #Nを含めて、mainへのプッシュで Issue がクローズされるようにします。labs/*/audio/が変更された場合も含め、すべてをコミットします(メッセージ例:Publish labs: ceph-first-steps (new), kafka-in-a-nutshell (lab page)、セッションの帰属リマインダーからの Co-Authored-By 行を追加)。そしてgit push origin mainを実行します(SSH リモートは設定済み)。ワーキングツリーに今回のリクエストに無関係な共有プレイヤーコードの変更がある場合は、それらを含めるかどうかを確認してください。 - デプロイ. GitHub Actions の実行が完了するのを待ちます (
curl -s https://api.github.com/repos/bigzaqui/videolabs/actions/runs?per_page=1でstatus/conclusionを確認。約20秒間隔で最大約3分間ポーリング)。失敗した場合は報告し、盲目的に再試行しないでください。シークレット欠落エラーの場合は、リポジトリシークレットCLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_IDの確認が必要です。 site/labs.json内のすべてのラボを検証(新しいラボだけでなく):/が 200 を返しラボを一覧表示すること、/labs/<slug>/が 200 を返すこと、/labs/<slug>/chapters.jsonが JSON を返すこと(HTML フォールバックではない: サイトは未知のパスにも 200 を返すため、コンテンツタイプまたは本文を確認)、/labs/<slug>/lab.jsonがラボがある場合に JSON を返すこと、/media/<slug>/<slug>.mp4がセッションなしで 401 を返すこと(ゲートが機能している証拠)。再生自体には Turnstile チェック付きのブラウザセッションが必要なため、再生は行われなかったことを伝えます。URL を報告します:https://videolabs.pages.dev/labs/<slug>/。
1つのラボのみを公開する場合(まれ)、scripts/publish-lab.sh <lab-dir> <slug> "<title>" "<description>" を実行し、site/labs.json を手動で更新してから、手順3に進んでください。
共有コード
site/labs/kafka-in-a-nutshell/index.html は新しいラボごとにコピーされるページテンプレートです(タイトル、見出し、説明は実行時に site/labs.json から取得)。site/lab.js はラボに lab.json がある場合にラボリソースをレンダリングします。site/gate.js は Turnstile チェックです。これらを変更すると、次回のプッシュですべてのラボに影響するため、既存のラボで最初に確認してください。既存のラボはそれぞれ独自の index.html コピーを保持しています。テンプレートの変更が既存ラボに反映されるのは、そのコピーも更新された場合のみです。