# v2.3 — source-selector 修改規格 > 本章對應 R5(砍 URL 推論)+ R5-6(ffmpeg decoder 支援 mp4/avi/mov/mpeg/mpg)。 > 影響檔案:`frontend/src/components/camera/source-selector.tsx`、`frontend/src/stores/camera-store.ts`、`frontend/src/lib/i18n/zh-TW.ts`、`frontend/src/lib/i18n/en.ts`、`frontend/src/lib/i18n/types.ts` > 上層索引:`../design-spec-v2.md` --- ## 1. 修改範圍摘要 **砍**: - video tab 下的 `URL mode`(`videoMode === 'url'` 分支整塊) - `videoMode` state 本身(因為 video tab 只剩單一 `file` 模式) - `videoUrl` state、`handleUrlSubmit` handler - `startFromUrl` store action 呼叫端與 store 內實作 - 「正在解析影片連結,YouTube 影片可能需要 10-30 秒…」的 hard-coded 紅字提示 - YouTube / Vimeo / RTSP 相關文案 - i18n keys:`camera.uploadFile`、`camera.pasteUrl`、`camera.urlPlaceholder`、`camera.urlHelpText` **改**: - `` 從 `.mp4,.avi,.mov` → `.mp4,.avi,.mov,.mpeg,.mpg` - dropzone filter(若有影片 drop 支援)同步 - i18n key `camera.mp4AviMov` 值從 `MP4, AVI, MOV` → `MP4, AVI, MOV, MPEG` - Video tab 內只剩一個「選擇影片」按鈕 + 格式說明文字,無 sub-mode 切換 **保留**: - `isUploading` state(上傳大檔仍需 loading) - `uploadVideo` action - `sourceFilename` 顯示 - Camera / Image tabs 的所有邏輯完全不動 --- ## 2. 新的 video tab UI 狀態表 ### 2.1 結構(ASCII) ``` ┌─ Video tab ────────────────────────────────────────────────┐ │ │ │ [ 選擇影片 ] MP4, AVI, MOV, MPEG │ │ │ │ (可選)dropzone:拖放影片檔到此 │ │ │ └──────────────────────────────────────────────────────────────┘ ``` ### 2.2 狀態對照表 | 狀態 | 條件 | 可見元素 | 按鈕狀態 | |------|------|--------|---------| | Idle(預設) | 非 streaming、非 uploading | `[選擇影片]` button + 格式說明 `MP4, AVI, MOV, MPEG` | enabled | | Uploading | `isUploading === true` | `[上傳中...]` button(disabled)+ 格式說明 | disabled | | Streaming | `isStreaming === true`(由父元件處理,此 tab 的內容被 `[停止影片]` 按鈕取代) | `[停止影片]` + 檔名 | — | **注意**:Video tab 不再有 `Upload file` / `Paste URL` 兩顆 sub-mode 切換按鈕;使用者點 tab 後**直接就是上傳區**。 --- ## 3. i18n key 異動清單 ### 3.1 新增 key | Key | zh-TW | en | 說明 | |-----|-------|----|------| | `camera.mp4AviMovMpeg` | MP4, AVI, MOV, MPEG | MP4, AVI, MOV, MPEG | 取代舊的 `mp4AviMov` | (也可以選擇直接改舊 key 的值,見 §3.3 的建議) ### 3.2 刪除 key(zh-TW / en / types 三檔都要刪) | Key | 原值(zh-TW) | 刪除理由 | |-----|-------------|---------| | `camera.uploadFile` | 上傳檔案 | Video tab 不再有 sub-mode 切換,`camera.selectVideo` 已足夠 | | `camera.pasteUrl` | 貼上連結 | URL mode 砍除 | | `camera.urlPlaceholder` | `https://example.com/video.mp4` | 同上 | | `camera.urlHelpText` | 支援 YouTube、直接影片 URL(.mp4 等)及 RTSP 串流。 | 同上 | ### 3.3 修改 key(保留但更新值) | Key | 原值(zh-TW / en) | 新值(zh-TW / en) | |-----|-----------------|-----------------| | `camera.mp4AviMov` | `MP4, AVI, MOV` / `MP4, AVI, MOV` | `MP4, AVI, MOV, MPEG` / `MP4, AVI, MOV, MPEG` | **注意**:`key 名`雖然寫 `mp4AviMov`,但值改為包含 `MPEG`。保留 key 名避免 rename 造成其他地方引用失效。或者也可以 rename 為 `camera.supportedVideoFormats`,若 rename,type 檔也要同步。**建議 rename**,更語義化。 ### 3.4 `camera.selectVideo` 保留 文字「選擇影片 / Select video」不變,仍用於 video tab 的主 CTA。 --- ## 4. 程式碼變更預期(示意,實作以 Frontend Agent 為準) ### 4.1 `source-selector.tsx` diff 摘要 **刪除**(大約 50 行): - `const [videoMode, setVideoMode] = useState<'file' | 'url'>('file');` - `const [videoUrl, setVideoUrl] = useState('');` - `const handleUrlSubmit = async () => { ... }` - 從 store 解構 `startFromUrl` - `{activeTab === 'video' && (...)}` 內的 sub-mode 切換按鈕 `[上傳檔案] / [貼上連結]` - URL mode 的整個 JSX 分支(輸入框 + 「正在解析」提示 + `camera.urlHelpText`) - `import { Input }` 如果其他地方沒用,連 import 一起砍 **修改**: - Video tab 的結構從 `
` 內含兩個 mode 分支,改為直接 render file upload 區 - `` → `` - 格式說明文字改為 `t('camera.supportedVideoFormats')`(或維持 `mp4AviMov` key) **最終 video tab JSX 預期樣貌**: ```tsx {activeTab === 'video' && (
{t('camera.supportedVideoFormats')}
)} ``` ### 4.2 `camera-store.ts` diff 摘要 **刪除**: - interface 中的 `startFromUrl: (url: string, deviceId: string) => Promise;` - 實作中的 `startFromUrl: async (url, deviceId) => { ... }` 整塊 **保留**: - `uploadVideo` 不動 - `isUploading` state 不動 ### 4.3 `i18n/zh-TW.ts`、`i18n/en.ts`、`i18n/types.ts` 三檔同步: - 刪 `uploadFile`、`pasteUrl`、`urlPlaceholder`、`urlHelpText` - 新增 `supportedVideoFormats`(或修改 `mp4AviMov` 值) - types 檔移除對應 type 定義 ### 4.4 其他可能殘留 執行 grep 檢查: - `grep -r "startFromUrl" frontend/src/` - `grep -r "pasteUrl" frontend/src/` - `grep -r "youtube\|vimeo\|RTSP" frontend/src/` 若有殘留,一併清理。 --- ## 5. 無障礙考量 Video tab 變為單一按鈕後: | 項目 | 設計 | |------|------| | Tab order | camera → image → video → (內部) 選擇影片 button | | Button aria-label | `aria-label="選擇影片檔案,支援 MP4 AVI MOV MPEG"` | | Focus ring | 沿用 Button 元件預設 focus ring | | Screen reader | Button 點擊開啟 native file picker,macOS VoiceOver / Windows Narrator 會自動 announce file dialog | --- ## 6. 回歸測試重點(給 Testing Agent) - [ ] Video tab 點擊後**直接**看到 `[選擇影片]` 按鈕,無 sub-mode 切換 - [ ] 支援上傳 `.mp4`、`.avi`、`.mov`、`.mpeg`、`.mpg` 五種副檔名 - [ ] 不支援上傳 `.mkv`、`.webm`、`.flv`(ffmpeg LGPL minimal build 不含這些 decoder) - [ ] 上傳中顯示 `上傳中...`,按鈕 disabled - [ ] 上傳完成後開始 inference,`sourceFilename` 顯示正確檔名 - [ ] 全站 grep 不到任何 `startFromUrl` / `pasteUrl` / `youtube` / `vimeo` 字串 - [ ] 兩個語系(zh-TW / en)都沒有 dead keys - [ ] 舊版 i18n key 被刪後,TypeScript 編譯無 dangling reference --- ## 7. 與 v1 差異對照 | 面向 | v1 | v2 | |------|----|----| | Video 來源類型 | file + URL(YouTube / Vimeo / RTSP / 直接 .mp4) | 僅 file | | 支援副檔名 | `.mp4, .avi, .mov` | `.mp4, .avi, .mov, .mpeg, .mpg` | | Sub-mode 切換 | 有(2 顆切換按鈕) | 無 | | URL 輸入框 | 有 | **無** | | 解析 URL 提示 | 有(「YouTube 影片可能需要 10-30 秒…」) | **無** | | i18n key 數 | 含 4 個 URL 相關 key | 砍 4 個、新增 / 修改 1 個 | | `startFromUrl` store action | 有 | **無** | --- **下一步**:交 Frontend Agent 按上述 spec 實作,完成後交 Reviewer 審查、Testing Agent 做回歸測試。