這個切片服務的起點,其實一點都不浪漫。
它不是什麼 Side Project Showcase,也不是「我想驗證一個很潮的技術」。
起因非常現實:私人專案,需要私有化部署用 S3-compatible storage(MinIO),但系統裡沒有任何多媒體處理能力,也沒有任何開源的系統能解決我的問題
這問題翻成白話就是:沒得用,只好自己幹
一開始我就知道,這東西不能寫在主系統裡
在寫任何 ffmpeg 指令之前,我先做了一個決定:這一定是一個獨立的 service。
理由很簡單:
- ffmpeg 是 CPU-heavy
- 多媒體處理一定會炸
- 炸的時候不能拖主系統一起死
所以這個服務從第一天開始就只有一個責任:你丟檔案來,我處理完,丟進 S3,回傳結果
不碰帳號、不碰權限、不碰業務邏輯
第一版:只有單畫質影片,跟單版圖片上傳
這一步我刻意壓到不能再小
單畫質影片切片
第一個完成的功能只有這樣:
- 上傳影片
- 不轉碼
- 切成 HLS
- 上傳到私有化 S3
ffmpeg 在這裡只做一件事:copy,不重編碼
CPU 壓力低、I/O 單純、流程直線
這一版的目的不是「功能完整」,而是:先確認整條 pipeline 是真的能跑的
單版圖片上傳
圖片更簡單:收檔 → 上傳
第一版甚至沒有 Sharp。
因為我很清楚一件事:在流程還不穩定的時候,加變數只會讓 debug 變痛苦。
第一版的 AI 用法:產 snippet,不碰架構
第一版不是不用 AI,而是用得非常克制。
AI 幫我的只有一件事:把我已經知道要怎麼做、但不想重查文件的部分寫快一點
例如:
- ffmpeg HLS 的參數組合
- MinIO / S3 upload 的寫法
- Node.js stream / buffer 的處理方式
但整個專案的:
- 流程
- 邊界
- 結構
- 責任切分
全部都是我自己決定,架構非常土:
- Controller
- Service
- ffmpeg 直接塞在 Service
- Queue 是 in-memory
- 併發限制寫死在 code 裡
典型的:「我現在一定看得懂」版本
到這裡為止,我才敢停下來想一件事
在只有「單畫質影片 + 單版圖片」的情況下,我問了自己一個問題:如果我現在開始加功能,這個專案半年後我還敢不敢動?
答案很誠實:不敢
於是我做了一個順序上很關鍵的決定:先重構,再加功能
重構階段:我把整個專案交給 AI,不是要它幫我加新東西
我對 AI 的要求很直接:請你以一個後端架構師的角色,幫我重構這個專案
注意這一步沒有任何新功能,只有結構、邊界、責任的重新整理
AI 把整個專案,從 MVC + Service 重構成一個微型 DDD
實際發生的事情包括:
- Video / Image / Upload 拆成 domain
- ffmpeg / sharp 被關進 domain service
- Queue 抽成 interface
- 原本的 in-memory queue 改成 Redis-friendly
- 併發限制全部變成 config
這一步的價值不是「變高級」,是讓後面每一次加功能,都有地方放
重構完成後,才開始面對真正麻煩的需求
多畫質影片:第一個逼你對邊界負責的地方
需求一加上去,第一個問題馬上出現:如果原影片不是 1080p 呢?
- 720p 要不要生 1080p?
- 540p 要不要硬拉?
- 240p 要不要假裝有 360p?
這不是 ffmpeg 問題,我最後定了一個原則:只向下轉碼,永不升畫質
實作流程很直接:
- ffprobe 讀原始高度
- 根據高度動態生成可用 profile
const profiles = [1080,720,540,360];
const available = profiles.filter(p => originalHeight >= p);
如果你丟 240p,我就只給 original,不好看,但不說謊
假並行:我真的讓 AI 寫過,也真的踩過
在重構後加功能時,我一度讓 AI 很自然地寫出:
Promise.all(available.map(p =>transcode(p)));
理論上沒錯,實際上:
- CPU 被切碎
- ffmpeg 偶發 exit
- 檔案 I/O 開始互咬
最後還是回到那個很土、但很穩的解法:
for (const pof available) {
awaittranscode(p);
}
一次一個,讓 ffmpeg 獨佔資源
順序跑,反而比並行快,而且不會炸
圖片 resize:尺寸不乾淨,才是常態
圖片也是在重構後才加進來的。
一加就會遇到這種東西:
484 × 230
然後你一定得回答:
- 以寬還是高為準?
- 要不要裁?
- thumbnail 要不要填滿?
- 比目標尺寸小的要不要放大?
Sharp 不會替你選,AI 也不會
我最後選了一組一致的規則:
- 永遠維持比例
- 超過目標尺寸才縮
- thumbnail 不裁、不填
最後一步:我才要求 AI 幫我寫文件,帶我 onboard
這一步我刻意放在最後。
因為如果你在架構、邊界還在變的時候寫文件,只是在浪費時間。
我對 AI 說:
「假設我是只會 CRUD 的後端
今天第一天接手這個專案
請你寫文件,帶我從零走完整個流程」
我要的是:
- 從 upload 到 output 的完整流程
- 每個 domain 在幹嘛
- 哪些地方可以動,哪些地方不要碰
- 為什麼這裡順序、那裡並行
這一步是在確認一件事:這個專案,最後還是不是我能接手的東西。
AI 最可怕的地方,不是寫得太快
真正的風險,從來不是 bug,也不是效能
而是這件事:你失去對系統的心理模型
當 AI 開始幫你補邏輯、補結構、補抽象,如果你只是一路點頭、一路 merge,有一天你會發現:
系統跑得很好,但你不敢動它
所以我後來給自己訂了一個很硬的規則,AI 可以寫邏輯、可以重構、可以優化,但 AI 必須能把它寫的東西解釋給我聽
這不是一個炫技的專案,是一個誠實的專案
ffmpeg 不是新東西。
Sharp 不是新東西。
Redis、S3 也都不是。
真正困難的,其實是這些選擇:
- 要不要向上兼容
- 要不要產生假畫質
- 要不要在基礎設施層說謊
- 要不要把方向盤整個交出去
如果你也在用 AI 寫程式,希望這個經驗能幫你少踩一個坑:
可以讓 AI 幫你寫,
但一定要確保,最後還看得懂這個系統的人,是你自己