AI & ML DevOps GitHub Hugo & Blog

自我挑戰: 家用 KTV 系統實戰:Karaoke Eternal + Cloudflare Tunnel + 雙階段音量標準化 + 客製化點歌調音台

 自我挑戰: 家用 KTV 系統實戰:Karaoke Eternal + Cloudflare Tunnel + 雙階段音量標準化 + 客製化點歌調音台

客廳就是好樂迪!
本文記錄如何使用開源專案 Karaoke Eternal 為核心,搭配 Cloudflare Tunnel (Zero Trust)、雙階段 ffmpeg loudnorm 音量標準化管線,以及自行開發的 好樂迪風格下載點歌站與 Web Audio 調音台,打造一套親友用手機就能直接點歌、電視大螢幕順暢播放、且完全免開對外 Port 的自架家用 KTV 解決方案。


1. 系統架構設計 (Architecture)

傳統家用 KTV 架構常面臨兩難:影音串流需要大頻寬,但讓朋友用手機點歌又需要暴露在公網。

我們採用 「流量分流 + 零信任架構」:
- 大螢幕播放端:客廳電視或平板直連內網 IP(:8080/player),4K/1080p 影片純走區網,避開對外頻寬瓶頸。
- 手機點歌端:走 Cloudflare Tunnel 出口,外層以 Cloudflare Access (Google OAuth 白名單) 攔截,不開任何路由器 Port。
- 快速點歌下載站:客製 Node.js 服務(:8082),提供好樂迪霓虹風格介面,支援 YouTube 網址與關鍵字一鍵解析入庫。

┌──────────────── 筆電/家用主機 (Linux Server: 192.168.X.XXX) ──────────────┐
│                                                                           │
│   [電視/平板播放]                                                         │
│   http://192.168.X.XXX:8080/player                                        │
│         │ (區網直連)                                                      │
│         ▼                                                                 │
│   ┌───────────────┐    Docker Bind Mount    ┌──────────────────────────────┐ │
│   │karaoke-eternal│ ◀──────────────────── │ 宿主機 ./media/library (唯讀)│ │
│   └───────┬───────┘                         └──────────────▲───────────────┘ │
│           ▲ (Docker Network)                               │              │
│           │                                        (ingest.sh 轉檔)       │
│   ┌───────┴───────┐    落盤到 inbox              ┌──────┴───────────────┐ │
│   │ktv-downloader │ ───────────────────────────▶ │ 宿主機 ./media/inbox │ │
│   │ (:8082 點歌站)│                              └──────────────────────┘ │
│   └───────▲───────┘                                                       │
│           │                                                               │
│   ┌───────┴───────┐                                                       │
│   │  cloudflared  │ ───Outbound Tunnel───▶ Cloudflare Zero Trust (Google登入)
│   └───────────────┘                                        ▲              │
└────────────────────────────────────────────────────────────┼──────────────┘
                                                             │
                                                      [朋友手機點歌]
                                                https://ktv.yourdomain.com

2. 核心技術棧

層級 技術選型 解決的問題
容器編排 Docker Compose 服務解耦、環境隔離與一鍵重啟
KTV 核心 radrootllc/karaoke-eternal SQLite 歌庫、房間管理、即時佇列、Web 播放端
安全性 Cloudflare Tunnel + Access 免 DDNS、免開 Router NAT,結合 Google OAuth 身分驗證
音訊管線 ffmpeg (2-pass loudnorm) 抹平 YouTube 各影片錄音音量落差,消除暴音與耳語感
客製後台 Node.js (Express) + yt-dlp 自動清洗 YouTube 歌名雜訊、一鍵下載與背景轉檔
前端調音 Web Audio API (StereoPanner) 實時聲道隔離與播放速度/調音切換

3. 架構思維:影音檔到底該不該放在 Docker 裡面?

在規劃階段曾考量過:「是否直接將影片下載在 Docker 容器內,以維持本機乾淨?」

答案是絕對不行。這是嚴重的架構反模式 (Anti-pattern):
1. 容器生命週期問題:Docker 容器是隨時可銷毀重建的。一旦執行 docker compose down 或映像檔更新,所有下載的歌檔會直接灰飛煙滅。
2. Overlay2 寫入效能低落:Docker 容器層使用 Copy-on-Write 機制,處理數十 GB 影音大檔讀寫極度低效,且會迅速塞爆 /var/lib/docker。
3. 正確解法:宿主機檔案系統管理媒體庫 + Docker 唯讀掛載 (Bind Mount):
yaml volumes: - ./config:/config - ./media/library:/mnt/karaoke:ro


4. 媒體自動入庫與音量標準化 (Ingest Pipeline)

YouTube 上的歌曲音量參差不齊,常常上一首要轉大音量,下一首又震耳欲聾。因此我們設計了自動化 Ingest 腳本 scripts/ingest.sh,每當新歌落入 inbox 時自動觸發:

4.1 雙階段 EBU R128 音量標準化

採用 ffmpeg 的 loudnorm 濾鏡進行雙階段分析:
- 第一階段:分析整首歌曲的整體響度(Integrated Loudness)、真峰值(True Peak)與動態範圍(LRA)。
- 第二階段:根據第一階段分析出的數據線性歸一化,目標定在 I=-16 LUFS、TP=-1.5 dBFS。

4.2 自動觸發資料庫媒體掃描

以往放完檔案必須手動進 Karaoke Eternal 點擊「Scan Media」。我們在轉檔腳本末尾加入直接與 Docker 容器內 CLI 通訊的指令


5. 客製「好樂迪風格」下載與點歌後台 (ktv-downloader)

Karaoke Eternal 對檔名格式非常嚴格,必須是 歌手 - 歌名.mp4(注意中間連字號前後必須有空格)。若直接下載 YouTube 標題(例如 周杰倫 Jay Chou【晴天 Sunny Day】Official Music Video),會直接無法辨識而入庫失敗。

我們使用 Node.js / Express 開發了一套專門的下載容器,運行在 :8082:

5.1 智慧標題清洗器 (Regex Title Cleaner)

透過正則表達式,自動將官方 MV 的垃圾後綴與括號雜訊徹底去除

5.2 霓虹玻璃擬物 UI (Neon Glassmorphism)

  • 提供華語/台語熱門點播標籤(周杰倫、告五人、五月天等),點擊一鍵轉換為 ytsearch1: 關鍵字下載。
  • 提供「即時入庫檔名預覽框」,避免下載進 failed/ 資料夾。
  • 即時輪詢系統狀態:已入庫數、排隊中與錯誤檔提醒。

6. 深度踩坑與除錯實錄 (Troubleshooting)

在建置過程中遇到了幾個深層問題,都是官方文件沒寫的細節:

坑 1:歌單全空白,且主機 CPU 飆高無限遞迴 (ELOOP)

  • 現象:明明影片已經放在 media/library,但網頁打開永遠空白,且容器記錄瘋狂噴出:
    ELOOP: too many symbolic links encountered, stat '/proc/...'
  • 根因分析:Karaoke Eternal 在初始化資料庫時,SQLite 的 paths 資料表竟然被預設設定為 /(根目錄),導致媒體掃描器去遍歷 Linux 的虛擬目錄 /proc 與 /sys,掉入無窮符號連結遞迴。
  • 解法:直接透過 SQLite 修正路徑表,將其校正為 Docker 掛載路徑:

坑 2:原唱/伴唱切換無感?

  • 技術分析:許多人誤以為所有 MV 都有原伴唱聲道。但 YouTube 上 90% 的官方 MV 是標準立體聲(人聲混在正中間,左右聲道都有),單純用 StereoPanner 切換左右聲道是無效的。
  • 對策:
  • 針對正統 KTV 帶:左聲道為純伴奏,右聲道為人聲,Web Audio Panner 完美生效。
  • 針對標準流行歌:下個版本規劃在 ingest.sh 中整合 Demucs / Spleeter AI 模型,在轉檔時將立體聲自動拆軌成(Track 1: 伴奏 / Track 2: 人聲),達成完美的實時消人聲。

7. 成果展示與結語:工程師的極限技術挑戰

經歷了一連串的 Docker 掛載修復、資料庫路徑校正與雙階段音量歸一化調校後,整套架構最終在家用主機上跑起來:

  1. 零信任連線與內網分流:手機透過 Cloudflare Tunnel 遠端安全連線,客廳電視則走區網直連高畫質串流,完美避開對外頻寬瓶頸。
  2. 自動化音訊管線:透過 ffmpeg 成功將不同來源的音量壓縮在一致的響度範圍,解決了傳統自架 KTV 最惱人的忽大忽小聲問題。
  3. 架構自主權的成就感:從 SQLite 底層排錯到自製標題清洗與轉檔排程,完整走完了一套微型影音串流與轉檔自動化的全端流程。

免責聲明與核心價值:
老實說,這項專案從頭到尾都是「工程師的自我挑戰與純粹的技術自娛娛人」。探討怎麼用 Docker、Cloudflare Tunnel 和 ffmpeg 處理影音流固然有趣,但要真的開心唱歌、享受歡聚氣氛,還是得去好樂迪、錢櫃等正規場所。

用工程師的思維把玩影音管線、享受架構完全掌控在自己手裡的過程,才是這場技術冒險最迷人的地方!

Comments

Loading comments…

Leave a Comment

↑