Spotify player SDK in react - reactjs

I am trying to implement Spotify player SDK in my react app. But I do not know it is giving me an error that Spotify is undefined. I am trying to implement the script in the useEffect hook in this context file.
This is my context file and trying to set up player SDK in it. Thanks in advance.
import React,{ createContext, useState,useEffect } from 'react'
import { myPlaylist, fetchAnything } from "../../api-fetching/api-fetching"
// Get the hash of the url
const hash = window.location.hash
.substring(1)
.split("&")
.reduce(function(initial, item) {
if (item) {
var parts = item.split("=");
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = "";
export const MainContext = createContext();
const MainContextProvider = (props) => {
const authEndPoint = 'https://accounts.spotify.com/authorize?';
// Replace with your app's client ID, redirect URI and desired scopes
const clientId = "5c4e46e8acf24w794ru325qi535fw5325hsakf22be91378ff14";
let redirectUri = "";
if(process.env.NODE_ENV === "development") {
redirectUri += "http://localhost:3000/";
}
const scopes = [
"streaming", "user-read-email", "user-read-private",
"user-read-currently-playing",
"user-read-playback-state",
"user-library-read",
"playlist-read-collaborative",
"playlist-read-private"
];
const [token, setToken] = useState(null);
const [scriptLoading, setScriptLoading] = useState(true);
const [currentUser, setCurrentUser] = useState(null);
const [discover, setDiscover] = useState(null);
const [discoverPlaylist, setDiscoverPlaylist] = useState(null);
const [discoverPlaylistTracks, setDiscoverPlaylistTracks] = useState(null);
const [userPlaylist, setUserPlaylist] = useState(null);
const [ userPlaylistTracks ,setUserPlaylistTracks] = useState(null);
const [artistInfo, setArtistInfo] = useState(null);
const [albumTracks, setAlbumTracks] = useState(null);
const [newReleases, setNewReleases] = useState(null);
const [newReleasesTracks, setNewReleasesTracks] = useState(null);
const [searchResult, setSearchResult] = useState(null);
const [searchValue, setSearchValue] = useState("");
const [playlistTracks, setPlaylistTracks] = useState(null);
useEffect(() => {
let _token = hash.access_token;
setToken(_token);
fetchAnything(token, "https://api.spotify.com/v1/me", setCurrentUser);
if(scriptLoading){
const script = document.createElement("script");
script.src = "https://sdk.scdn.co/spotify-player.js";
script.async = true;
script.defer = true;
document.body.appendChild(script);
setScriptLoading(false);
}
window.onSpotifyWebPlaybackSDKReady = () => {
const player = new Spotify.Player({
name: 'Web Playback SDK Quick Start Player',
getOAuthToken: cb => { cb(token); }
});
// Error handling
player.addListener('initialization_error', ({ message }) => { console.error(message); });
player.addListener('authentication_error', ({ message }) => { console.error(message); });
player.addListener('account_error', ({ message }) => { console.error(message); });
player.addListener('playback_error', ({ message }) => { console.error(message); });
// Playback status updates
player.addListener('player_state_changed', state => { console.log(state); });
// Ready
player.addListener('ready', ({ device_id }) => {
console.log('Ready with Device ID', device_id);
});
// Not Ready
player.addListener('not_ready', ({ device_id }) => {
console.log('Device ID has gone offline', device_id);
});
// Connect to the player!
player.connect();
};
}, [token])
useEffect(() => {
if(currentUser){
myPlaylist(token, setUserPlaylist, currentUser.id);
}
}, [currentUser, token])
return (
<MainContext.Provider
value={{ currentUser,playlistTracks, setPlaylistTracks ,searchValue, setSearchValue,searchResult, setSearchResult,newReleasesTracks, setNewReleasesTracks ,newReleases, setNewReleases ,albumTracks, setAlbumTracks,artistInfo, setArtistInfo,discoverPlaylistTracks, setDiscoverPlaylistTracks,userPlaylistTracks, setUserPlaylistTracks, userPlaylist,discoverPlaylist,setDiscoverPlaylist,discover,setDiscover, token,setToken, authEndPoint, clientId, redirectUri, scopes }}>
{props.children}
</MainContext.Provider>
)
}
export default MainContextProvider

You must refer to the Player through a global object:
window.onSpotifyWebPlaybackSDKReady = () => {
const player = new window.Spotify.Player({
name: "Carly Rae Jepsen Player",
getOAuthToken: (callback) => {
callback("access token here");
},
volume: 0.5,
});
};

Related

TypeError: Cannot read properties of undefined (reading 'addEventListener'), don't know how to proceed

Learning react, currently trying to create a video call web app, however I get this error:
TypeError: Cannot read properties of undefined (reading 'addEventListener')
on this line of code:
useEffect(() => {
peer.addEventListener("negationneeded",handleNegotiation);
return () =>{
peer.removeEventListener("negotionneeded",handleNegotiation);
};
},[]);
handleNegotiation:
const handleNegotiation = useCallback(() => {
const localOffer = peer.localDescription;
socket.emit("call-user",{userID: remoteUserID, offe: localOffer });
}, []);
here is also the whole file:
import React, {useEffect, useCallback, useState} from 'react';
import ReactPlayer from "react-player";
import { useSocket} from "../providers/Socket";
import { usePeer } from "../providers/Peer";
const SessionPage = () => {
const { socket } = useSocket();
const { peer, createOffer, createAnswer,setRemoteAns,sendStream,remoteStream } = usePeer();
const [myStream,setMyStream] = useState(null);
const [remoteUserID, setRemoteUserID] = useState();
const handleNewUserJoined = useCallback(
async(data) =>{
const {userID} = data
console.log("New user joined the session",userID);
const offer = await createOffer();
socket.emit('call-user',{ userID, offer });
setRemoteUserID(userID);
},
[createOffer,socket]
);
const handleIncomingCall = useCallback( async(data) => {
const {from, offer} = data;
console.log("Incoming Call from", from, offer);
const ans = await createAnswer(offer);
socket.emit("call-accepted",{userID: from, ans});
setRemoteUserID(from);
},
[createAnswer, socket] );
const handleCallAccepted = useCallback(async(data) => {
const {ans} = data;
console.log("Call Got Accepted",ans);
await setRemoteAns(ans);
}, [setRemoteAns]);
const getUserMediaStream = useCallback(async() => {
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
setMyStream(stream);
}, []);
const handleNegotiation = useCallback(() => {
const localOffer = peer.localDescription;
socket.emit("call-user",{userID: remoteUserID, offe: localOffer });
}, []);
useEffect(() => {
socket.on("user-joined",handleNewUserJoined);
socket.on("incoming-call",handleIncomingCall);
socket.on("call-accepted",handleCallAccepted);
//return () =>{
// socket.off("user-joined",handleNewUserJoined);
//socket.off("incoming-call", handleIncomingCall);
//socket.off("call-accepted",handleCallAccepted);
//};
}, [handleCallAccepted,handleIncomingCall, handleNewUserJoined, socket]);
useEffect(() => {
peer.addEventListener("negationneeded",handleNegotiation);
return () =>{
peer.removeEventListener("negotionneeded",handleNegotiation);
};
},[]);
useEffect(() => {
getUserMediaStream();
},[]);
return(
<div className='session-page-container'>
<h1>Hi mom, Im on TV :D</h1>
<h4>You are now online with {remoteUserID}</h4>
<button onClick={(e) => sendStream(myStream)}>Share my video</button>
<ReactPlayer url={myStream} playing muted/>
<ReactPlayer url={remoteStream} playing/>
</div>
)
}
export default SessionPage;
--> Peer file
import React, { useMemo, useEffect, useState, useCallback } from "react";
const peerContext = React.createContext(null);
export const usePeer = () => React.createContext(null);
export const PeerProvider = (props) => {
const [remoteStream, setRemoteStream] = useState(null);
const peer = useMemo(() =>
new RTCPeerConnection({
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:global.stun.twilio.com:3478",
],
},
],
}),
[]
);
const createOffer = async() => {
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
return offer;
};
const createAnswer = async (offer) => {
await peer.setRemoteDescription(offer);
const answer = await peer.createAnswer();
await peer.setLocalDescription(answer);
return answer;
};
const setRemoteAns = async(ans) =>{
await peer.setRemoteDescription(ans);
};
const sendStream = async(stream) => {
const tracks = stream.getTracks();
for(const track of tracks){
peer.addTrack(track,stream);
}
};
const handleTrackEvent = useCallback((ev) =>{
const streams = ev.streams;
setRemoteStream(streams[0]);
}, [])
useEffect(() => {
peer.addEventListener("track",handleTrackEvent);
return () =>{
peer.removeEventListener("track",handleTrackEvent)
}
},[handleTrackEvent, peer])
return(
<peerContext.Provider value={{ peer, createOffer, createAnswer, setRemoteAns, sendStream,remoteStream}}>{props.children}</peerContext.Provider>
);
};
useEffect with calling addEventListener on peer works earlier than some value assigned there.
Just add check of value existed:
useEffect(() => {
if (!peer) return
peer.addEventListener("track",handleTrackEvent);
return () =>{
peer.removeEventListener("track",handleTrackEvent)
}
},[handleTrackEvent, peer])

localhost/:1 Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'srcObject') at SocketContext.js:27:1

Unable to get the video in my webapp
Showing error in line
myVideo.current.srcObject = currentStream;
My SocketContext cod
import React,{createContext,useState,useRef,useEffect} from "react";
import {io} from 'socket.io-client'
import Peer from 'simple-peer'
const SocketContext = createContext()
const socket = io('http://localhost:5000')
const ContextProvider = ({children}) => {
const [stream, setStream] = useState()
const [me,setMe] = useState('')
const [call, setCall] = useState({})
const [callAccepted, setCallAccepted] = useState(false)
const [callEnded, setCallEnded] = useState(false)
const [name, setName] = useState('')
const myVideo = useRef()
const userVideo = useRef()
const connectionRef = useRef()
useEffect(() => {
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then((currentStream) => {
setStream(currentStream);
myVideo.current.srcObject = currentStream;
});
socket.on('me', (id) => setMe(id));
socket.on('callUser', ({ from, name: callerName, signal }) => {
setCall({ isReceivingCall: true, from, name: callerName, signal });
});
}, []);
const answerCall = () => {
setCallAccepted(true)
const peer = new Peer({initiator:false,trickle:false,stream})
peer.on('signal', (data) => {
socket.emit('answerCall',{signal: data,to:call.from})
})
peer.on('stream', (currentStream) => {
userVideo.current.srcObject = currentStream
})
peer.signal(call.signal)
connectionRef.current = peer
}
const callUser = (id) => {
const peer = new Peer({initiator:true,trickle:false,stream})
peer.on('signal', (data) => {
socket.emit('calluser',{userToCall:id,signalData:data,from:me,name})
})
peer.on('stream', (currentStream) => {
userVideo.current.srcObject = currentStream
})
socket.on('callAccepted',(signal) => {
setCallAccepted(true)
peer.signal(signal)
})
connectionRef.current = peer
}
const leaveCall = () => {
setCallEnded(true)
connectionRef.current.destroy()
window.location.reload()
}
return (
<SocketContext.Provider value={{call,callAccepted,myVideo,userVideo,stream,name,me,callEnded,setName,answerCall,callUser,leaveCall}}>
{children}
</SocketContext.Provider>
)
}
export {ContextProvider,SocketContext}
enter image description here
enter image description here

Api called twice next js

wondering how this could happen when this get call API twice. I'am using nextjs with typescript and using and design.
Below my code
const EditRoles = () => {
const router = useRouter();
const router = useRouter();
const { id } = router.query;
const [detail, setDetail] = useState();
const [rolePermission, setRolePermission] = useState([]);
const [pagination, setPagination] = useState<Params>({
page: 1,
row: 10,
});
const [loading, setLoading] = useState(false);
const [nextPage, setNextPage] = useState(0);
const getRolePermission = async (payload: { page?: number; row?: number; search?: string }) => {
if (id) {
setLoading(true);
const res = await httpService
.get(`${apiUrl.user}/v1/role-permission/${id}`, { params: payload })
.then((resp) => resp);
const rps = await res.data;
setLoading(false);
const roleP = rps.data.map((rp) => {
return { ...rp };
});
setRolePermission(rps.page === 1 ? roleP : [...rolePermission, ...roleP]);
setNextPage(rps.nextPage);
setPagination({ ...pagination, page: pagination.page + 1 });
console.log('this next page: ', rps.nextPage);
}
};
useEffect(() => {
getDetailRole();
getRolePermission({
...pagination,
});
form.setFieldsValue({
name: detail,
permissions: rolePermission,
});
}, [id, form, detail]);
return (
// ... HTML GOES HERE ... //
);
};
export default EditRoles;
And below are this result for the code. testing code
My question is, why this api called twice and the pagination sometimes breaking like the video?
Please help what is wrong with the code.
Thank you

user.displayName not showing on react firebase app

const [user, setUser] = useState({});
const [pass, setPass] = useState('')
const [name, setName] = useState('')
const [isLoading, setIsLoading] = useState(true)
const auth = getAuth();
const inputHandler = e => {
setUser(e?.target.value)
}
const passHandler = e => {
setPass(e?.target.value)
}
const nameHandler = e => {
setName(e?.target.value)
}
const toggleLogin = event => {
setIsLogIn(!event.target.checked);
}
const signUpHandler = (e) => {
signUp(user, pass)
.then(result => {
setUserName();
history.push(url)
// console.log(url)
})
.finally(() => {
setIsLoading(false)
})
.catch((error) => {
setError(error.message)
// ..
});
e.preventDefault()
}
const signUp = (user, pass) => {
setIsLoading(true)
return createUserWithEmailAndPassword(auth, user, pass)
}
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user)
// console.log("auth changed",user.email)
} else {
setUser({})
}
setIsLoading(false)
});
}, [auth])
const setUserName = () => {
updateProfile(auth.currentUser, {
displayName: name
});
Before displayName property being updated its redirecting to the route it came from. Is this happening for asynchronous nature?
I'm trying to set the displayName property on the navbar.displayName is getting set but not showing on ui, but showing after when I refresh the page. How can I fix this issue?

How to pass variable to hook in React?

I am trying to pass some custom metadata to my firebase firestore, I believe I must pass the metadata I grabbed in my component up to the hook but am unsure how to do so,
my component:
const UploadForm = () => {
const [file, setFile] = useState(null);
const [error, setError] = useState(null);
const [metadata, setMetadata] = useState(null);
const types = ['image/png', 'image/jpeg'];
const changeHandler = (e) => {
let selected = e.target.files[0];
if (selected && types.includes(selected.type)) {
setFile(selected);
setError('');
const pieceName = document.getElementById("pieceName").value;
const pieceDescription = document.getElementById("pieceDescription").value;
const newMetadata = {
customMetaData: {
artName: pieceName,
artDescription: pieceDescription
}
};
setMetadata(newMetadata);
...
export default UploadForm;
& my hook:
const useStorage = (file, metadata) => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
// references
const storageRef = projectStorage.ref(file.name);
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
}, (err) => {
setError(err);
}, async () => {
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt, metadata });
setUrl(url);
});
}, [file, metadata]);
return { progress, url, error };
}
export default useStorage;
I am able to upload to Firebase Storage/firestore no problem but don't know how to feed this extra metadata.
To change the metada just call the updateMetadata on the ref:
const useStorage = (file, metadata) => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
// references
const storageRef = projectStorage.ref(file.name);
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
}, (err) => {
setError(err);
}, async () => {
await storageRef.updateMetadata(metadata)
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt, metadata });
setUrl(url);
});
}, [file, metadata]);
return { progress, url, error };
}
export default useStorage;
You can read more about it here.

Resources