用 Raspberry Pi 打造一台 Spotify 播放器 – Part 1

最近把 Raspberry Pi 4B 改成 Spotify 播放器,想把製作方式記錄下來。

以前要在 Raspberry Pi OS 的 Chromium 上執行 Spotify Web Player,會因為缺少 Widevine DRM 支持的關係而無法播放。約在今年三月時,Raspberry Pi OS 正式提供了 Widevine DRM 的支持,所以現在只要在 Raspberry Pi OS 上安裝 Widevine DRM 的套件包即可用 Chromium 播放 Spotify!

在 Raspberry Pi OS 上開啟終端機,執行:

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install libwidevinecdm0
$ sudo reboot

然後用 Chromium 打開 https://open.spotify.com,就可以開始使用 Spotify 了。


不過我想把 Raspberry Pi 改成 Spotify 專屬播放機,所以接下來就來說明如何設定吧。

一開始要先做一些前置作業,先打開 Chromium 瀏覽器,然後在設定裡把「起始畫面」設成「開啟新分頁」:

打開 Raspberry Pi 設定,把 Display 裡的「Screen Blanking」設成「停用」:

接著切換到 Raspberry Pi 設定裡的「介面」,啟用「SSH」。

然後打開終端機,輸入 ifconfig,記下 Raspberry Pi 的 IP 位址。


我想利用 Chromium 的 Kiosk 模式來開啟 Spotify Web Player,並且在開機進入桌面時自動開啟 Chromium。這需要寫一些腳本程式,讓我們開始寫吧:

先在家目錄下建立一個 bin 資料夾,然後用文字編輯器 (nano) 開一個 start_kiosk.sh 檔案,並且存在 bin 資料夾裡:

$ cd ~
$ mkdir -p bin
$ cd bin
$ nano start_kiosk.sh

start_kiosk.sh 的內容如下,複製貼上後,Ctrl + O 存檔, Ctrl + X 離開:

#!/bin/bash

export DISPLAY=:0

while true;
do
  sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
  sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences

  sleep 1

  /usr/bin/chromium-browser \
    --kiosk \
    --noerrdialogs \
    --disable-infobars \
    https://open.spotify.com
done

說明:

export DISPLAY=:0 這行是指定要輸出的顯示器。

sed -i 這兩行是用來清理 Chromium 的 crash flag:

sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences

用 Kiosk 模式啟動 Chromium,且不要顯示錯誤對話框與訊息條:

/usr/bin/chromium-browser \
  --kiosk \
  --noerrdialogs \
  --disable-infobars \
  https://open.spotify.com

在終端機裡,用 chmod 修改 start_kiosk.sh 的執行權限:

$ chmod 755 start_kiosk.sh

然後編輯 ~/.config/lxsession/LXDE-pi/autostart:

$ nano ~/.config/lxsession/LXDE-pi/autostart

在 autostart 加入這一行:

@/home/pi/bin/start_kiosk.sh

Ctrl + O 存檔, Ctrl + X 離開 nano。然後重新開機。

重新開機後,可以看到開機後會自動開啟一個全螢幕的 Spotify Web Player 了!


雖然用手機上的 Spotify app 就可以遠端控制 Spotify Web Player,不過我還想要控制 Raspberry Pi 的系統音量,或是遠端控制重開機或關機,所以我寫了一個 Python script,可以透過 WebSocket 控制 Raspberry Pi。

程式碼在此:https://github.com/wlelab/SpotifyPi/blob/main/spotifypi_service.py

這個 Python 程式還需要搭配「Spotify Web Player Hotkeys」這個 Chrome 擴充套件使用,先用 ssh 連到 Raspberry Pi,然後 cd 到 ~/.config/lxsession/LXDE-pi/ 目錄,把 autostart 改名,然後重新開機:

$ ssh pi@<Raspberry Pi IP address>
$ cd ~/.config/lxsession/LXDE-pi/
$ mv autostart autostart_copy
$ sudo reboot

重開機後,會進入 LXDE 桌面而不是開啟 Chromium Kiosk 模式。

然後打開 Chromium,前往 設定 => 擴充功能 => Chrome 線上應用程式商店,搜尋「Spotify Web Player Hotkeys」這個擴充套件,並安裝之。

然後在 Chromium => 設定 => 擴充功能 => 鍵盤快速鍵 裡設定 hot keys,如下圖所示:

spotifypi_service.pystart_spotifypi_service.sh 下載下來,複製到 ~/bin 資料夾,並且修改執行權限:

$ chmod 755 spotifypi_service.py
$ chmod 755 start_spotifypi_service.sh

安裝 Python script 所需的套件:

$ pip3 install websockets
$ pip3 install pyautogui

然後 cd 到 ~/.config/lxsession/LXDE-pi/ 資料夾,把 autostart 的名稱改回來:

$ cd ~/.config/lxsession/LXDE-pi/
$ mv autostart_copy autostart

接著用 nano 在 autostart 裡加上這行:@/home/pi/bin/start_spotifypi_service.sh,如下所示:

@/home/pi/bin/start_spotifypi_service.sh
@/home/pi/bin/start_kiosk.sh

重新開機,這次會用 Chromium Kiosk 模式開啟。


在其他的 PC 上,下載 test.py,然後開啟終端機,執行:

$ pip3 install websockets
$ python3 test.py

會有以下的資訊輸出:

Usage: test.py [URL] [command]

command list:
    get_volume - get current volume value
    set_volume [number] - set volume, number value range: 0 ~ 100
    toggle_play_pause - toggle play / pause
    next_track - next track
    prev_track - previous track
    toggle_shuffle - toggle shuffle
    toggle_repeat_state - toggle repeat off / single song / whole playlist
    shutdown - shutdown machine
    reboot - reboot machine

其中 URL 的格式為 ws://<Raspberry Pi IP address>:<Port>,我在 Python script 裡把 port 設為 9487。

假如 Raspberry Pi 的 IP 位址為 192.168.1.110,那麼 URL 就是「ws://192.168.1.110:9487」。

舉例,如果想取得當前的系統音量值:

$ python3 test.py ws://192.168.1.110:9487 get_volume

: [volume](40)

想設定系統音量值:

$ python3 test.py ws://192.168.1.110:9487 set_volume 55

: [volume](55)

想切換 播放/暫停 或是 下一首歌曲:

$ python3 test.py ws://192.168.1.110:9487 toggle_play_pause

: [toggle_play_pause](ok)

$ python3 test.py ws://192.168.1.110:9487 next_track

: [next_track](ok)

返回的內容格式為 [event](value),[ ] 內是事件名稱,( ) 內是事件的值。

既然可以透過 WebSocket 來控制 Raspberry Pi 了,所以我寫了一個 GUI app 來傳送控制命令,下一篇會講解如何編譯執行那個 GUI app。