Spotify SDK 在尝试播放或跳过音频时抛出“this._streamer is null”错误

问题描述 投票:0回答:2

我正在构建一个应用程序,旨在利用 Spotify 的网络播放器 SDK 并允许播放。我已成功将用户帐户连接到播放器以及所有其他必需的先决条件,但每当我尝试播放音频(遵循 Spotify 自己的示例代码)时,我都会收到控制台错误,指示:

控制台错误

Uncaught TypeError: this._streamer is null

编辑:我本来会发布错误堆栈的其余部分,但其中包含的 Spotify API URL 将帖子标记为垃圾邮件,因此不幸的是它们已被删除。

目前,编码的 React 组件有点长,但我将删除与我想做的其他事情相关的不相关部分:

应用程序.js

// External imports
import { Fragment, useEffect, useRef, useState } from 'react';
import { useCookies } from 'react-cookie';

export default function CartPlayer(props) {

    const track = {
        name: "",
        album: {
            images: [
                { url: "" }
            ]
        },
        artists: [
            { name: "" }
        ]
    }

    const [player, setPlayer] = useState(null);
    const [isPaused, setIsPaused] = useState(false);
    const [isPlaybackActive, setIsPlaybackActive] = useState(false);
    const [currentTrack, setCurrentTrack] = useState(track);
    const [deviceId, setDeviceId] = useState(null);

    const [cookies, setCookie, removeCookie] = useCookies();

    const spotifyAccessToken = cookies.userSpotifyAuth.access_token;

    // Spotify SDK hook
    useEffect(() => {

        const script = document.createElement("script");
        script.src = "https://sdk.scdn.co/spotify-player.js";
        script.async = true;
    
        document.body.appendChild(script);
    
        window.onSpotifyWebPlaybackSDKReady = () => {
    
            const player = new window.Spotify.Player({
                name: 'Web Playback SDK',
                getOAuthToken: cb => { cb(spotifyAccessToken); },
                volume: 0.5
            });

            setPlayer(player);

            player.addListener('ready', ({ device_id }) => {
                console.log('Ready with Device ID', device_id);
                setDeviceId(device_id);
            });
    
            player.addListener('not_ready', ({ device_id }) => {
                console.log('Device ID has gone offline', device_id);
            });
    
            player.addListener('player_state_changed', ( state => {

                if (!state) {
                    return;
                }

                setCurrentTrack(state.track_window.current_track);
                setIsPaused(state.paused);

                player.getCurrentState().then( state => { 
                    (!state)? setIsPlaybackActive(false) : setIsPlaybackActive(true) 
                });

            }));

            player.on('playback_error', ({message}) => {
                console.error('Failed to perform playback', message);
            })

            player.connect();
    
        };

    }, []);

        // This function transfers active playback to the Spotify session in the browser
    useEffect(() => {

        async function transferPlayback() {

            await fetch('https://api.spotify.com/v1/me/player', {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer ' + cookies.userSpotifyAuth.access_token
                },
                body: JSON.stringify({
                    device_ids: [
                        deviceId
                    ],
                    play: true
                })
            });

        }

        if (deviceId) {
            transferPlayback();
        }

    }, [deviceId])

    if (!isPlaybackActive) { 
        return (
            <>
                <div className="container">
                    <div className="main-wrapper">
                        <b> Instance not active. Transfer your playback using your Spotify app </b>
                    </div>
                </div>
            </>)
    } else {
        return (
            <>
                <div className="container">
                    <div className="main-wrapper">

                        <img src={currentTrack.album.images[0].url} className="now-playing__cover" alt="" />

                        <div className="now-playing__side">
                            <div className="now-playing__name">{currentTrack.name}</div>
                            <div className="now-playing__artist">{currentTrack.artists[0].name}</div>

                            <button className="btn-spotify" onClick={() => { player.previousTrack() }} >
                                &lt;&lt;
                            </button>

                            <button className="btn-spotify" onClick={() => { player.togglePlay() }} >
                                { isPaused ? "PLAY" : "PAUSE" }
                            </button>

                            <button className="btn-spotify" onClick={() => { player.nextTrack() }} >
                                &gt;&gt;
                            </button>
                        </div>
                    </div>
                </div>
            </>
        );
    }

该代码与 Spotify 提供的示例非常相似,除了浏览器内“设备”准备就绪并获得 ID 时调用的函数,然后为自身请求活动状态,以便它可以主动播放音频。有谁知道这里会发生什么吗?

javascript reactjs spotify
2个回答
0
投票

我找到了一个解决方法/解决方案。问题似乎出在 React 18 上,从 SDK 调用的

iframe
出现了问题。

我的解决方案是降级到react 17,然后它就像一个魅力。我有一个私人仓库,所以我无法分享,但如果不是 18,请分享你的反应版本。

如果你像我一样并且使用过 Next.js,这是降级的方法 https://github.com/vercel/next.js/discussions/36006


0
投票

这个问题被问到已经很长时间了,但我最近在 Next.js 14 + React 18 上遇到了这个问题,不得不自己修复它,所以我想我会分享我的解决方案。

我注意到 iframe 也存在问题,可能特别是 React 18 现在如何使用

createRoot
,所以我开始尝试。看来在主组件中使用这样的组件来加载 Spotify SDK 是可行的:

import { type FC, createElement } from 'react';

const SpotifyScript: FC = () => {
  const script = createElement('script', {
    id: 'spotify-player',
    type: 'text/javascript',
    async: false,
    defer: true,
    src: 'https://sdk.scdn.co/spotify-player.js',
    onLoad: () => {
      console.log('Spotify loaded');
    },
    onError: console.error
  });

  return script;
};

export default SpotifyScript;

不确定到底是什么原因,但我已经测试过这个,它至少让我过去了调用

player.getCurrentState()
等错误。您仍然可以使用
window.onSpotifyWebPlaybackSDKReady
回调来创建播放器并将其保存到某种状态。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.