影片編輯(螢幕錄製 / OBS / 談話錄音)
Script 工具包:此技能的 scripts/ 目錄(prep.sh, transcript_txt.py, ocr_scan.py,
cam_flags.py, df_enhance.py, build_edl.py, render.py, verify_output.py,
chapters.py, overview.py, job.example.json, selftest.sh)。執行時請將其複製到
<workdir>/scripts/ 中,確保任務不依賴技能目錄。scripts/selftest.sh 可在數分鐘內驗證完整安裝。
輸入
<src>:原始錄製檔,通常是~/Desktop中最新的*.mov(OBS 命名格式YYYY-MM-DD HH-MM-SS.mov)。若有多個近期錄製檔,請先確認哪一個是正確的再開始漫長的流程——編輯錯誤的檔案會浪費一個小時。<target_minutes>:若未指定則詢問;一般從 45-90 分鐘的來源剪輯成 20-30 分鐘。<workdir>:全新的暫存目錄,例如/tmp/<session>/edit。- 工具鏈:
ffmpeg6+,python3,mlx_whisper, DeepFilterNet3, Pillow/numpy/soundfile, Apple Vision (pyobjc-framework-Vision/-Quartz).
步驟
- 偵查,絕不碰觸原始檔。
ffprobe <src>(解析度、fps、音訊)。僅在工作目錄中使用副本或提取的檔案。 - 前置處理。
prep.sh "<src>" $W:orig48.wav,mono16.wav,frames/(每 2 秒一張)、camall/(網路攝影機裁切,1 fps,幾何資訊根據解析度自動推導)、sheet_overview.jpg,silences_raw.txt(僅供診斷)、以及transcript.json(mlx_whisper large-v3-turbo,含逐詞時間戳記,約需 4 分鐘)。Whisper 在 prep 返回後仍會持續在背景執行——請立即啟動df_enhance.py orig48.wav df_enhanced.wav(DeepFilterNet3,CPU 約需 6 分鐘),此步驟與前置處理獨立。 - 閱讀完整逐字稿(透過
transcript_txt.py ... --from/--to分為 3 段讀取)。將保留範圍(以原始秒數為單位)寫入job.json -> keep。靜音修剪幅度很小(約 47 分鐘中修剪 2 分鐘);真正的長度縮減來自內容判斷。Whisper 會自我提示:某個詞重複 10 次以上或連續空白片段 = 無意義內容,應予切除。 - 視覺靜止檢查。 「什麼都沒發生」通常是視覺上的靜止,而非音訊靜音。對 0.5 fps 的畫面進行幀差分析:若在約 10 秒的視窗內像素變化小於 1% = 無活動;將間隔不超過 1 秒的短暫活動合併;需連續 >=4 秒才進行裁剪;保留 0.5 秒的緩衝。閃爍的游標或轉圈圈會偽造活動——請遮蔽或調高閾值;檢查中間幀是否有「變化後立即恢復」的突發狀況。打字屬於噪音而非靜音:音量閘門應使用增強音軌上的 RMS(
pause.loud_db),絕不使用原始的silencedetect。 - 開場。 剪掉第一個真正內容之前的全部片段。若開頭緩慢/無聊,則從最有趣的示範開始;可選用 1-2 個精彩片段作為冷開場,然後加速導入。絕不以桌面背景或黑畫面開場——前 30 秒雜亂無章會讓觀眾覺得品質低劣。
- 洩漏掃描(在你閱讀時同步執行)。 在
frames/上執行ocr_scan.py scan(先run):IPv4/v6,*.ts.net,電子郵件,API 金鑰,ssh 相關內容。對每個終端機/設定檔密集出現的區段進行 2 fps 的密集掃描(ocr_scan.py dense src.mov dense 600:60 ...)。靜態文字使用實心方塊覆蓋(boxes);滾動的終端機輸出則對整個窗格進行模糊處理(blur視窗 +blur_regions,使用原始像素座標)——逐行標記會遺漏取樣間的文字。127.0.0.1/localhost可保留。將每個處理過的視窗記錄在job.json中。 - 隱私裁剪(網路攝影機)。
cam_flags.py(透過 Vision 偵測手接近嘴巴的動作)+cam_flags.py --sheet S:DUR對每個標記的叢集以 2 fps 產生特寫畫面。剪掉使用者不願公開的時刻:停頓時手放在臉上、離開座位、其他人入鏡、全臉佔滿畫面。一般的思考姿勢和小動作則可保留。絕不為了手勢而在一句話中間進行裁剪——應對齊到最近的句子邊界,並註明遺失的內容。 - 使用者指定的時間戳記裁剪需嚴格執行。 "cut 0000 - 01:12" -> 將其放入
job.cuts(或keep),精確套用,然後重新檢查接合處的節奏。 - 音訊母帶處理。 合理性檢查:增強音軌與原始音軌的相關係數 > 0.95(
df_enhance.py會輸出此數值)。預設audio_chain為:高通 75 Hz,圍繞 220 Hz / 3.2 kHz / 9 kHz 的減/增,de-esser,3:1 壓縮器;若有持續的風扇噪音,可新增equalizer項進行陷波濾波;render.py會進行兩次 loudnorm 正規化至 -16 LUFS / -1.5 dBTP。原始麥克風音軌保留為音軌 2。 - EDL + 渲染。
build_edl.py->segments.json(保留段落內大於 0.7 秒的停頓縮短為 0.4 秒;對齊至偵測到的幀率;小於 0.3 秒的片段直接丟棄)。render.py:分組平行h264_videotoolbox編碼,透過-c copy拼接,混流兩個音軌。可按組重新執行——若某組失敗,修復後重新執行,未變動的組別會跳過。預設輸出 1080p,除非另有要求(4K 會讓渲染時間加倍且無實際效益)。 - 交付前驗證。
verify_output.py在以下情況會以非零值退出:幀數與 EDL 不符、兩個音軌長度與影片不一致、以 4 fps 對輸出影片的每個遮罩視窗進行 OCR 掃描時發現任何洩漏。同時提取每個隱私裁剪點以及 0:00-1:00 的輸出畫面並親自檢查。若素材敏感,可使用--full進行全檔洩漏掃描。 - 重新轉錄新剪輯。 逐字稿、字幕和章節必須對應輸出的時間線,而非來源——請對剪輯後的影片重新執行 Whisper(或使用
chapters.py,它會透過 EDL 重新映射時間)再寫入 SRT/章節。絕不能直接使用來源逐字稿的時間戳記。 - 中繼資料 + 交付。 無需二次要求:章節時間戳記(
chapters.py,>=3 個,第一個在 0:00),2-3 個標題選項,約 30 個標籤(總長度小於 500 字元;可依要求提供 +2 組標籤/描述變體),描述,每種語言的 SRT(每行約 42 字元;可依要求提供多語言版本),皆為純文字。透過 youtube-pack 產生縮圖:閱讀使用者最近 10 張縮圖的風格;預設為白色/米色背景 + 黑色文字,除非使用者要求否則不放入人臉,Logo 和文字要夠大且不擁擠。最後將<output>.mp4(以及 SRT/中繼資料)移至~/Downloads並open該檔案 / 在預設應用程式中開啟該資料夾。
輸出
<Topic> - YYYY-MM-DD - edit.mp4(1080p,2 個音軌)位於~/Downloads,並在預設應用程式中開啟。<workdir>:job.json、segments.json、group_bounds.json、vf_<n>.txt、遮罩/隱私記錄。~/Downloads:SRT、metadata.txt(標題、描述、標籤、章節)。- 可依要求提供:從同一來源分割的主題子影片,各自附帶章節。
可組合使用
whisper/DFN3 (內建) -> video-edit (驗證過的 mp4 放置於 ~/Downloads) -> youtube-pack (thumbnail.png) -> 瀏覽器上傳至 YouTube Studio(設定與使用者的其他影片一致)。
規則
- 絕不修改原始錄製檔案。
- 目標長度僅供參考;若內容在不刪除核心談話的前提下無法再縮短,則稍微超長交付,並指出接下來的兩個可裁剪段落。
- 在進一步修剪停頓之前,先裁剪整個離題段落;保留硬體相關討論、現場示範、誠實的備註、重點回顧。
- 始終以「移至 ~/Downloads 並開啟」作為結束動作。
- 誠實報告:你無法聽到最終結果——請明確說明,並指向音軌 2。
- 分開錄製的音訊(Discord/Craig)通常不存在;請檢查 Desktop/Downloads/iCloud/Voice Memos,若找不到則使用 OBS 麥克風並告知使用者。
- 當被要求釋放空間時:刪除舊的未接受草稿/變體,保留原始檔和最終版本。
- 多人 podcast:找到正確的音軌(通常來自多個音軌中的 2 個),將音訊對應到正確的講者,隨著講者說話切換對應的影片畫面,並保持轉場乾淨。
- 絕不因為渲染完成就宣稱編輯完成;只有
verify_output.py+ 親自檢查畫面才能確認。
驗證
verify_output.py輸出 PASS(幀數正確、兩個音軌、遮罩視窗內無洩漏)並以 0 值退出。- 親自檢查 0:00-1:00 以及每個隱私裁剪點的畫面(
verify_output.py --sheet 0:60)。 - 對剪輯後的影片進行 SRT 重新轉錄的抽樣比對。
- 使用
ffprobe檢查交付檔案:長度、解析度、fps、兩個音訊串流。
已知失敗情況
- 編輯了錯誤的影片 -> 在執行流程前先確認最新的檔案與主題相符。
- 字幕/章節使用了來源時間線 -> 剪輯後需重新轉錄(步驟 12)。
- 輸出中仍可見主機名稱 -> OCR 取樣間的文字滾動;模糊整個窗格,擴大範圍,然後對輸出進行 OCR。
- Silencedetect 錯誤地裁剪了打字/影片播放的聲音 -> 使用增強音軌的 RMS 進行音量閘門判斷(
pause.loud_db),而非僅靠靜音偵測。 - 開頭黑畫面雜亂 -> 驗證輸出 0:00-1:00 的畫面,以實際內容進行冷開場。
cp -i覆蓋提示 / 沙盒 TCC 封鎖~/Downloads-> 使用/bin/cp並關閉沙盒。- ffmpeg 濾鏡因超過約 100 個
between()條件而當機("Cannot allocate memory") -> 減少render_groups數量。 - 閃爍的游標在幀差分析中被視為活動 -> 遮蔽/調整閾值,檢查中間幀。
render.py幀數不匹配 -> 它會拒絕拼接;請閱讀render_<n>.log(可能是-ss未對齊關鍵幀,或解碼器損壞)。- 當你讀取
transcript.json時 Whisper 仍在執行 ->transcript_txt.py會回報空片段;請等待whisper.log結束。
範例
- 2026-09-02 談話,47 分鐘 -> 26 分鐘:32 個保留範圍,2 個隱私裁剪(9:52-9:58, 26:08-26:14),2 個模糊視窗 + 1 個方塊遮罩用於
*.ts.net主機名稱,渲染約需 2 小時(牆上時鐘),僅透過輸出端 OCR 才發現洩漏。 - 2026-09-24 OBS 教學課程:使用者拒絕了第一個剪輯("背景噪音、打字聲、開頭非常無聊")-> 移除打字噪音、選擇更好的開場、重新製作逐字稿,然後嚴格執行
0:00-1:12的開頭裁剪、洩漏掃描、使用較大 Logo 的白色/米色縮圖、2 組中繼資料變體、移至 Downloads。 - Podcast(2026-09-18):1 小時 40 分鐘影片 + 5 個候選音訊檔 -> 識別出 2 個正確的獨立講者音軌、將聲音對應到影片、1080p、修剪開頭、SRT + 西班牙文/阿拉伯文/印度文翻譯、章節時間戳記、包含兩位講者的縮圖、文字置頂、無黑色背景。