SoundButtons - 音聲按鈕
https://sound-buttons.maki0419.com/
這是一個Vtuber聲音按鈕網站,方便聽你老婆怪叫
此站特色在於獨家的音檔投稿系統,送出表單後能全自動剪輯音訊、產生按鈕。
前端使用Angular;後端以Azure Functions搭配Azure Blob Storage實作,在Github上開源。
前言
我一直在思考如何把我的專業和興趣結合。我是個軟體工程師,我喜歡ACG、我喜歡Vtuber。Koikatu插件、截選歌單都是成果;而這也是。
今年(2021)年後轉職為網站後端工程師,加入了 多奇 ——
一間以技術為主的專案公司。
Sound Buttons專案算是我的個人練習台,練習的同時我也盡力要求自己按照標準實做。Angular規定很多,要求你把code寫在對應的地方。很繁瑣難學,但這就是它的價值。當你的code都能寫在預期的位置,其它寫Angular的工程師就能容易讀懂你的專案。
說句心裡話,
我是個後端工程師,我不喜歡寫js,js很難做架構;但Angular寫起來就是舒服ww
此文前半段是寫給大眾的操作說明;後半段是技術介紹,說說這次我用了什麼酷玩意
功能介紹
首頁
https://sound-buttons.maki0419.com/
進入首頁會來到Vtuber總覽。
這頁的重點在於動態載入內容,此站內容全是json設定檔,要加人物只需要寫新設定檔就行。
也就是說,內容的擴充很簡單,歡迎各位聯絡我添加你婆
另外RWD很好玩,請看看這個
人物頁
https://sound-buttons.maki0419.com/tama
左半邊是人物介紹;右半邊是Youtube來源和聲音按鈕
最左下角為AudioControl,有「音量調整」、「全部停止」、「語速調整」功能

本頁也有做RWD,尤其是在AudioControl的表現上,我自認做得還不差~

投稿功能
https://sound-buttons.maki0419.com/yoruka/upload
在人物頁的右上角有個「投稿」連結,點此開啟該人物專用的投稿表單
投稿功能支援兩種方式來提供音檔
-
Youtube網址:
填入Youtube影片ID,在表單上測試起始、結束秒,送出表單由後台系統剪輯
-
上傳音檔:
直接上傳音檔,此種方式不用等待系統作業,也不用擔心作業失敗,上傳完畢能立刻看到結果。
此方式適合擁有現成音檔的人使用。
以此方式仍推薦填上Youtube來源,以便將人流導向回Vtuber
兩種方式可以擇一,也能同時填寫
同時填寫時會使用上傳之音檔,並在Youtube預覽區顯示填入的Youtube影片來源
投稿預覽
https://sound-buttons.maki0419.com/yoruka?liveUpdate=1
在投稿頁的右上角有「待審核預覽」連結,點此開啟投稿後的成果預覽
投稿時系統會全自動產生聲音按鈕,能在運算完成後即時看到成果,這是本站賣點
由於投稿功能並沒有防白目機制,仍需由我手動整理至正式版。
要重整內容時請按左下角的「重新整理本頁內容」
本站使用Angular,為SPA架構,只要不按F5,在站內瀏覽時都能保持狀態
如果內容有錯需要刪修,可以透過Github連絡我
FAQ
- Q: 這網站能幹嘛?
A: 能聽你老婆怪叫 - Q: 請問按哪裡投稿?
A: 人物頁面的右上角 -
Q: 為什麼投稿會失敗?
A: 請在直播結束後一小時再試,或是把該影片ID回報給我
投稿失敗一般是因為下載超時
後端Azure Functions的運算時間至長為10分鐘,超過就會強制停止。
Youtube對Azure Functions主機的下載速度並不算快,有可能會載到超時。
對此我有額外做了處理,詳見後述。 -
Q: 我想加人
A: Github Discussion
-
Q: 我寫錯了
A: Github Discussion -
Q: 網站有Bug
A: Github Issues
-
Q: 我想請你喝奶茶
A: 謝謝,綠界
技術介紹
專案架構
-
sound-buttons
主專案,為Angular網頁,目前直接Host在Github Page
-
sound-buttons_configs
網頁內容是以json檔管理,預期會頻繁更新,把這些config檔抽離為git submodule
-
sound-buttons_upload-backend
這是Azure Function,用來接form post後剪音檔、上傳至Blob Storage、更新json config
-
docker-sound-dl
為了解決下載超時問題,預先把完整音檔存至Blob Storage,由Blob Storage下載速度能保證夠快
技術細節
sound-buttons
首頁
首頁結構很簡單,一個ng-for就寫完,但css很複雜。卡片動畫是魔改自網路範例,同時也學到RWD調整。這是我第一次寫SASS、也是我第一次用CSS Variables。
人物頁面
人物頁是自己重頭做的切版,很好的練習到了。尤其是左下角的AudioControl,以display grid使之能在RWD改變時正確流動。
上傳表單
在上傳表單中有youtube ID、Start、End和file upload的交叉驗證,用到比較細微的表單狀態操作、ValidatorFn撰寫等
File Upload後的音檔長度驗證,然後修改表單中End參數
表單送出的multipart/form-data如何做組合;form post狀態管理等等。
Audio Service
所有按鈕音訊都由Audio Service集中管理。音訊是使用HTMLAudioElement,基本,但足以應付需求。
Color Service
本站的主色、副色是隨著人物設定改變的,我寫了一個service來管理這個。主副色是以SASS搭配CSS Variable做的,在實做中我弄清了這兩種技術的執行順序。並且,我在這裡覆寫了幾個Bootstrap的primary、secondary顏色來實現功能。
Config Service
網頁所有內容都是來自json設定檔,而設定檔總共有兩種:首頁用的總覽、個人頁的詳細。
總覽設定檔中寫著個人設定檔的網址,這需要兩層訂閱來讀取。為了寫這段學了點Rx,Rx水也是很深。
多國語系i18n
本專案有做多國語系i18n,我嘗試了三種解決方案
-
自製的i18n
我自己做了一個簡單的service來處理json檔內的多國語系,並自己寫了i18n pipe,這裡有git記錄 -
Angular內建的i18n
但因為它是預編譯至個別資料夾,這不方便用在我的Github Page部屬架構中,這裡也有記錄 -
ngx-translate
最後我採用ngx-translate,它的用法多元,且專案架構不會改變,這裡是git compare。
ngx-translate和我的自製i18n相比之最大好處在於它有工具可以extract所有需要翻譯的字串
按鈕
得益於Angular、ES6和Typescript,我可以很好的把按鈕給封裝起來。
在這裡我遇到一個小坑:由json以Button型別接進來的物件,並不會帶有我在Button型別上定義的方法。我知道ts在執行時期沒有型別,但我預期Angular在http.get()進來時會以對應的型別new出來接,應該會過我的ctor。但並沒有...所以我寫了pipe map自己new
sound-buttons_upload-backend
後端選用Azure Functions的原因有下
- 網站後端很適合Azure Functions的耗用量方案(Consumption plan)
- 每月免費送 1 百萬個request,以及每月 400,000 GB 的資源耗用量
- 後端只用來接上傳表單,運行時間不長足夠我用,就算超過也很便宜(每百萬次執行 NT$6.011)
- 對,它就便宜
- 我的音檔是存放在Azure Blob Storage,這兩個產品的整合度很高
- 雖說是Serverless,但C#原生的Path、File、Directory都能使用,我在剪音檔時需要暫存檔案
流程圖

YoutubeDLSharp
這是一個C#的youtube-dl wrapper。寫法算直覺,內建不少snippet可以抄。
我對youtube-dl略懂略懂,在以前的這個專案使用過,之後可能會寫一篇專文介紹?
另外一提,youtube-dl的windows binary使用的是舊版python打包,有個已被關閉但未修復的issue
有以下方式解決
- 用新版python重新打包youtube-dl
- 在Azure Functions主機上安裝新版python,然後傳入wrapper
- 改用youtube-dlc
我選3 ༼ つ ◕_◕ ༽つ
Xabe.FFmpeg
這是一個C#的FFmpeg wrapper,我使用FFmpeg來剪音檔。
用法有點特別,要讀doc,但能work得很好。
Azure Blob Storage
在Azure Function觸發時可以直接DI拿到CloudBlobContainer,直接拿這個做存取即可,不過我寫完後才發現這是Legacy API...
說實話Azure Functions對Blob Storage的官方文件寫得不怎麼樣,也幾乎沒有什麼中文資源,只能多Google
docker-sound-dl
這是一支.NET Core Console Application,並包裝為Linux
Container,掛在我的個人主機排程執行docker run --rm
專案上線測試後遇到一個大問題:
部份Vtuber的影片下載速度奇慢,慢到下載時間超過10分鐘上限,直接被Azure Functions timeout停掉
我估計這是Youtube儲存結點對Azure Functions主機的速度不佳,或者是有流量限制。我的解法是排程每天在其它機器先下載完整音源上傳至Azure Blob Storage儲存。只有由同一區域的Azure Blob Storage拉檔案至Azure Functions絕對不會慢到超時。因為後端接到的影片來源是可預期的,所以這解法可行。
Azure Blob Storage的.NET Core文件就寫得不錯,值得閱讀
在寫Dockerfile時還遇到一個Debug陷阱:
Visual Studio在F5 Debug時只會build base,Dockerfile內修改都要寫去base
Scully
Angular是SPA,在其它子頁面上沒有辦法抓到meta預覧。在不同的VT社群推廣時可能只想PO出該VT的頁面,而不是首頁,沒有預覧是個問題。在這裡我使用了Scully,它可以由Angular專案產生出靜態網頁,並能讓功能照常執行。
保哥有一場直播介紹此主題,提供如下
IPFS部屬
(已移除)
https://ipfs.sound-buttons.maki0419.com/
最近迷上去中心化和區塊鏈,IPFS的部份是技術嘗試,效能來說不會比Github
Pages上的網站好
我在自己家架了IPFS節點,開放API讓Workflow接
CD流程如下,我的Github Workflow
- 把網頁資料夾丟到IPFS網路上
- 讓Pinata釘起來
- 讓我自己的節點釘起來
- 重寫cloudflare上的DNSLink
這裡是Cloudflare有關DNSLink的doc
DNSLink讓我的網址指向IPFS位置,並且會自動通過cloudflare的IPFS Gateway,這讓沒有辦法存取IPFS網址的環境也能打開網站。在部屬時重寫DNS設定,這樣就能由固定的網址訪問IPFS檔案。
版權申明
本作品使用MIT
License,並且不做營利;圖片、音訊為原出處所有,願尊照其規範使用
若權利所有人希望刪修網站內容,請在此回報:
Github Discussion
沒有留言:
張貼留言