創作內容

153 GP

[達人專欄] 自製 YouTube-OBS 跑馬燈外掛!在實況顯示影片標題(Golang + JavaScript)

作者:解凍豬腳│2019-01-04 03:03:40│贊助:2,310│人氣:3770
 
  這次來分享一下最近的靈感和成果吧。

  平時用 OBS 開遊戲實況的時候,常常遇上觀眾在聊天室問:「豬腳,可以問一下現在播的歌名是什麼嗎?」

  每次問、每次回答,這樣一直下去也不是辦法。要是安裝了其他 YouTube 相關的 OBS 外掛,似乎又沒有辦法符合我想要的簡單跑馬燈風格,而且也不能隨心所欲地修改它。

  既然要把目前播放中的 YouTube 影片標題放到跑馬燈裡面,那一定要有辦法取得網頁裡面的內容。然而,由於瀏覽器對 JavaScript 的限制,導致要利用 JavaScript 把影片標題寫入 OBS 裡跑馬燈指定的 txt 檔案會變成一件很麻煩的事情,於是我把腦筋動到了 HTTP server 和 Golang 上面。

  做法是這樣的:首先我們利用 Golang 寫出來的程式(當然你要用 Python 或其他語言也可以)建立一個 HTTP server,這個程式負責用來接應、刷新 OBS 跑馬燈指定的 txt 檔案;至於網頁瀏覽器那端,則是使用 Tampermonkey 搭配 JavaScript 來抓取歌曲名稱,並且在需要更新跑馬燈的時候,將歌曲名稱送到 Golang 那邊建立起來的 server。

  先來談談用 JavaScript 抓影片名稱。如果是對於一個平常有寫爬蟲經驗的人來說,對於 selector 已經有足夠的理解,那想利用 JavaScript 取得網頁特定元素內容,自然是很簡單的事情。只要對影片標題區塊右鍵、檢測元素:





  一點開就可以抓到了,依照 tag[.class][#id] 的規則,它的 selector 寫作:
  yt-formatted-string.style-scope.ytd-video-primary-info-renderer

  後來我研究了一下,發現這麼做會出問題,因為符合這個 selector 的元素一共有三個,如果要取得真正的標題,就只能固定抓其中的第二個元素:
    document.querySelectorAll("yt-formatted-string.style-scope.ytd-video-primary-info-renderer")[1].innerText;

  寫爬蟲最擔心的事情就是 query 選出來的東西不唯一,要是遇上了例外情況,抓到的資料就可能不正確。所以為了保險起見,我把它往上追溯,找到它的 parentNode:
  h1.title.style-scope.ytd-video-primary-info-renderer

  利用 F12 打開 console,抓抓看它的 innerText:
    document.querySelector("h1.title.style-scope.ytd-video-primary-info-renderer").innerText;



  確定可以透過這個 selector 取得標題內容以後,就可以動手寫 JavaScript 的 code 了。在這之前我們需要在瀏覽器上安裝 Tampermonkey 這個擴充功能。

  寫好的 code 我貼在這裡:自動更新實況跑馬燈

  先來解釋一下這段 JavaScript。其實起初我測試的時候,發現 YouTube 網頁的運作機制比較特別,當你從某一首歌切換到另一首歌的時候,網頁應該是只有把裡面的播放器等等元素動態切換成別首歌,而不是直接將整個網頁重載。也就是說,只有當你第一次點進該網頁的時候,才會觸發一次 document-end 的事件,之後切換歌曲都不會觸發。

  這意味著,如果我 code 寫的內容設定在 document-end 的時候才捕捉影片名稱、送出影片名稱的話,我就只能夠抓到第一次播放的影片名稱,這個 code 之後就會起不了作用。

  於是我設了一個解決方案:每 0.5 秒(500 毫秒)偵測一次影片標題,如果發現影片標題有變更的話,我就送出影片名稱。

  所以,你會在我的 code 裡面看到 setInterval 的函數,它就是被我用來反覆確認歌曲有沒有切換,如果歌曲名稱變了,那就把這個歌曲名稱資訊重抓一次,利用當初剛載入網頁,觸發 document-end 的時候建立的 iframe,把歌曲名稱送去我用 Golang 建的 server。

  這時候一樣開著 F12 的 console 頁面,去 YouTube 隨機點個幾首歌,觀察一下 console 上面的文字,會發現我寫的腳本成功透過 console.log(encodeURIComponent(nowTitle)); 顯示出來了:



  當然,上面這些只不過是整個外掛的一半,最重要的還是負責接收影片名稱,以及將名稱寫入文字檔的 server 端。

  一方面是因為自己最近剛學 Golang,一方面也是因為用 Golang 建 HTTP server 還蠻方便的,所以就選擇它了。

  寫好的 code 我放在這裡:YouTubeListener.go

  原理很簡單。我們在本地端隨便抓一個 port 來用,只要 server 這邊收到了就寫入 title.txt。這份 code 使用的是 port 8763,你想要把它改成其他的 port 也可以(只要沒被其他程式佔用),但請注意,若想修改的話,JavaScript 指定的送達地點也要跟著改成一樣的。

  這樣的 code 不到 100 行就可以解決了,相信光是看字面也能看得懂程式的運作。

  寫好的程式在這:YouTubeListener.7z



  之後,只要把 YouTubeListener.exe 開著,接著再打開 YouTube,隨便點一首歌,就會發現影片名稱會被送到那程式上面,並且由那程式把名字寫進同目錄下的 title.txt 裡面了。



  所以,我們這時候打開 OBS,在場景裡面新增一個文字(GDI+),接著右鍵 > 濾鏡,新增捲動濾鏡,再憑自己喜好設定寬度,再右鍵 > 屬性,把檔案來源設成 title.txt,由於 OBS 本身對於跑馬燈的內容也是即時更新的,所以隨著 YouTube 播放的歌曲而變動的跑馬燈就完成了:



  這裡有些小細節要強調。

  第一點是,JavaScript 裡面送出的歌曲名稱是用 encodeURIComponent() 函式(URL 編碼)轉換過的,這是用了避免歌曲名稱出現「&」的時候,網址的參數會被切開來的情形。

  第二點是,你會在那段 JavaScript 腳本跟 Golang 的 code 發現裡面設了一組 accessKey,這是為了安全考量。如果今天有個外人試圖偽造連線請求,想要惡意地把一些假資訊送到你的電腦裡面,害你的實況台出現「某些文字」,那你就可以使用這個 accessKey 來避免,因為只有你才知道這個 accessKey 的內容。雖然把 Golang 的 ListenAndServe 設在 127.0.0.1 已經夠安全了,但保險起見還是寫一下。

  舉個例子,我在 Golang 裡面寫的是這樣:先讀取 accessKey.upk 檔案裡面的內容(並且將之設為 key),接著建立 HTTP server。

  這個同樣的 key 我也設在 JavaScript 的腳本裡面(兩串是一樣的),例如我預設的 key 內容是「952d9c43(太長了,中間省略)3ad20b0e」,那我在網頁抓到新歌曲名稱的時候,就會把剛開始在網頁裡面塞好的 iframe 網址跳轉到這個地方

  Golang 這邊建立的 HTTP server 在收到這次連線請求的時候,就會去對照這組 key 是不是跟在 accessKey.upk 一樣,確認一樣的話才把名稱寫進去。

  如果你有實驗精神的話,可以試試看自己用瀏覽器訪問這個網址,看看會不會成功送出一筆資料過去,這樣它的原理也就會變得很好理解了。

  這個 key 當然你也可以自己定義,總之只要確保 accessKey.upk 的內容跟 JavaScript 腳本裡面設的 accessKey 相同,那就可以了。

  以上是這次利用 Golang、JavaScript 聯合起來做的跑馬燈外掛原理。如果把兩份 code 稍微改造一下,甚至還可以把 YouTube 影片網頁裡面的瀏覽人次等其他資訊一起寫到文件檔裡面,並且顯示在實況畫面呢。

  感謝大家把滑鼠滾輪滾到這,我是豬腳,我們下次再會。
 
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4249603
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:OBS|實況|遊戲實況|實況台|YouTube|音樂|外掛|Golang|Go|JavaScript

留言共 50 篇留言

絲庫忒・艾莉雅
先卡位 下次實況用

01-04 03:07

A2266604
我是文盲

01-04 03:12

luilo
先留個言免得別人以為自己看不懂[e8]

01-04 03:16

我是月太 づ(・ω・)づ
抱歉我來傳教一下,其實也可以配 Node.js,這樣就不用多學 Go XD

01-04 05:07

解凍豬腳
我才不要!
Golang 大法好
宗教戰爭打起來 XD01-04 05:21
泛泛之輩
原來是大佬阿(跪

01-04 05:28

柔柔
大推Golang神教

01-04 05:32

K-I-D
看不懂 知道你是大神就好

01-04 06:44

神話世紀
好棒

01-04 07:16

MR4031
https://truth.bahamut.com.tw/s01/201811/64a75fd96604c28f1f606558faf6a5f1.JPG

01-04 07:29

玄暗烏黛墨縲黑黓焦皂
酷欸,有夠白話。雖然我沒在實況,不過這玩意值得收藏

01-04 08:40

巴哈板孫文♫ユリ
魅力上升囉

01-04 09:04

解凍豬腳
什麼時候才可以跟文ちゃん觸發草叢事件 [e33][e33]01-04 14:31
Don
有看沒有懂,Q_Q我好弱

01-04 10:13

MR4031
話說程式語言不是只學一個就好?,學那麼多我會瘋掉

01-04 10:26

解凍豬腳
對,基本上只要先把一種學到精,其他的程式語言就等於先會一半了
但是各家程式語言的特性仍然有點不同:
https://forum.gamer.com.tw/Co.php?bsn=60076&sn=5542201501-04 14:35
MR4031
https://truth.bahamut.com.tw/s01/201812/907ab772b958bf6afe364f3c9aab6396.JPG

01-04 10:26

雪之王女‧F‧巧可奈
外行人看不太懂只能純推了>///<

01-04 10:46

Holysheep
看來是上機考都100分的工程師呢

01-04 11:14

Starlight
卡位等有空研究

01-04 11:17

夜月夢夢
結果設了跑馬燈還是有人問

01-04 11:59

休閒玩的小麥提督
打那麼多誰他媽看的完.jpg

01-04 12:05

忘記惹
看不懂...

01-04 12:12

紫幽幽
難得看到不是用node.js做小工具的

01-04 15:09

阿民
Golang能直接建立http server的特性真的很強,寫習慣後回去寫C,老實說,在語法上會不習慣XD

01-04 17:47

解凍豬腳
上上個月第一次接觸 Golang,從此棄用 Python XD
雖然 compile 出來的東西很胖,但 Golang 優點太多了
1. 它可以直接 compile 成 exe
2. Goroutine 太棒了,簡單好用
3. 它的 code style 超美 [e32][e32]
(我覺得把左大括號獨立成一行的都是邪教)01-04 18:00
阿民
而且能編譯成任何平台的二進位執行檔TM方便的,不用再安裝Runtime的感覺真好XD

01-04 17:53

解凍豬腳
真的,讚讚讚……用 Python 的話還得要用 Py2exe,而且還限版本01-04 18:01
阿民
我有提到那美好的go fmt嗎?(好像沒有)那真是美好的聚合體XD

01-04 18:46

卡姆喵
簡約但是這方法極神,請收下我的膝蓋<(__)>
這方法可以擴展到其他同樣想要擷取的網頁上的文字訊息吧?
感覺可以自己刻一個擷取實況聊天室成為彈慕的功能(O

01-04 19:54

解凍豬腳
沒有錯!果然是同樣有在 coding 的人呢 XD
但剛才去 Twitch 聊天室測試了一下
發現每一筆留言都沒有獨特的編號
所以面對同一人有重複留言的情況會比較難分辨出來01-04 20:47
死螞蟻司馬燚
阿是關我

01-04 21:19

ひびき
推實用

01-04 23:44

香飯炒腸
太酷炫了吧 我在實況測試使用結果失敗了現在老二卡在電風扇裡 問題出在哪

01-05 00:37

解凍豬腳
哇,太酷炫了吧,那我一定要看看你的測試過程 [e15]01-05 00:40
ひびき
請問出現undefined該怎麼解決呢

01-05 23:06

解凍豬腳
一直都是 undefined 嗎?怪了……01-05 23:08
解凍豬腳
我剛才稍微修正了一下,避免 undefined 的字樣被送出去
不過這應該還沒辦法解決抓不到標題的問題就是了
你可能要檢測元素,然後截圖給我看看01-05 23:23
解凍豬腳
如果你那邊腳本沒有自動更新的話,手動點到我這篇文章的腳本網址,就可以安裝新版本了01-05 23:24
別再打了我認錯就是了
乾好厲害,原來資工系讀到後面可以有這麼多應用
敬佩敬佩

01-07 23:22

解凍豬腳
我不是資工系的,是資管 [e6]
其實這裡的內容幾乎沒半點東西是從系上來的
學 coding 基本上都要靠自己01-07 23:24
別再打了我認錯就是了
噢記錯了,還以為你資工XD
既然大部分能自學那我還是早點開工學習好了(´_ゝ`)

01-07 23:40

粽鬱精
倉鼠語言(¯―¯٥)

01-08 01:54

解凍豬腳
https://stickershop.line-scdn.net/stickershop/v1/sticker/17570285/ANDROID/sticker.png01-08 01:57
氧化二氫
學到了利用 HTTP server 實現 javascript 輸出的方法,也請收下我的膝蓋
以及我觀察出 youtube 在切換標題時,會改變該標題元素的 text 節點
而監聽 DOM 節點可使用原生的 Mutation Observer API
https://developer.mozilla.org/docs/Web/API/MutationObserver
在被賦值為 undefined 等情形時,可以使用 || 運算子決定預設值
如果篩選不到預想的元素,似乎也可以直接篩選 <title> 標籤,不過此字串可能涵蓋原始標題餘外的其他資訊
我的程式碼:https://ideone.com/dhGj50

01-22 09:03

氧化二氫
程式碼改了小地方:https://ideone.com/xNjeVQ

01-22 09:14

解凍豬腳
這 code 漂亮很多
我一直是個 JavaScript 新手
每次抓資料總是用土法煉鋼的方式 XD
感謝分享02-06 09:48
喜德
雖然這個時候有點晚跪了,但還是請收下我的膝蓋><!!

04-26 13:06

碧綠色的兔子
豬腳你好~ 同層目錄下沒看到 title.txt 所以我自己新增了一個。然後我播放youtube時開啟中的exe也沒出現文字。我的OBS文字新增好了可是屬性無法選擇來源是title.txt,可以請你幫我解答嗎? 謝謝~

06-25 15:15

解凍豬腳
你是直接把程式下載來用嗎,如果是的話那你在那段 JavaScript 裡面的 accessKey 要清除,改成這樣:
const accessKey = '';

這個 accessKey 是我另外做的安全機制,程式裡面本身寫死的 accessKey 和 port 這兩樣東西,要和 JavaScript 腳本裡面的一樣 06-25 15:32
解凍豬腳
如果你要有 accessKey 功能的話,就要自己用 Golang 的環境自己再用我給的 code 重新編譯一個 exe 檔案 06-25 15:38
碧綠色的兔子
我是直接點 "寫好的程式在這:YouTubeListener.7z" 下載這個解壓縮來用。
accessKey.upk 這個檔案我打不開...我我我也聽不太懂java我是文科...不好意思...
我應該不要accessKey 功能沒關係! 那請問我可以直接把這檔刪掉嗎? 還是怎麼做比較簡單 呵呵不好意思

06-25 15:53

解凍豬腳
刪了也沒用,因為我是讓它自動產生 XD
上面有一個安裝到 Tampermonkey 的腳本對不對
妳打開 YouTube 後,從右上角 Tampermonkey 找到自動更新跑馬燈:
https://i.imgur.com/9tlRVHr.png
對它點右鍵,就可以編輯腳本內容,把這行:
const accessKey = '952d...0b0e';
改成:
const accessKey = '';

然後按 Ctrl+S,這樣應該就可以了?06-25 15:59
解凍豬腳
啊不好意思我說錯了,妳要用記事本把 accessKey.upk 打開
比如說妳看到的 accessKey 是 abcde12345
那 Tampermonkey 那邊妳就要改成:
const accessKey = 'abcde12345';06-25 16:06
碧綠色的兔子
(腳本?) 我剛剛沒裝Tampermonkey ,我現在裝好了。
可是我跟你圖片不太一樣。
你可以看這裡嗎? 因為我貼不了圖。謝謝。
https://i.imgur.com/vJoCp5K.jpg

06-25 16:10

解凍豬腳
妳沒有看內文……QQ06-25 16:14
解凍豬腳
Tampermonkey 那段有個「自動更新實況跑馬燈」要安裝06-25 16:15
碧綠色的兔子
我...我其實都有看完整篇...可是我看不懂的地方就看了也不懂呀,然後我就以為只要安裝最後面一個程式就萬事OK,我再去安裝一下。呵呵呵......

06-25 16:17

碧綠色的兔子
我確定我已經安裝好了!
https://i.imgur.com/RgzSAwN.jpg
可是好像還是跟你的圖片不一樣
https://i.imgur.com/YTssWiS.jpg
呵呵呵.......

06-25 16:24

碧綠色的兔子
(我有開啟EXE也有開啟YOUTUBE)

06-25 16:25

解凍豬腳
要在 YouTube 的分頁點開才會出現06-25 16:28
碧綠色的兔子
我在YOUTUBE點開 它還是這樣耶
https://i.imgur.com/SjnKL9z.jpg

06-25 16:44

解凍豬腳
我不確定妳的步驟是哪邊漏掉了,這真的很奇怪
「重新安裝版本 20190106」試試06-25 16:56
碧綠色的兔子
我重新安裝了。也重新確認KEY,它自己帶的就是我筆記本的我不用修改。
我的EXE開啟著。
跑馬燈顯示已啟用↓
https://i.imgur.com/46XOmt4.jpg
可我依然沒有你的圖片自動更新跑馬燈那樣子

06-25 17:11

解凍豬腳
妳的 YouTube 分頁網址是 ...www.youtube.com/... 形式嗎?06-25 17:14
碧綠色的兔子
ps.壓縮檔案打開沒有title.txt這個檔案唷
我第一次自己新增了進去,感覺沒幫助。
我現在是把它刪掉的狀態,不知道是不是這個檔案的原因。

06-25 17:14

碧綠色的兔子
我的YOUTUBE 是
h t t p s : / / www.youtube.com/watch?v=hLThkxsnQpk

然後我只開一個YOUTUBE

06-25 17:16

解凍豬腳
妳確定妳是停留在 YouTube 分頁的時候點擊 Tampermonkey 的按鈕卻沒有腳本?這不可能06-25 17:18
碧綠色的兔子
恩恩。youtube分頁 右上是灰的。其他分頁有的右上是黑有的是灰。

06-25 17:20

解凍豬腳
那妳改點選控制台:
https://i.imgur.com/Es7ZXZP.png

然後把那腳本點開,正確的內容該是這樣:
https://i.imgur.com/HAyBDEQ.png

如果有一行 // exclude 之類的,把那行刪掉

然後在這裡直接延續剛剛的步驟吧
把 accessKey.upk 用記事本開啟,複製裡面內容
然後把那串英文數字改到腳本裡面

我懷疑妳剛才是不小心按到 exclude youtube.com 才會這樣06-25 17:26
碧綠色的兔子
我沒有看到 // exclude 這行。
然後它自己帶了 accessKey.upk 那一串完全一樣,所以我不用改。
然後...我剛剛說的...就是那資料夾解完壓縮後打開沒有title.txt沒關係嗎?

06-25 17:31

碧綠色的兔子
阿 發生了很神奇的事情!! 我把YOUTUBE網址貼在右上黑的某個分頁...右上就出現跟你一樣了

06-25 17:34

碧綠色的兔子
可是那個....

所以,我們這時候打開 OBS,在場景裡面新增一個文字(GDI+),接著右鍵 > 濾鏡,新增捲動濾鏡,再憑自己喜好設定寬度,再右鍵 > 屬性,把檔案來源設成 title.txt,

右鍵> 屬性 沒有出現檔案來源?
https://i.imgur.com/Jm7nzDt.jpg

06-25 17:42

解凍豬腳
https://i.imgur.com/6FO9mUA.png06-25 17:47
解凍豬腳
https://i.imgur.com/gvZokV7.png06-25 17:47
碧綠色的兔子
有了 >"< 看到了 我一直沒注意下面有一行... 對不起...
謝謝豬腳大大
memeda....memeda..... >"<

06-25 17:58

我要留言提醒:您尚未登入,請先登入再留言

153喜歡★johnny860726 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:2019 年,你好... 後一篇:豬腳有個萬能老爸...

追蹤私訊

作品資料夾

nlpss05050有緣人
今日小屋更新,兩週事務所實習之外勤紀錄看更多我要大聲說1小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】