直播小工具: 使用 Vue+serverless 把綠界 Donation 當 SuperChat 呈現

linnil1
8 min readApr 25, 2021

--

故事很簡單

就是綠界目前的界面對實況主而言沒這麼好用就是了

所以某一天改進之後,這個服務就派不上用場了

對於直播主不是友善的界面

Architecture 架構圖

這張架構圖之後會慢慢說明,其實重點是這個服務沒有後端,而且資料都直接存在 local 。因為只使用 CloudFlare,所以 Low latency, high availibilty, Load balancing, DDoS prevention 該有的好處都有

使用 Donation API

總之要抓取綠界的 Donation,要找找看相關的 API,綠界有提供許許多多的 API (e.g. 發票, 金流 物流) ,但是沒有 for 直播主收款的,所以只能自己找。

概念是從這裡來,綠界有提供 alertbox ,只要一斗內,就會跳出圖片文字並發出聲音

綠界直播主贊助成功動畫的官方側視圖

我們就可以找網頁裡面的 API ,然後依樣畫葫蘆的持續 query (每五秒一次),就可以收到所有的 Donation 了

A sample python code to query ECPay donation event

秉持的 serverless 的精神(我之前的文章),我盡量不要拿到後端處理,因為我顧服務的 availability 很麻煩,而是直接讓 Cloudflare 的 worker 去做 query,query 的結果直接回傳給 client,我完全沒看到任何資料,更別說放進資料庫了

A part of code in `worker.js` that query ECPay donation event

所以 client 端可以 curl https://showmysc.linnil1.me/test/{id} 然後我的 worker 就會吐資料。為什麼不要直接在網頁上 query 綠界 API 是因為會有 CORS(Cross-Origin Resource Sharing) 也就是跨網站資料的安全問題,所以某種程度上來講我把 Cloudflare worker 當 proxy 用

SuperChat Format

其實 YouTube 的 SC 的 HTML 格式其實很簡單,就下面這樣而已

The illustration of YouTube SC format.

元件對齊都是用 flex ,有興趣可以看一下 https://css-tricks.com/snippets/css/a-guide-to-flexbox/

為什麼要複製同樣的格式是因為現在很多 vtuber 都有自己的 YouTube chat 的 style ,所以直接給出一樣的格式,他們就不用再多改甚麼,格式調整可以參考這個大家常用網站 https://chatv2.septapus.com

我依樣畫葫蘆的把一張張 SC 弄成 Vue(Vue3) 的 component ,最後用 list 去生成那些 superchats 。

<SC
v-for="sc in scs"
:key="sc.id"
:author-photo="sc.author_photo"
:amount-string="sc.amount_string"
:author-name="sc.author_name"
:message="sc.message"
:timestamp="sc.timestamp"
/>

New function/New format 新增的功能

Default Photo 預設頭像圖片

CSS 那裏要下一點功夫,確定在 OBS 上不會出現問題,CSS 細節的調整方式都寫在網頁上。其中最麻煩的是圖片,最後決定用 CSS 變數的方式來讓實況主好設定,只要在 --default-src 填入自己需要的圖片 URL。

#author-photo {
--default-src: url(https://yt3.ggpht.com/ytc/AAUvwnh3aAJX95-LepOS4z_EYe8P-Iv3l0TkhRmotxV5vBk=s176-c-k-c0x00fffff-no-rj);
}

Text-To-Speech: Google 語音

其實這個很炫砲的功能不難,跟綠界提供的 alertbox 一樣,call Google translation 的 API? 來玩

import { soundManager } from "soundmanager2";soundManager.createSound({
url: "http://translate.google.com/translate_tts?ie=UTF-8&total=1&idx=0&textlen=" + msg.length + "&client=tw-ob&q=" + encodeURIComponent(msg) + "&tl=zh-TW"
}).play()

Integration 整合

結合剛剛的 Donation query(當成後端,會回傳 json 檔) 再加上這裡的 Vue介面(前端),我們用 axios(https://axios-http.com) 把資料串起來,就像下面的程式碼一樣簡單

axios.post('http://localhost:8081/test/' + this.id)
.then(res => {
res.data.forEach( (sc) => {
this.scs.push(sc);
})
})

Storage 儲存

然後確保這些資料儲存在瀏覽器裡,每次有新的 SC 進來的時候,會以 json 格式存到 Local Storage 裡,才不會因為網頁重整而不見。( OBS 的瀏覽器即使在不同場景但 storage 是一樣的)

localStorage.setItem(id, JSON.stringify(sc));       // write
return JSON.parse(localStorage.getItem(id)) || {}; // read

有人問可以用 IndexedDB 存這些資料,是的,之後有空再來改。所以目前網頁上的缺點是開兩個一樣的分頁時 LocalStorage 會互搶(雖然看不出來),而且 LocalStorage 的修改沒有跟 Vue 裡的 objects 同步(另一個方向有同步)

Routing

最後把網址當作變數使用 /test/:id ,這個可以在前端可以用 vue-router 實踐。

# vue router setting
{
path: '/test/:ID',
name: "test",
component: SCPage
}
# Link the 'test/:ID'
<router-link :to="{name: 'test', params: {ID: id}}"></router-link>
# SCPage
data() {
return {
id: this.$route.params.id
}
}

Text Pages

剩下不重要的比如說說明頁面,就拿 bootstrap 預設格式跟 h1 h2 p input br 可以解決大部分的障礙

A screenshot of my introduction page

Result

最後就來實測,當然是真的花錢斗下去

左上: 我的網頁。下,右, 斗內界面

用 OBS 開:

把我的網站用 OBS 的瀏覽器功能打開,其中 default author_photo 是我分別用悠白咪嚕的圖片測試

實戰,感謝可愛的悠白使用,大家來訂閱吧 https://www.youtube.com/channel/UC-o-1qjKkMLq-ZFxXIzOUBQ。右上是,SC 模式(最新的放在上面),左邊的是念 SC 模式(最新的放下面)

悠白配信截圖 https://www.youtube.com/watch?v=9FYuO_h-Ir0

Conclusion

雖然我弄了這個服務,但憑心而論

YouTube 提供服務、幫你推薦,本來就要收費的,從斗內抽一點成是合理的。所以我沒有很推薦 YouTuber/Vtuber 捨棄原本 YT 提供的方式,全用綠界

就這樣 網址在這

https://showmysc.linnil1.me

覺得這篇對你有幫助的話 就按 clap 吧

--

--

linnil1

目前做生物資訊與演算法,過去做過 Machine Vision(Deep learning),維護伺服器(k8s, docker),部分IOT(rpi, arduino)