>全球首創youtube 音樂直播Radio 互動頻道

全球首創youtube 音樂直播Radio 互動頻道
首先聲明這是案件委託。有個音樂頻道的youtuber想開啟直播頻道,找我諮詢希望我給建議,我就說不然來作聽眾評分系統吧,讓聽眾透過聊天室來對目前播放的曲目進行評分,來影響音樂直播頻道的曲風走向,這樣也可以知道聽眾會比較喜歡聽哪些曲風的音樂,就可以針對該回饋進行增強。在linux有 obs studio軟體,也可以透過該軟體進行 youtube串流直播,也可以針對音效作點特別的處理,比方說最後幾秒淡化這樣,但是他沒有我開發的系統最重要的部分–––「聽眾回饋機制」。
專案概述
YouTube Stream 是一個網頁版的 YouTube Live 串流控制面板,類似於簡化版的 OBS Studio。它讓用戶可以透過瀏覽器介面上傳影片和音訊檔案,然後控制直播串流到 YouTube Live,實現 24/7 不間斷的自動化直播。
技術架構
前端使用 Next.js 15 搭配 React 19 和 Tailwind CSS 建構,採用 App Router 架構。後端使用 Go 1.23 語言配合 Gin Web 框架開發。資料庫選用輕量級的 SQLite 並啟用 WAL 模式優化並發效能。串流核心透過 FFmpeg 處理影音編碼和 RTMP 輸出。整個專案使用 Docker Compose 容器化,部署在 DigitalOcean 的 4 核心 8GB 記憶體主機上。
主要功能
串流控制功能讓用戶可以選擇一個視頻檔案做為背景畫面,搭配一個音訊播放列表進行串流。視頻會無限循環播放,而音訊則按照設定的模式播放,可以是順序播放或加權隨機播放。
媒體管理功能支援上傳 MP4 視頻和各種音訊格式,系統會自動偵測檔案時長並儲存相關資訊。用戶可以建立多個播放列表,在播放列表中添加音訊軌道,並為每個軌道設定不同的權重。
聊天室整合功能會定時輪詢 YouTube Live Chat API 取得觀眾留言,並透過 WebSocket 即時推送到前端顯示。系統會自動識別觀眾的喜歡或不喜歡回饋,支援繁體中文、英文、日文三種語言的關鍵詞識別。
統計功能會記錄每首音訊的播放次數、喜歡數和不喜歡數,並提供 CSV 匯出功能。
特別之處
加權隨機播放演算法是這個專案的核心亮點。每首音訊軌道都有一個基礎權重,而有效權重會根據觀眾回饋動態調整,計算公式是基礎權重加上喜歡數減去不喜歡數。播放機率與有效權重成正比,這意味著越受歡迎的音訊會被播放得更頻繁,形成一個由觀眾投票驅動的自適應播放系統。
即時動態覆蓋功能利用 FFmpeg 的 drawtext 濾鏡,在直播畫面上即時顯示當前播放的音訊名稱和累計的喜歡踩數。當有觀眾發送回饋時,畫面會短暫顯示感謝訊息,五秒後自動消失,讓觀眾能立即看到自己的投票被接收。
防濫用機制確保投票系統的公平性。每位觀眾對每首音訊只能投一票,並且設有用戶冷卻時間和每首音訊的投票上限。系統還會過濾掉機器人帳號自己發送的訊息,避免影響統計。
獨到之處
這個專案最具突破性的創新是全球首創的 YouTube 直播聊天室即時評分系統。在此之前,從未有任何工具能讓直播主在 YouTube Live 上建立一個由觀眾投票驅動的音樂電台。觀眾只需在聊天室輸入簡單的關鍵詞,就能即時影響播放列表的演算法權重,讓喜歡的歌曲更頻繁出現、不喜歡的歌曲逐漸淡出。這種將被動觀看轉變為主動參與的互動模式,徹底改變了音樂直播的遊戲規則。
傳統的音樂直播只能單向播放,觀眾的喜好完全被忽略。而這套系統讓每一位觀眾都成為節目的共同策展人,透過群體智慧即時塑造播放內容。想像一下,一個 24 小時不間斷的音樂頻道,它的播放順序不是由演算法冷冰冰地決定,而是由正在收聽的觀眾們用真實的投票一票一票堆疊出來的。這是音樂直播領域前所未有的民主化嘗試。
無縫軌道切換技術確保這個願景能夠穩定實現。當一首音訊播放完畢時,系統會自動啟動新的 FFmpeg 進程播放下一首,而視頻持續循環不中斷。這種設計讓串流可以 24 小時連續運行,無需人工干預。
完整的 OAuth 整合讓用戶只需透過 Google 帳號登入,系統會自動管理 YouTube API 的 access token 和 refresh token,在 token 過期前五分鐘自動刷新,確保長時間運行不會因為認證問題中斷。
提醒訊息系統會在串流開始時以及每六小時自動向聊天室發送一則提醒訊息,告知觀眾如何使用關鍵詞進行投票,提高互動參與度。
WebSocket 即時通訊讓前端能夠每兩秒接收一次串流狀態更新,包括當前播放的軌道、串流健康指標如碼率和幀率、以及重連次數。聊天訊息也透過 WebSocket 即時推送,不需要前端主動輪詢。
API 配額優化是實際營運時的重要考量。YouTube Data API 每天有 10,000 單位的配額限制,這個專案將聊天輪詢間隔設定為 60 秒,每次呼叫消耗 5 單位,一天下來大約消耗 7,200 單位,留有足夠的緩衝空間應對其他 API 操作。
<Gallery images={[ { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053863005-c8d59845-a651-4f8c-8f85-9734865b8c8b.png?alt=media&token=d4a3ea2d-57a9-4c9d-b7bb-90949fca629d", alt: "youtube-streaming-panel-zh-TW-gallery-1" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053864117-0457fcb4-0820-4c84-a73e-5a6cf48881bb.png?alt=media&token=40ef4ce6-540a-43ec-ae51-ec52a3f8f68f", alt: "youtube-streaming-panel-zh-TW-gallery-2" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053864707-1a9c7d5e-da3b-409c-9554-479886853b38.png?alt=media&token=97635835-88b9-4c9b-b21a-a4e7b8c29eec", alt: "youtube-streaming-panel-zh-TW-gallery-3" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053865361-2ef8d82e-d8d0-4235-b0d6-73b389774e4c.png?alt=media&token=fb6d49ae-c389-4389-97cb-7e5c3d0e0f5b", alt: "youtube-streaming-panel-zh-TW-gallery-4" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053866039-1155811f-12c0-40ce-a247-d24038764057.png?alt=media&token=83f097b1-87b7-4be8-8470-ce5e8621b68f", alt: "youtube-streaming-panel-zh-TW-gallery-5" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053866677-150d1bdb-aea9-4d6a-92d2-106042964d56.png?alt=media&token=1874f8c8-30b8-49e2-a987-21014c828c2c", alt: "youtube-streaming-panel-zh-TW-gallery-6" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053867554-44950b75-0260-40db-829d-96e62a1cb920.png?alt=media&token=b36ff4bb-1caa-46a0-8209-226a60ab17c8", alt: "youtube-streaming-panel-zh-TW-gallery-7" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053868170-dff5ddfe-9448-4a56-8e92-c67a378d329c.png?alt=media&token=d396d704-2941-4f00-a701-d519d1a1a501", alt: "youtube-streaming-panel-zh-TW-gallery-8" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053868846-2f4283ce-605d-4d47-a8b4-b18dc0dbfc9e.png?alt=media&token=1035417c-f532-4b0f-a6a1-b152cc42d569", alt: "youtube-streaming-panel-zh-TW-gallery-9" }, { src: "https://firebasestorage.googleapis.com/v0/b/blog-98831.firebasestorage.app/o/posts%2Fyoutube-streaming-panel%2Fzh-tw%2F1768053869522-0356dc50-d6b9-4c6e-a3bd-59a2ac9a563a.png?alt=media&token=43f2575b-fef8-417a-a5b4-ac46dddf7d1e", alt: "youtube-streaming-panel-zh-TW-gallery-10" } ]} />
## 留言
$ 留言載入中...