小屋創作

日誌2019-01-04 03:03

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

作者:解凍豬腳

 
  這次來分享一下最近的靈感和成果吧。

  平時用 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 影片網頁裡面的瀏覽人次等其他資訊一起寫到文件檔裡面,並且顯示在實況畫面呢。

  感謝大家把滑鼠滾輪滾到這,我是豬腳,我們下次再會。
 

154

51

LINE 分享

相關創作

[達人專欄] 自作輕爵士鋼琴曲:”Those Wonderful Days We Had”

【樂譜】The Dark Knight - Like a dog chasing cars

[Minecraft日記]現實逃避行 #100

留言

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

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