發布 videolabs 網站
「發布」表示每次都會部署包含所有實驗室的完整網站。
網站儲存庫:/opt/opus/videolabs (github.com/bigzaqui/videolabs,推送至 main 分支時部署至 https://videolabs.pages.dev;GitHub Actions 發布 site/ 資料夾)。
實驗室:/opt/opus/videolabs/labs/<slug>/(每個實驗室一個資料夾,位於同一個儲存庫中;slug 即 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會在實驗室頁面上顯示實驗室資源。如果 captures 或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。它會為每個實驗室印出一行PLAN(說明將上傳或略過的內容、是否有lab.json),為無法發布的實驗室印出ATTENTION行(缺少檔案、未 fast-start、無lab.config.json),以及為沒有對應項目的目錄條目印出NOTE行。Exit code 2 表示至少有一個ATTENTION。逐一修正每個問題(撰寫lab.config.json、執行node engine/cli.mjs <slug> player、製作海報等)並重複直到沒有問題為止,或告知使用者哪個實驗室被排除及其原因。用簡潔的幾行向使用者顯示規劃內容,包括將上傳哪些影片及其大小。- 沒有記錄上傳的實驗室(缺少
state/<slug>.sha256)會進行上傳。如果使用者表示 R2 中已經存在完全相同的檔案,請使用--adopt <slug>記錄其雜湊值而不實際上傳。--force-upload會重新上傳所有內容;僅在使用者要求取代影片時使用(重新上傳後,檢視者端可能仍會快取長達 24 小時)。
- 沒有記錄上傳的實驗室(缺少
- 同步。
scripts/publish-all.sh(使用相同的旗標)。對於每個準備就緒的實驗室,它會先將渲染結果壓縮為out/<slug>.web.mp4(scripts/compress-mp4.sh:mono AAC 64k + x264 CRF 28,約縮小 65% 大小,每 12 分鐘影片約需 5 分鐘,在渲染內容未變更時會快取;渲染本身絕不會被修改),然後將該網路複本上傳至 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 金鑰、令牌或密碼變數賦值,或存在私鑰,則會失敗),並在繼續前修正其報告的任何問題。向使用者顯示git status以及 videolabs 儲存庫的差異摘要(新增/變更的實驗室、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 remote 已設定)。如果工作目錄中對共用播放器程式碼的變更並非本次請求的一部分,請在包含前先詢問。 - 部署。 等待 GitHub Actions 執行完成(
curl -s https://api.github.com/repos/bigzaqui/videolabs/actions/runs?per_page=1,檢查status/conclusion;大約每 20 秒輪詢一次,最多約 3 分鐘)。如果失敗,請回報問題,不要盲目重試;missing-secret 錯誤表示儲存庫機密CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID需要處理。 - 驗證
site/labs.json中的每一個實驗室(不僅是新實驗室):/回傳 200 並列出它們;/labs/<slug>/回傳 200;/labs/<slug>/chapters.json回傳 JSON(不是 HTML 回退頁面:網站對未知路徑會回傳 200,因此請檢查 Content-Type 或回應內容);/labs/<slug>/lab.json對於有 lab.json 的實驗室回傳 JSON;/media/<slug>/<slug>.mp4在沒有工作階段時回傳 401(證明閘道已啟用)。播放本身需要包含 Turnstile 檢查的瀏覽器工作階段,因此請說明未進行播放。回報 URL:https://videolabs.pages.dev/labs/<slug>/。
若僅想發布一個實驗室(較罕見),請執行 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 副本;範本變更僅在其副本也一併更新時才會套用到它們。