專案架構
FlowPick 的技術架構詳解,包括系統設計、模組劃分、資料流和關鍵設計決策。
本文件面向希望深入理解 FlowPick 內部設計的開發者,涵蓋系統架構、模組職責、資料流和關鍵設計決策。

系統架構概覽
FlowPick 由兩個主要產品形態組成:瀏覽器擴充功能和線上工具網站。兩者共享核心下載引擎,但在媒體偵測和網路請求處理上有所不同。
┌─────────────────────────────────────────────────────────┐
│ FlowPick │
│ │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ 瀏覽器擴充功能 │ │ 線上工具網站 │ │
│ │ │ │ │ │
│ │ · 網路請求監控 │ │ · M3U8 下載器 │ │
│ │ · 媒體自動偵測 │ │ · DASH 下載器 │ │
│ │ · 彈出視窗 UI │ │ · 文件系統 │ │
│ │ · 跨域請求能力 │ │ · 首頁展示 │ │
│ └────────┬─────────┘ └────────────┬─────────────┘ │
│ │ │ │
│ └───────────┬───────────────┘ │
│ │ │
│ ┌───────────▼───────────────┐ │
│ │ 核心下載引擎 │ │
│ │ │ │
│ │ · useStreamMerge.ts │ │
│ │ · useFFmpeg.ts │ │
│ │ · 分片下載與並行控制 │ │
│ │ · AES-128 解密 │ │
│ │ · 串流式檔案寫入 │ │
│ │ · 格式轉換 │ │
│ └───────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
兩種產品形態的定位:
| 維度 | 瀏覽器擴充功能 | 線上工具網站 |
|---|---|---|
| 目標使用者 | 日常高頻使用者 | 臨時使用者、無法安裝擴充功能的環境 |
| 核心優勢 | 自動偵測、一鍵下載 | 無需安裝、跨平台 |
| 技術約束 | Manifest V3 限制 | 同源策略限制 |
| 入口方式 | 工具列圖示點擊 | 直接存取網頁 URL |
關於擴充功能與線上工具的詳細功能差異和選擇建議,請參閱 線上工具 — 與擴充功能的對比。關於擴充功能的安裝步驟,請參閱 安裝指南。
模組詳解
核心下載引擎
下載引擎由兩個 composable 組成,位於 app/composables/。

useStreamMerge.ts
負責串流媒體分片的下載、解密、合併和寫入。這是整個系統最核心的模組。
主要職責:
| 功能 | 實作方式 |
|---|---|
| 分片並行下載 | Worker Pool 模式,共享任務計數器 |
| 重試機制 | 指數退避,最多 3 次 |
| AES-128 解密 | Web Crypto API |
| 分片拼接 | 二進位直接拼接(TS)或 FFmpeg 轉封裝(MP4) |
| 檔案寫入 | FSA → StreamSaver → Blob 三級降級 |
| 進度追蹤 | 滑動視窗速度計算 + 剩餘時間估算 |
| 記憶體管理 | 取樣預估 + 閾值檢查 + 策略選擇 |
匯出介面:
export interface StreamMergeOptions {
segments: ArrayBuffer[] | AsyncGenerator<ArrayBuffer>
totalSegments: number
filename: string
outputFormat?: 'mp4' | 'ts'
onProgress?: (progress: StreamMergeProgress) => void
signal?: AbortSignal
}
export interface StreamMergeProgress {
phase: 'downloading' | 'merging'
percent: number
downloadedBytes: number
totalBytes: number
speed: string
eta: string
}
關於下載引擎的完整技術實作(含並行控制、重試策略、記憶體管理、寫入策略對比),請參閱 下載引擎架構。關於三級寫入策略的降級邏輯,請參閱 下載引擎架構 — 策略對比總結。
useFFmpeg.ts
負責 FFmpeg WASM 的載入、生命週期管理和媒體處理命令執行。
主要職責:
| 功能 | 實作方式 |
|---|---|
| WASM 載入 | 按需載入,支援多執行緒/單執行緒自動切換 |
| 多執行緒偵測 | 檢查 SharedArrayBuffer 和 crossOriginIsolated |
| TS → MP4 轉封裝 | ffmpeg -i input.ts -c copy output.mp4 |
| 音影片合併 | 分別寫入虛擬 FS,執行合併命令 |
| FMP4 重組 | 處理 DASH 的初始化段 + 媒體段 |
| 進度回呼 | 解析 FFmpeg 輸出的 time 資訊 |
匯出介面:
export const useFFmpeg = () => {
return {
ffmpeg: Ref<FFmpegType | null>
loaded: Ref<boolean>
loading: Ref<boolean>
error: Ref<string | null>
load: () => Promise<void>
mergeToMP4: (options: MergeOptions) => Promise<ArrayBuffer>
mergeAudioVideo: (options: MergeAudioVideoOptions) => Promise<ArrayBuffer>
mergeFmp4: (options: MergeFmp4Options) => Promise<ArrayBuffer>
}
}
關於 FFmpeg WASM 的載入流程、多執行緒偵測和效能對比,請參閱 格式轉換 — FFmpeg WASM 引擎。關於 SharedArrayBuffer 的設定要求,請參閱 瀏覽器相容性 — 進階 API。
頁面模組
M3U8 下載器 (m3u8-downloader.vue)
處理 HLS 串流媒體協定的下載頁面。
處理流程:
使用者輸入 URL
↓
fetch M3U8 內容
↓
m3u8-parser 解析
↓
┌─ Master Playlist? ──→ 展示畫質列表 → 使用者選擇
│
└─ Media Playlist? ──→ 提取分片列表
↓
檢查 #EXT-X-KEY(加密資訊)
↓
下載金鑰檔案(如有)
↓
並行下載分片 + 解密
↓
合併/轉封裝
↓
寫入磁碟
關鍵依賴:
m3u8-parser:解析 M3U8 清單useStreamMerge:分片下載與合併useFFmpeg:格式轉換
關於 HLS 協定的 Master Playlist 與 Media Playlist 的區別,請參閱 影片嗅探 — HLS 串流。關於線上工具中 M3U8 下載器的使用方式,請參閱 線上工具。
DASH 下載器 (dash-downloader.vue)
處理 DASH 串流媒體協定的下載頁面。
處理流程:
使用者輸入 URL
↓
fetch MPD 內容
↓
mpd-parser 解析
↓
檢查 ContentProtection(DRM)
↓
提取 AdaptationSet(影片/音訊)
↓
展示串流列表 → 使用者選擇
↓
下載初始化段(如有)
↓
並行下載媒體段 + 解密
↓
FMP4 重組 / 音影片合併
↓
寫入磁碟
關鍵依賴:
mpd-parser:解析 MPD 清單useStreamMerge:分片下載與合併useFFmpeg:FMP4 重組與音影片合併
關於 DASH 串流的偵測原理和 ContentProtection 處理,請參閱 影片嗅探 — DASH 串流。關於 DRM 保護內容的限制說明,請參閱 已知限制 — DRM 保護內容。
文件系統
基於 Nuxt Content v3 構建,文件以 Markdown 檔案形式存放在 content/ 目錄。
目錄結構:
content/zh-Hans/
├── 1.docs/ # 文件主體
│ ├── 1.getting-started/ # 快速開始
│ ├── 2.features/ # 功能特性
│ ├── 3.advanced/ # 進階指南
│ ├── 5.troubleshooting/ # 故障排除
│ └── 6.developer/ # 開發者文件
├── 4.changelog/ # 更新日誌
└── 6.legal/ # 法律條款
導覽系統:每個目錄下的 .navigation.yml 定義該分類的標題和圖示。Nuxt Content 自動收集所有文件並產生側邊欄導覽。
文件版面配置:app/layouts/docs.vue 提供統一的文件頁面版面配置,包含頂部導覽、側邊欄和內容區域。
關於文件的編寫規範(Frontmatter、內容格式、多語言),請參閱 貢獻指南 — 文件編寫指南。
資料流
完整下載流程
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 取得清單 │ → │ 解析清單 │ → │ 下載分片 │ → │ 合併寫入 │
└─────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │
▼ ▼ ▼ ▼
fetch() m3u8-parser Worker Pool useStreamMerge
mpd-parser AES-128 解密 useFFmpeg
fetch() 並行 FSA/SS/Blob
各階段詳細說明:
| 階段 | 輸入 | 處理 | 輸出 | 可能失敗原因 |
|---|---|---|---|---|
| 取得清單 | M3U8/MPD URL | HTTP GET 請求 | 清單文字 | 網路錯誤、URL 過期、404 |
| 解析清單 | 清單文字 | m3u8/mpd-parser 解析 | 分片列表 + 中繼資料 | 格式不標準、DRM 保護 |
| 下載分片 | 分片 URL 列表 | Worker Pool 並行下載 | ArrayBuffer 陣列 | CORS、限流、token 過期 |
| 合併寫入 | ArrayBuffer 陣列 | 拼接/轉封裝 + 寫入 | 磁碟檔案 | 記憶體不足、寫入權限 |
關於下載引擎的完整資料流(含錯誤分類和重試機制),請參閱 下載引擎架構 — 資料流全景。關於各階段失敗時的排查方法,請參閱 常見問題排查。
寫入策略選擇流程
開始寫入
│
▼
File System Access API 可用?
│
├── 是 → 使用 FSA 串流式寫入(最優)
│ · 16MB 緩衝區
│ · 支援任意大小
│
└── 否 → StreamSaver 可用?
│
├── 是 → 使用 StreamSaver 串流式寫入
│ · Service Worker 代理
│ · 支援大檔案
│
└── 否 → 預估檔案大小
│
├── < 1.5GB → Blob 模式
│ · 全部載入到記憶體
│ · 觸發瀏覽器下載
│
└── > 1.5GB → 拒絕下載
· 提示切換瀏覽器
關於三級寫入策略的詳細對比(含各策略的適用場景和限制),請參閱 下載引擎架構 — 策略對比總結。關於各瀏覽器對 FSA API 的支援情況,請參閱 瀏覽器相容性 — 功能支援矩陣。
關鍵設計決策
為什麼選擇 FFmpeg WASM 而不是伺服器端處理?
決策:所有媒體處理在瀏覽器端完成。
理由:
- 隱私保護:使用者檔案不上傳伺服器
- 零伺服器成本:無需維護轉碼伺服器叢集
- 即時可用:無需等待上傳和排隊
- 離線能力:理論上可在 PWA 模式下離線使用
代價:
- 效能低於原生 FFmpeg(約 10-20%)
- 首次載入需要下載 WASM 檔案(約 8MB)
- 受瀏覽器記憶體限制
關於 FFmpeg WASM 與原生版本的效能對比資料,請參閱 已知限制 — FFmpeg WASM 效能。關於隱私保護的完整說明,請參閱 隱私與安全。
為什麼使用三級寫入降級策略?
決策:FSA → StreamSaver → Blob 的優先級鏈。
理由:
- FSA API 是最優方案,但僅 Chrome/Edge 支援
- StreamSaver 相容性更廣,但依賴 Service Worker
- Blob 是兜底方案,確保所有瀏覽器都能下載
代價:
- 需要維護三套寫入邏輯
- 降級行為可能導致使用者體驗不一致
關於三級策略的詳細實作和降級觸發條件,請參閱 下載引擎架構 — 檔案寫入模組。關於各瀏覽器的寫入能力對比,請參閱 瀏覽器相容性 — 功能降級策略。
為什麼並行下載使用 Worker Pool 而非預先分片?
決策:使用共享計數器 + 動態任務分配。
理由:
- 分片大小不均時,預先分片會導致部分 Worker 閒置
- 共享計數器確保所有 Worker 持續工作直到任務完成
- 實作簡單,無需複雜的負載均衡邏輯
關於 Worker Pool 的並行控制實作和效能分析,請參閱 下載引擎架構 — 並行數與效能的關係。關於並行數的設定方法,請參閱 設定參考。
為什麼擴充功能和線上工具共享核心引擎?
決策:useStreamMerge 和 useFFmpeg 作為獨立 composable,不依賴擴充功能 API。
理由:
- 程式碼重用,避免維護兩套下載邏輯
- 線上工具可作為擴充功能功能的展示和降級方案
- 便於測試:核心邏輯可在一般網頁環境中除錯
關於擴充功能與線上工具在 CORS 處理上的差異,請參閱 已知限制 — CORS 跨域限制。關於兩種產品形態的功能對比,請參閱 線上工具 — 與擴充功能的對比。
依賴關係圖
m3u8-downloader.vue ──────┐
├──→ useStreamMerge.ts ──→ Web Crypto API
dash-downloader.vue ──────┤ │ fetch API
│ ├──→ useFFmpeg.ts ──→ @ffmpeg/ffmpeg
擴充功能彈出視窗 ─────────┘ │ @ffmpeg/util
├──→ File System Access API
├──→ StreamSaver.js
└──→ Blob API
文件系統 ──→ @nuxt/content ──→ Markdown 檔案
└──→ @nuxt/ui ──→ Tailwind CSS
依賴關係說明: