You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Ubuntu环境下Spotipy无显示器用户认证方案咨询

解决树莓派无显示器环境下Spotify语音助手的认证难题

核心问题

当前使用SpotifyOAuth默认依赖本地浏览器完成授权,但无显示器的树莓派无法操作;语音输入密码存在严重安全隐患。需要安全、简便地在无显示器环境完成Spotify用户授权。

方案一:远程授权(将验证链接发送至其他设备)

通过手动获取授权URL,让用户在其他设备完成登录后,返回授权码完成认证。

实现步骤

  1. 关闭自动浏览器跳转,手动获取授权URL
    修改认证逻辑,禁用自动打开浏览器,通过语音播报授权链接:

    from spotipy.oauth2 import SpotifyOAuth
    
    # 初始化OAuth对象,禁止自动打开浏览器
    sp_oauth = SpotifyOAuth(
        client_id="aaa000",
        client_secret="bbb111",
        redirect_uri="http://127.0.0.1:9090",
        scope="user-library-read,user-read-playback-state,user-modify-playback-state",
        open_browser=False
    )
    
    # 获取授权URL并语音播报
    auth_url = sp_oauth.get_authorize_url()
    engine.say(f"请在其他设备打开链接完成授权:{auth_url}")
    engine.runAndWait()
    
  2. 获取授权码并完成认证
    用户在其他设备登录后,Spotify会跳转到设置的redirect_uri,URL中包含code参数。让用户通过语音告知该参数,程序即可完成认证:

    engine.say("授权完成后,请告诉我回调URL里的code参数")
    engine.runAndWait()
    auth_code = listen().strip()
    
    # 用code获取token并初始化Spotify客户端
    token_info = sp_oauth.get_access_token(auth_code)
    sp = spotipy.Spotify(auth=token_info['access_token'])
    
  3. 本地保存token,避免重复授权
    将token写入本地文件,下次启动直接读取,过期自动刷新:

    import json
    import os
    
    TOKEN_FILE = "spotify_token.json"
    
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, 'r') as f:
            token_info = json.load(f)
        if sp_oauth.is_token_expired(token_info):
            token_info = sp_oauth.refresh_access_token(token_info['refresh_token'])
            with open(TOKEN_FILE, 'w') as f:
                json.dump(token_info, f)
        sp = spotipy.Spotify(auth=token_info['access_token'])
    else:
        # 执行上述授权流程后,保存token到文件
        with open(TOKEN_FILE, 'w') as f:
            json.dump(token_info, f)
    

方案二:设备授权流(官方推荐无浏览器方案)

Spotify提供专门针对无浏览器设备的设备授权流,无需用户输入复杂授权码,流程更简便。

实现代码

from spotipy.oauth2 import SpotifyDeviceAuth

# 初始化设备授权对象
sp_oauth = SpotifyDeviceAuth(
    client_id="aaa000",
    client_secret="bbb111",
    scope="user-library-read,user-read-playback-state,user-modify-playback-state",
    open_browser=False
)

# 获取验证信息并语音播报
auth_info = sp_oauth.get_device_authorization()
engine.say(f"请打开网址 {auth_info['verification_uri']},输入验证码 {auth_info['user_code']},完成后告诉我")
engine.runAndWait()

# 等待用户确认授权完成
while True:
    response = listen()
    if "完成" in response or "好了" in response:
        break
    engine.say("请确认授权完成后告诉我")

# 获取token并初始化客户端
token_info = sp_oauth.get_access_token()
sp = spotipy.Spotify(auth=token_info['access_token'])

流程说明

程序启动后会生成一个验证网址和8位验证码,用户在任意设备浏览器打开网址、输入验证码并登录Spotify账号,即可完成授权。验证码有效期为15分钟,超时需重新生成。

整合后的完整代码(设备授权流+token持久化)

import spotipy
from spotipy.oauth2 import SpotifyDeviceAuth
import pyttsx3
import speech_recognition as sr
import json
import os

engine = pyttsx3.init()
recognizer = sr.Recognizer()
TOKEN_FILE = "spotify_token.json"

def listen():
    with sr.Microphone() as source:
        recognizer.adjust_for_ambient_noise(source)
        audio = recognizer.listen(source)
        try:
            return recognizer.recognize_google(audio).strip()
        except sr.UnknownValueError:
            engine.say("没听清,请再说一遍")
            engine.runAndWait()
            return listen()
        except sr.RequestError:
            engine.say("网络异常,无法识别语音")
            engine.runAndWait()
            return listen()

def init_spotify():
    sp_oauth = SpotifyDeviceAuth(
        client_id="aaa000",
        client_secret="bbb111",
        scope="user-library-read,user-read-playback-state,user-modify-playback-state",
        open_browser=False
    )

    # 读取本地token
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, 'r') as f:
            token_info = json.load(f)
        if sp_oauth.is_token_expired(token_info):
            token_info = sp_oauth.refresh_access_token(token_info['refresh_token'])
            with open(TOKEN_FILE, 'w') as f:
                json.dump(token_info, f)
        return spotipy.Spotify(auth=token_info['access_token'])
    else:
        # 首次授权流程
        auth_info = sp_oauth.get_device_authorization()
        engine.say(f"请打开网址 {auth_info['verification_uri']},输入验证码 {auth_info['user_code']},完成后告诉我")
        engine.runAndWait()

        while True:
            response = listen()
            if "完成" in response or "好了" in response:
                break
            engine.say("请确认授权完成后告诉我")
            engine.runAndWait()

        token_info = sp_oauth.get_access_token()
        with open(TOKEN_FILE, 'w') as f:
            json.dump(token_info, f)
        return spotipy.Spotify(auth=token_info['access_token'])

def play_song(song_name, sp):
    results = sp.search(q=song_name, limit=1)
    if not results['tracks']['items']:
        engine.say(f"未找到歌曲 {song_name}")
        engine.runAndWait()
        return
    song_id = results['tracks']['items'][0]['id']
    try:
        sp.start_playback(uris=[f"spotify:track:{song_id}"])
        engine.say(f"正在播放 {song_name}")
        engine.runAndWait()
    except spotipy.exceptions.SpotifyException:
        engine.say("请确保Spotify设备已登录你的账号并处于运行状态")
        engine.runAndWait()

if __name__ == "__main__":
    engine.say("正在初始化Spotify,请稍等")
    engine.runAndWait()
    sp = init_spotify()
    engine.say("你想播放什么歌?")
    engine.runAndWait()
    song_name = listen()
    if song_name:
        play_song(song_name, sp)

注意事项

  • 确保Spotify开发者应用中已添加方案一所需的redirect_uri,设备授权流默认启用无需额外配置。
  • 保存token的文件需设置合理权限,避免被其他用户读取。
  • 设备授权流的验证码有效期为15分钟,需提醒用户及时完成授权。

内容的提问来源于stack exchange,提问作者Arturo Medina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:50:21