How To Build A Better Spotify With React

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video i'm going to show you how you can create spotify but actually make it even better because we can search for any song that we want for example a random stream beats song and when we play it it'll actually pull up the lyrics of that song [Music] welcome back to web dev simplified my name is kyle and my job is to simplify the web for you so you can start building your dream project sooner so if that sounds interesting make sure you subscribe to the channel for more videos just like this now to get started we're going to be building out a react application for this spotify app so i just have a simple client folder that i ran create react app in as you can see i just have all the boilerplate react code and then i have an empty server folder where we're going to put all of our server code because we actually need a server to do some of the authentication and lyric lookups for our application also a really interesting tool that we're going to be using in this video is something called tab nine so if you just go over to your extensions here and do a quick search for tab nine you'll see tab nine just click enable or install whatever it is for you and this will install the tab nine extension for you and tab 9 is a completely free auto complete ai generator so it'll use ai to generate auto completions for you these auto completions are amazing they're so much better than the standard vs code ones and honestly they made creating this project so much easier and as you see throughout the rest of this video we're going to use tons of table9 autocompletes that just make writing code so much easier it makes it more enjoyable honestly it's just a really powerful tool tab 9 was actually kind enough to sponsor this video so if you want you can find a link in the description with additional information about tab 9 if you want to learn more about it but other than that you're going to see tons of use cases of it as we write code in this tutorial so with that out of the way let's actually talk about how this application is set up we're actually going to be using the spotify api for this application because spotify has a huge list of music that we can search from and play and that'll make getting started with this application easier and then from there we're going to tack on additional functionality for the libraries that we're going to use for finding the lyrics of each song because spotify doesn't actually reveal lyrics to you so we need to use other libraries for that so if you just go to developer.spotify.com or just search spotify developers you'll get brought to this page and we need to go to the dashboard section this is where you can view all of your different applications and just make sure that you are logged in so let's just log in real quick and i'm already logged in so it logged me in and as you can see we have the spotify clone test that was what the demo project i showed you was that's what this is right here running and then we can create a new app down here so what you're going to want to do is just click on the create a new app button give your name an app we'll just call it spotify clone and then we'll give it a description we'll just say spotify but better there we go and then just check these marks you know essentially saying that you read terms of service and so on and now you can create an application and you can view your client id and you can also view the client secret if you click on this button you can even edit settings about your application and one important setting we're going to need to modify here is this redirect uris you're going to want to set this to the url of your website in our case since we're just doing testing we're going to set this to http backslash backslash localhost 3000 because that is going to be the port and address where we're running our application for testing but once you move past the testing phase you're going to want to remove this redirect uri and actually set it to the real uri of your actual application so once that's done just click save and that's pretty much all we need to do to set up our application on spotify's end and once you do that it will essentially allow you to log in with spotify because if i click this login with spotify button you can see it's going to bring me to this page here this is the working version application i just need to say that i agree to these terms and then it's going to redirect me to that redirect url which in our case is localhost 3000 and from here we can start using our application as you saw in the demo at the beginning of this tutorial but obviously we're not going to be using this version of our application we're going to build it from scratch so let's just close out of that and go over to our client here where we can actually start up our application so if we just open up a terminal and we cd into that client directory we can run npm start and that's going to start up the front end of our application which is just a simple react application then just give that a little chance it should start up and pop up over here and we just have the boilerplate react code rendering for us over here so nothing really crazy yet now the first thing i want to work on in our application is going to be authentication so if we just go over to spotify here and we go to the docs section we should find documentation if we click in the web api section we should hopefully find some documentation in here that goes over authentication if we just look around you can see we have authorization right here let's just click on that and here's how we get authorization and in spotify there's a bunch of different ways to actually do authorization but the best way to do it is if you have a server that you're able to use your client secret that they give you to actually do the authentication and if we just come down here you can see they have four different workflows and the one we're going to be focusing on right here is this authorization code which is this first workflow which is the one that requires a web server and it looks really complicated when you look at this diagram but it's actually fairly straightforward and simple to use i'm going to show you exactly how to do it so if we just scroll down here a little ways essentially what we need to do is we need to create an authorization url as you can see we have this https accounts.spotify.com authorize and then we have a bunch of different parameters we need to specify for this url we need to put our client id our response type the redirect uri and then all the way down here we need to put the scopes that we need to be able to access and as you can see here's like an example of what this would look like so to do this let's just copy this url here like this and inside of our source folder here let's just create a new component we're going to call login.js do the little rfc trick to be able to generate this just like that as you can see we have a functional component and we can create an auth url here we just set that to this for now and what we need to do is add in all of these additional extra information such as our client id we can say client underscore id we need to set that to our client id then the next thing that we need to set inside of here is going to be our response type and this it says needs to be set to code so let's just set this to code just like that and we also need our redirect uri and this is going to be that url we just entered which is http localhost 3000 and as you can see already if you look at my autocomplete suggestions i'm having autocomplete suggestions from tab9 that are automatically telling me oh you know what you probably want you know port 8080 or poor 3000 is kind of using ai to tell us what would be the best option so it's already making my code a little bit easier to read even for this string right here then we need our scopes so we can say and scope and scope is essentially just a space double limited list of all the different scopes that we need and instead of a url a space is just percent 20 so we just replace all of our spaces with percent 20. we actually have a bunch of different scopes we need to be able to access instead of having you watch me type it all i'm going to paste them in here and then explain exactly what scopes we have so the first scope we need to access is streaming then we use that percent 20 for a space then we need to access their email so that's user read email again percent 20 then user read private these are essentially required scopes to access user information then we have user library read this will determine if a song is in the user's favorite library and with user library modified we can actually add songs to their favorites user read playback state allows us just to figure out if they're playing songs and figure out what songs are playing which is great for our lyric lookup and then user modify playback state allows us to modify which song they're actually playing so pretty straightforward stuff and streaming again just allows us to play songs on their account so make sure you type in all of these exactly as is and all we have left is to enter in our client id so if we just back up here a little bit back to where we're on the dashboard you can see we have our spotify clone and we have our client id this is public so it's okay if we put it in our front end like this and that right there is our entire arthur url if we redirect to this url it'll actually ask us for all these different permissions and to sign in and to authenticate our application with this auth url now inside of this login component let's actually start rendering out all of different information and get a link that goes to this auth url essentially just a single button and i'm going to be using bootstrap for some of the styling let's just get into our client again and i want to npm i bootstrap and i want to get react bootstrap as well just hit enter on that and that allows us to use different bootstrap libraries and components so we could come in here and say for example import container and we want to get that from and as you can see it's already auto suggesting certain things but we want to get it from react bootstrap there we go and that allows us to get our container component also to ensure that we actually have these styles being rendered inside of here we just need to make sure we import the bootstrap slash disk bootstrap again this tab 9 is coming in super handy because that's the exact route we need we need the css and we need bootstrap.css and let's get the minified version of it so again tab 9 coming in super handy and for now let's clear out this app component and just render our login component so we can actually have it on our screen let's make sure that we import login and we want to import it from dot slash login again tab 9 coming in super handy normal vs code won't do that for you now with that saved we can get rid of like this app css app test index css the logo all this test release stuff and then here let's just make sure we get rid of our index css reporting of the web vitals and all this we just want a bare bones application and now finally in our login component we can actually create our component we're just going to use a simple container here now inside of this container we just need a single button and we're going to use an actual link for this but we can style it as a button by just giving it the class of button button success and we want to give it a button large class as well and we're going to give it an href and that href is just our auth url close off this button and we'll just say log in with spotify there we go now if we go over to our application you can see failed the file cannot resolve our bootstrap disk bootstrap cssbootstrap min.css so if we just go back into our app i accidentally put bootstrap in here one more one too many times it's just bootstrap dist css now if we say this should hopefully get rid of that error if i just refresh and you can see we have our button i just want to make sure this button is centered on our screen so we're going to come in here give this a class name of d flex we want to justify content in the center and we want to align items center make sure this is content and then also just to make sure we have a full height here we can set our min height equal to 100 vh now if i say that you can see our button is centered now if i click on this button i get redirected to that url appear which has all that information that we specified and it just tells the user to make sure they agree to this and if we click agree it'll redirect us back to localhost but you can see that we now have a code inside of our url we can use that code in the next step of our authorization in order to get a token which we can use for the user to authenticate them for all the different requests that we need so we need to convert this code here to a token if we go back to the spotify documentation there are going to be certain urls that we can access in order to do this but we're going to be using a library that makes it a little bit easier for us there's a library called spotify web api node which you can use both in node and on the browser so the name is a little misleading but essentially what this allows you to do is call the spotify api in a much easier way and as you can see it has tons of different things that you can do inside of it the thing we're focused on is authentication which is way down here in the documentation we just keep scrolling all the way we finally found the authorization section what we care about is right here the section that essentially allows us to create in a code we take our code and we can convert it into an access token and a refresh token which allows us to actually authenticate the user we need to do this on the server because it requires our client a secret which we can get inside of our dashboard here so we need to set up a server that we can actually use for this login code so inside of a server here let's just create a new file we're going to call it server.js and then i want to make sure that i go into that folder so i can just say cd dot dot slash server now we're in that server folder and i can just say npm init dash y to initialize a package json file and then i want to install express as well as that spotify web api node library that we just talked about we're going to use both of these libraries in order to set up a really basic server also i just run that again it looks like a field for some reason it should install both of these libraries for us if we look in the package json you can see both of those are here i also want to install here nodemon but i want this to be a dev dependency so let's just save that as a dev dependency and inside of our server we can start requiring some of our files we can get express which is just requiring express then we can get our app which is just equal to express and again tab 9 is coming in super handy it allows us just auto generate pretty much all this code also up here we want to get that spotify oops spotify api we'll call it web api just like that and that is just equal to require spotify web api dash node there we go so we have essentially the shell of our application and we can just say app.post and we want to post just a simple login application there we go and inside of here i just make sure that this is an arrow function inside of here i can create a new spotify api i can set it to spotify web api i want to make a new one of these so let's actually use capital s here just to clarify that this is a class that we're creating and inside of here i need to pass all the credentials so in our case we need to pass redirect url which in our case is a uri and that is just http localhost 3000 we also need to get our client id and we need to get our client oops client secret we can get both of these here from our dashboard so get the client id and store that in here and then get our client secret and obviously storing these is hard coded inside of our server is a bad idea since it's not very secure we're going to move these into an env file but for now i just want to test to see if this works and then if it works we can move it into an env file so now we have a spotify api and if we look at the documentation once we have a spotify api that takes in these different pieces of credentials what we need to do is get the code which we're going to pass up so we can just say like const code equals request dot body dot code we're going to pass it up in the request body then we can call this authorization code grant and pass it our code and this is just a promise which is going to return to us data that has the access token a refresh token and then a time when the actual access token is going to expire we can say spotify api dot authorize or authorization code grant pass it in our code we can just say dot then this is going to get our data and then we have access to all of the different information that we need and this is what we're going to return from our api so we can say res.json and we want to return an access token which is our data dot body dot access token and this is actually underscore token just because that's how the library works then we need to get our refresh token and this is just equal here if i spell token or access token quickly that's just the same thing data dot body and i want to get the refresh token and then finally we're going to have here our expires in this just data dot body dot underscore expires in and again tab 9 is making all this auto generation super easy now for some reason we have an error we can just throw in a dot catch here we're going to just do a simple res.send status and we're going to send a 400 status essentially we had some kind of error then we can just save that and that's really all that we need to do for our actual api it's super straightforward we just need to authorize that we have a code and once we do the software adjacent code it's going to give us this access token of refresh token we need to actually do the accessing the refreshing of our authentication and then we can just send down an error if for some reason we had a problem now if we go back down into our application you can see here we have our login if we go over here we have our code that's inside of our url so what i want to do is every time i access our page i want to get this code from our url we can just do this outside the component we can just say const code is equal to if we use url search rams we can pass it in our window.location.search and this is essentially going to get the portion of our code after this question mark this is just going to give us an object that has all this information so we can say dot get code and that's going to give us the url param that is called code which in our case is the one that we care about and if we have a code that we want to render a new component which in our case we're just going to call dashboard.js we'll just do a quick rfc here to get that dashboard generated up and now inside of our app let's import dashboard from dot slash dashboard and now what we can do is we can say if we have a code then we want to render out our dashboard we're going to pass it in the code that we have just like that otherwise we want to render this login component now as you can see when i save we're rendering that dashboard component and if inside of here i just rendered out our code and i save you're going to see our code is being printed out to the screen so this is working as we would expect obviously we don't want to print out this code but this is a good start now instead of putting all the logic for our login and authentication of refresh tokens in our dashboard i want to create a custom hook that handles all this logic for us we're going to call it use auth.js and we can just do a little rfc trick here and we don't care about any is being returned we just care about this being a custom hook called use auth now with use us i'm going to pass in the code that we need and what we're going to store inside of here is our access token our refresh token and our expires in essentially the three different things we're returning from our server when we log in so i want to get state for all those so i can say const access token i want to get set access token and i set that equal to use state and then i'm going to do the exact same thing but i want to get for our refresh token i want to set our refresh token and then this is going to be slightly different this is set expires in then right here we have our expires in this is just the three pieces of information we need and then in order to get that information we can just use a simple use effect down here we can say use effect inside this use effect we just clear out some of this we know our input here is going to be code that's the thing that we want to run this use effect every time our code changes and inside the shoes effect we just want to call that api that we created so first let's make sure we import use state and use effect just like that and then in order to call our api we're going to be using axios so let's just make sure we go back we just cd into our client folder here we can mpmi axios this will just make making requests so much easier than using fetch we can import axios from axios just like that let's make sure i spell axios correctly now in order to use axios we can just say axios.post and we can post to a specific url which in our case is going to be http localhost and right now if we go to our server we aren't running our application on any port so we can just say app.listen and we're just going to specify a port of 3001 for now that's just hard coded and now in here we can say at port 3001 we want to go to the login route and we want to post some data and this data is just going to be our code we're just posting our code to this route and it's going to call all the code on our server for us and then we can come in here and we can actually get our response and the part of the response we care about is our data so let's just say console.log res.data and see what this returns to us so now that we have that running down here let's cd back into our server and we just want to run our server and we're going to run it with node mod so to do that let's just create a simple task called devstart and all this is going to do is called nodemon server.js and now down here we can say npm run dev start and that should start up our server with nodebond as you can see it started up down here and now if we go inside of our dashboard and we make sure we pull in that use auth we can just say const access token which is the thing we care about is coming from use off and we're going to pass in the code so should hopefully run this for us if we save or immediately get an error we need to make sure we import use auth so let's just import use auth from dot slash use off like that now hopefully we don't get any errors when i refresh as you can see it worked and if we inspect we should hopefully get our data being returned if we go to our console you can see that we're getting an error is essentially saying localhost 3000 has been blocked by cores so we just have a cores issue this may sound complicated and difficult to solve but luckily course is really simple all we need to do is go to our server so let's just close out of this and we just want to install a package called course that's all we need to do and then inside of our server if we just import this package we can say const cores equals require cores and then we can say here app.use and call that course function and this is just going to fix all those cores errors we rerun our application and we just inspect our page over here and we just refresh over to our console you're going to notice now we're getting different errors we're saying request failed with a status code of 500 and inside of our console we're also getting an error being printed out cannot read property code of undefined so the issue with that is that our body is not able to be parsed so again we need to download a separate library called body parser so we say mpmi body parser and again we can require this just like we did with cores so we can say body parser equals require body parser and then we just say app.use body parser dot and we care about json so we're going to call the json function because we want to use the json body parser now if we rerun our application hopefully this is the last time we'll need to do this if we just refresh over here you can see again we're getting a request failed 400 but there's no error on our server so to see what's going on let's just get that error object and we're going to console.log our error to see exactly what's going on so just refresh down here and we get the error printed out if we scroll all the way up you're going to see it says an authentication error occurred while communicating with spotify's web api invalid grant authorization code expired essentially the code that we're trying to use has expired because you can only use a code once and then it expires very quickly afterwards so essentially our code no longer works we need to get a new code so one way we can fix this is if we have some kind of error like this then inside of our use auth here what we can do is just put a simple catch because this is going to catch any error that we get and what we want to do if we have an error is just redirect the user so we can say window.location equals localhost essentially our root location so we're just going to redirect the user back to the login page so now you can see we had an error so it redirects us back to you know login page here we click login with spotify you can see we didn't have an error this time so if we inspect and go to our console you can see we have our access token and our refresh token and it says it's going to expire in 3600 seconds which is essentially one hour one other issue you'll notice though is that we still have the code in our url and i'd kind of like to just remove that from our url so one easy way we can do that is just by saying here window.history.push state we just want to push in here essentially everything is going to be empty and we just want to push in the root url so that's just going to remove all this extra stuff from the end of our url so if we try this again it's again going to redirect us back to this page because our code has expired and if we log in you can see that now our url has been modified so we don't have that extra code section at the end of our url which is exactly what we want and now what we can do is use these setters here with our data to actually set our data so we can say set access token is res.data.access token copy this down a few more times we're going to set our refresh token this is coming from refresh token and then finally right here our expires in set expires in is going to come from our expires in now we have all the information we need and at the bottom we can just return our access token just like that so this access token right here is essentially the thing that we need to call all of the different spotify apis the ones that allow us to search for songs play for songs and so on but it only lasts for an hour and then it expires and it would suck if your user had to relog in every single hour if they wanted to use your application so instead what we're going to do is we're going to set up a little bit of a command that's going to automatically refresh the token for us so that way we don't have to worry about making the user log in and that's what this refresh token is for and again we need our server to be able to do the refresh for us but on our actual client side what we can do is set up the code to call our server so we can do inside of our use auth hook right here to set up another use effect this use effect is essentially going to say whenever our refresh token changes or whenever our expires in changes then what we want to do is run this use effect and that's because right before our token expires we want to make sure that we refresh it using this refresh token and to refresh it we're just going to create a route inside of our server here we're just going to say post this is just going to be for refresh and again this is going to take a request and a response and inside of here what we need to do is get our refresh token which is just going to be request.body.refresh token just like that because this is what we actually need to do the refresh if we go back to this api over here and just scroll down a little ways you'll see that we have another command called spotify api refresh access token and all we need to do is use the refresh token here and the refresh token is going to be set inside of our credentials up here so essentially if we just copy this spotify here we can say that we also need to patch it our refresh token and then we can use the rest of the code down here for actually refreshing our token let's just copy this exact code down here and i'm just going to convert this over to use arrow functions because i find them a little bit cleaner to work with i'm going to use the dot catch syntax here or if we just catch an error we're going to do the exact same thing we did down here where we just send that error to the user get rid of all of this there we go and then what we can do inside of here for now is we'll just say console.log data and we'll get rid of this so this will at least just print out the data that we're getting and we really will care about the data body because that's going to be the actual information from our response so if we save that this is what we're going to really care about and for now we're just going to access this information so if we go back into our use auth we can actually set up this hook that's going to do that refresh for us and it's going to look a lot like this here so i'm just going to copy our authentication instead we want to pass to refresh we want to pass it in our refresh token so we want to go to the refresh url and we want to pass it our refresh token and this is going to return to us some data and to see what that data is let's just comment this out for now essentially to see what that data is we're going to log it out into our server console so now all we need to do is just log in with spotify and you'll see immediately over here if we look we get the information being printed out that is our data and our data has an expires in it has an access token and then a token type and a scope and really all we care about is our access token and our expires in so we can actually use that information and pass it down to our user so back into our server instead of just console logging our data we can say res.json we're going to pass it in the json that is our access token which is our data.body dot access token and we want to get our expires in which is just our data dot body that expires in just like that this is the information we're passing down and then inside of our use off we can get essentially the same information but we only care about our access token and our expires in so we've essentially just done the same thing that we did up here but it's only for refresh which is why we're just getting an access token and the expires in if we get a failure for some reason again we're just going to redirect the user so now let's just see if this does anything if we log in with spotify you can see that immediately we're getting redirected back so something's not quite working right to see what that error is let's just go into our server and we're going to console.log any error that we get and now let's just log in and you can see we get an error being printed out so let's see exactly what this says all the whip is just as an authorization error invalid request refresh token must be supplied so let's just make sure request body dot refresh token and if we go back into use auth we are passing up the refresh token so that looks to be correct up here we are setting our refresh token to the res.data.refresh token let's just double check in our server that we're properly passing that down in our login refresh token is data dot body slash refresh token it appears all to be correct so again inside of our use auth let's just make sure we don't have anything else that is incorrect what we can do is we can just say console.log refresh token to see what our refresh token is at all points and now if we just log in with spotify inspect our console let's just try that one more time here but we're going to make sure that we don't redirect the user so just comment out this redirect here so now log in with spotify inspect go to our console and you're seeing we get undefined but then we actually do have a refresh token but we're still getting that wrong error coming through the nest place to look is obviously going to be in our server let's just put this back to how we had it get rid of this console log because it looks like everything's correct on our application end so inside of our server what we want to do find our slash refresh which is right up here we want to make sure our refresh token is actually something so console.log refresh token just like that now let's see if this actually prints out anything useful if we just scroll past the top of the error you're going to see our refresh token is undefined so clearly something is wrong with what is happening to our refresh token when it comes up to here so i think i know what the problem is if we go back into our use off our issue is actually here for example whenever our refresh token expires and changes this gets ran but it's actually running before we actually have a refresh token or expiring because it's running before this code finishes so we just put in a simple check that says if refresh token if we don't have one of those or we don't have an expires in time then i just want to return i don't want to do anything this should hopefully resolve the error if we log in you can see immediately we no longer have that error if we go to inspect our console we don't have any errors at all if we look inside of here again no errors so this is working as expected now the only other step is essentially make sure that we only do this refresh right before our thing expires so we can use the set timeout for that so we can just say cons timeout is equal to set timeout and inside of our set timeout we want to essentially do all of this code so let's put it inside of our set timeout here just like that and for our set timeout timer essentially what we want to do is we want to take our expires in time we want to essentially refresh this maybe one minute before it expires so if we just subtract 60 seconds that'll be one minute and we multiply by a thousand to convert this seconds to milliseconds and that'll be our perfect timeout then down here if we do have some kind of error we just want to make sure we clear our timeout we can just return clear timeout and we can pass it in our timeout just like that so this is just going to make sure that if for some reason our refresh token expires and changes before an actual refresh we just make sure we clear the timeout so we don't use an incorrect refresh token now hopefully we don't actually have any calls to our api we shouldn't get anything printed out down here and as you can see we don't because we're not actually refreshing now to check to make sure that this timeout works let's set our refresh to something like 61 seconds and since we're subtracting 60 seconds this will essentially refresh every one second we're going to set this to 61 here and right here we're also going to set it to 61 just to see if this works and if we save we should hopefully see a bunch of things being printed out because every second we should do a refresh so after one second of time we should have something being printed out but we don't let's just make sure if we inspect we have no errors here but it looks like nothing's going up to our server if we go to our server it looks like we're not even printing anything in here so let's just try a console log that says hi to see if we actually are printing up to our server and we'll just refresh over here real quick log in and hopefully we should see high getting printed out and we get it printed out once but we don't get it printed out anymore the reason this is occurring is because our expires in and our refresh token are technically never refreshing so the set timeout is only being run once if we want to make sure we run this every single time our expires and time changes we can change this to a set interval now this is going to run on an interval every single time essentially our expires and is about to change and if at any point our refresh token or expires and changes then it's going to make sure that it actually does the refresh of this timeout for us so now let's just make sure we change this to a clear interval we're going to call this timeout variable interval let's just copy this up to here and now if we just click log in here we should see high being printed out once every second and as you can see it's printing out once every second it's continuing to print out a little hard to see but if i make this a little larger you can see that it's continually printing out once every single second so let's just bring this back down here and let's make sure we change this to our res.data dot expires in so that this section works and up here same thing res.data.expires in so essentially that's all of our authorization code taken care of for us we have refreshing happen automatically in the background for us we also have here that our token is being created for us immediately so in our dashboard we have access to that access token and the great part is all that confusing and convoluted code is hidden away in this use off hook so we don't even have to think about it when we're working with our dashboard now the next thing that i want to focus on is essentially the search bar that's going to show up at the top of our page when we're logged in we'll have a search bar up here so first i'm going to wrap everything inside of a container let's just do a container here let's just make sure we import container we're going to get that from react bootstrap and also while we're at it we're going to import form because we're going to need a form and speaking of that form let's just come in here and get a form dot control the type of search this is going to be for our search section we're also going to give it a placeholder value this is just going to say search song artists and also we're going to give it a value this value is going to be a variable called search which we're going to create and it's just going to be some state so on our on change what we can do is we can say e we can set our search based on that e dot target dot value that's all it really takes to create that and up here we're just getting an error that says we didn't finish off our string so now if we save everything looks like it's working we just don't have those variables created so let's import use state up here and we're going to get our search and our set search and those are going to be equal to use state and by default we'll just make it an empty string so if we save you can see we log in that we now have that search bar at the top let's add a few little styles to our container to make our styling a little bit better we're going to of course make it a flexbox container and we're going to style everything in the flex column direction so it's critical and put some padding on the top and bottom of two also something i'm going to do preemptively is just set our height here to 100 vh for our container the reason i'm doing that is because the actual player we want to put at the very bottom of our screen and we want to put all the songs that are searched for or the lyrics in the very middle and those are going to take up all the rest of the spot we can create a simple div here with a class name of flex grow one and this is essentially going to grow to fill all the available states we're also going to put some margin on the top and bottom and this is where all the songs or lyrics are going to go to make sure that this is a scrollable section we're going to set the style here to be overflow y of auto that way it'll scroll if it needs to and this is where essentially our songs are going to go if we log in here you can see this is our songs section and at the bottom whatever we put down here we just create a div called bottom it should show up at the very bottom of our page as you can see this text bottom is at the very bottom of our page so now in order to use the spotify api we're actually going to use the same library we used on the server so let's create a new terminal tab here cd into our client i'm going to npmi that's spotify web api node and even though it's called spotify web api node it's actually usable within the browser so if once we have this created we can actually import this so we can say import spotify web api from spotify web api node and we can just say cons spotify api equals new spotify web api we again need to pass it in parameters so in our case our client id and our client id we can just copy from here just like that now also in order to do all the searching and stuff we're going to need to set up a few use effects so let's import use effect and then within here we'll create a use effect and this first use effect is going to be whenever our access token changes we need to make sure we set our access token on our spotify api so we can say spotify api dot set access token and pass in our access token we want to make sure first of all that we have an access token so if we don't have one we're going to return so if we don't have one return otherwise we're going to set it on our spotify api to use that access token for all of our further queries that way we don't have to specify it every time we try to make a query just go back to our app over here and now we can actually set up our use effect which is going to be for searching so every single time that our search query changes or whenever our access token changes we want to make sure we rerun this code and to save our search we're going to get a state called search results and we're going to set search results and we're going to set this to an empty array so now if we don't have a search then what we want to do is just return here and we want to set our search results equal to an empty array because if we don't have any search essentially we don't have anything to search for so we're going to empty out our search results also if we don't have an access token yet we want to just return again because we don't want to query anything if we don't have an access token let's just make sure we return then finally what we can do is actually do the search query so i can say spotify api and what i want to do is search tracks and what this is going to do is we can pass in our search which in our case is our search term and this will search any tracks on spotify based on artist name album name track name and so on it uses a bunch of different criteria based on the search term this just as a promise so we can say dot then and we're going to get our response now before we do anything i'm just going to console.log this response and if i save this hopefully when i log in and i start searching for something we should have some data being printed out as a response as you see we have three different responses because i changed my search three different times if i open this up you can see we have a section called body which we care about and inside of that body section we have a tracks section inside of here we have our items section which contains all the different items as you see inside here we have even more information so we have res dot body dot tracks dot items and this is going to contain the list of all the different tracks that we care about and as you can see we have the artist and really we're just going to list out one of the artists names so we get the first artist name we can get the album image which is inside of here and also on top of that we can get the name of the track right here so we want to get the name we want to get the uri so we can play it we want to get the album art and we want to get the artist name so let's just do a simple map over this to get all that information we can say res.body.tracks.items.map we're going to map through each one of the tracks now for each track we just want to return down here we want to get the artist name so we're going to just say artist name actually we'll just call it artist and that is just track dot artists and this is an array and the very first one we're going to get and we're going to get their name so we'll just say the very first artist dot name then what we want to do is get the name of the track we'll call it title and that's just track dot name i'm going to get the uri which is just track.uri then of course we want to get the album url this album url is going to be a little bit trickier but if we come into this album section we have an images array so we can say track dot album url dot images and essentially what we want to do is get the smallest one and we're not going to know exactly which one the smallest one is so we're going to write a little bit of code to do that for us we say con smallest album image and this is just going to take our track dot album dot images right here we want to reduce this down to one value so we're going to take our smallest and we're going to take the current image and all we want to do is if image.height is less than our smallest dot height because if we look here we have a height property on all of our different images then we want to return the current image otherwise what we want to do is we want to return the smallest and then to populate the very first value we're just going to get the first image as the starting point so we'll just say here track album images of zero so essentially all that this is doing right here we just expand this out so it's a little easier to read we're just saying okay what we want to do is loop through all of our images and at any point if the current image is smaller than the smallest we're going to set that as our new smallest image and now we can take our smallest album image and we can get the uri i think is what it's called if we just open up our console again we can be 100 sure under our console go into our album images and it's actually url so let's just make sure we set that as url and this information we want to just set for our search results so set search results equal to the return of this now if we save this hopefully we should have this search results variable being set and we can just console.log search results up here to see exactly what's happening and of course we're already getting errors and it just says right here unexpected token expected comma that's just down here it looks like i'm missing some parentheses in place i think this is just an extra parenthesis right here instead that parentheses should be right there there we go that cleaned up our code for us we don't have anything being printed out so if we log in you can see we have empty array and when i start searching you can see we now have items being populated in there and as you can see we have an album url an artist a title and the uri to actually play the song that's all the information that we need about each one of our tracks and every single time i type something it prints out a new list but there's one slight problem with this is that some of these requests may take slightly longer some may come back quicker so what we want to do is every time we change our search or access token we want to cancel this request there's really no super good way to cancel our request so instead what we're going to do is we're just going to create a simple variable called cancel we're going to set it equal to false we're going to do this all the way up here before we make our api request then inside of here if cancel is equal to true i just want to return i don't want to do anything and finally when we come down here all the way at the bottom we can return and inside of here we can just set cancel equal true what this is going to do is essentially going to say okay make the request and if a new request is made in this time period we're going to set the cancel for the previous request to true which inside of here will actually cancel that request for us we can actually see this but if we inspect our page go to our console we shouldn't have this being printed out a bunch of times so i can type a bunch of different times and you can see it still prints out empty but as soon as i stop typing then it'll actually do the request for us of course there's no songs with that title but if i do a little bit less typing and stop again note songs we'll just try a little bit less typing and stop you can see there's five songs that have that but it immediately did those five results and it didn't do any of the other results and now if i delete a bunch of things do that again you can see immediately it did just the printing out once because it only did the query one time where it actually didn't have cancel set to true and that's just because every time i typed a new character it came in before this set search results executed which made sure that the cancel was set to true for the previous one so it never actually set the results until i finished typing now let's just get rid of this console log so we don't pollute things and what i want to do is actually take those search results and display them down here where it says songs so to do that let's just take our search results map over them so we have a track for each one of these and essentially all that i want to do is that if you want to return a new component and this component we're just going to call it a track result actually we'll call it a track search result in this track search result we're going to pass it in our track obviously that's all the information we need it needs to have a key which we're going to set to our track uri that's always going to be unique and then we're just going to close this off for now this is our track search results and let's create that component back search result dot js little rfc trick to get that generated and there we go import track search result from track search result make sure this is capital right there and make sure this is spelled correctly there we go we're getting our track searchers all imported so now if we log in here hopefully everything is going to work if we search nothing's going to show up here and that's just because our track search result right now doesn't do anything let's make sure we get our track in here and then what i want to do is just style out this div so the very first thing i'm going to do is just come in here with a simple class name i want to make this a flex container set a little bit of margin around it so that it's spaced out from all the other rows and we're going to align all the items in this to be in the center then inside of this div i want to essentially have an image where the source of that image is going to be equal to our track dot album url that's the url that we got and i want to make sure here that i specify some styles that it never gets too big so our height is going to be 64 pixels and our width is going to be here 64 pixels make sure we put a comma in there and close off our image now if we just search you can see immediately we have our images being rendered which is perfect next thing i want to do is actually render out the title of our song but we can put this inside of another div and we just want to make sure we space it out a little bit so we'll say class name margin on the left is three that's just going to space it out from our album and then we can get a div that has our actual track title the track dot title now if i save you can see it prints out the name of the track and i also want to print out the name of the artist and this is just going to change the text color to be muted that way it's a little bit lighter gray this is the track dot artist now if i save you can see we have the artist down here and we have the track name up here now the final thing that i want to be able to do is whenever i click on one of these tracks i want to play it so first of all inside of some styles here i want to change my cursor to the pointer and this just whenever i hover over one of these rows gives me the icon that says that i can actually click on it and also i want to set up an on click that is going to do something like handle play because we want to play that song and inside that function handle play what we need to do is just do a little bit of code that chooses our track for us so we're going to take in something here called choose track then here we're just going to call choose track with our track that's all that we're going to do and this choose track function is a function we're going to create in a little bit but now whenever we click on one of these it'll call this true's track function for us so we need to create that choose track and figure out how we can actually play our spotify songs so in order to play a song we're actually going to use a library here so let's just make sure that we're in the correct folder we just say ls this is the correct folder so we can just say npmi this is called the react spotify web playback this is a library that's going to do a bunch of the work for us it has a component itself built in that allows us to do really easy playing of songs directly from spotify so once this finishes installing i'm going to create a new component called player.js which is going to house our player just do a quick rfc here and then what we want to make sure we do is in our dashboard we want to render out that player all the way down here at the bottom let's just come in here we can say player and we'll just close that off right now we don't have anything passed to it but that's okay also let's make sure we import that up here so we want to get player we want to get it here from player so now if we go into that player component we can render out that spotify player and this is just a simple component that we can import so we're going to import spotify player and it comes from that react spotify player web playback just like that and this spotify player takes a few different things first of all we need to pass it in our access token which is just called token we need to get an access token that we pass in here just like that so if we go back to our dashboard scroll all the way down we can make sure we pass in our access token just like that then back into our player we need to specify a show save icon this is just going to allow us to save songs to our spotify library and then we specify the uris of the songs that we want to play so we want to pass in the track uri for the track that we want to play and inside of here we're going to check if we have a song to play then we're going to pass it into an array called track uri here otherwise we're going to pass it in empty arrays we don't have any songs to play because this always expects an array to be passed into it now lastly what i want to do is i just want to make sure that if we don't have an access token that'll return null up here because we don't actually want to render a player if we don't have an access token to use with it now if i save i log in we should have a player show up at the bottom as you can see it just loaded in and this is the player that we have now we just need to make sure we pass in our track uri if i go into our dashboard here this is pretty simple our track uri is just going to be equal to whatever song we currently select but right now we don't have any songs being selected so we need to store that in some type of state so let's just create a new state we're going to call this one plane track and set plane track and by now this is just going to be nothing so let's clear it out and make sure here i spell set correctly and then we just want to create a simple function called choose track and this choose track function is going to take a track it's going to set our plane track oops set plane track to our track we also want to make sure we clear out our search term because we don't want our search to be there at all so we're going to clear out our search once we choose a track just like that now this choose track is something we can pass in to our track search results just like this if you remember inside that track search result we're using that choose track here and passing it the track we want to play so then down here we can take our plane track and we can get the uri if it exists so if we have a plane track it's going to get the uri for us so now we can do is just wait here log in type something in for example stream beats and we can click on this it's going to play it but you'll notice it doesn't actually play and that's because we first need to click the play button down here and then it's going to start playing that's a little bit clunky in my opinion so we can actually work around this because this player has a play built into it and you could think we'll just set this to true and it'll work but we actually need to make sure we set this to true after we change our song otherwise it won't actually work we need to make sure it sets to true after we select a song to do this is actually super simple we can just create a really simple state for play and set play set it equal to use state and by default it's going to be set to false and then we can use a simple use effect and all the shoe's effect is going to do is set plate to be equal to true every time that we change our track uri then in order to unset our play to true essentially set it to false when we're done playing all we need to do is use a callback property here this callback takes a function and this function has some state and the state will tell us if we're playing or not so if we're not playing then what we want to do is just set our play to false essentially this state is plane this is going to occur every time the state changes so every time our song changes every time our song finishes starts and so on this callback is going to be called so every time that we're not playing it's going to set our play to false for us and then here we just pass in our play so now we just make sure we import use state and use effect we come over here type in a song like stream beats played it should hopefully play immediately and of course it didn't let's just test that one more time to make sure it wasn't a fluke we'll say play here and it didn't play we'll just try refreshing it log in search for this again and this time it works so it looks like we just need to refresh our page so now the last step is just to display the lyrics of the song right here in the middle section if we go back to our dashboard what we can do is we can say okay here's going to be our search results and if we don't have any search results then we want to display our lyrics so if our search results length is equal to zero then what we want to do is inside of here display a new div which is just going to have some centered text so we'll say text center we also want to make sure we style it in a certain way here so that the white space doesn't actually wrap we can say here three and by this actually mean that it allows the white space to wrap so it allows new lines and so on to be displayed and then in here we're just going to display our lyrics which right now we don't actually have a variable for but we're going to create some state for this this is going to display our lyrics state and if we just scroll up here we can set state for our lyrics in a set lyrics we can just set this to an empty string and then whenever we change songs i want to set our lyrics to be an empty string now all we need to do is a way to get the lyrics and we're going to use our api that we've created for that so let's just minimize some of these hooks here and create another hook and this hook here is going to be for our api to access the lyrics and this is going to happen anytime the song that we're playing changes so anytime our plane chat changes we're going to call this use effect and first we're going to make sure that we have a plane track so if we don't have a plane track we're just going to return otherwise we're going to use axios we're going to make a get request here we want to make it to our localhost 3000 this is actually localhost 3001 and we're just going to create an api called lyrics then we can pass in here some params since we're doing a git request we need to specify params we want to specify the track which is our plane track dot title and we want to specify the artist this is our plane track dot artist just like that and then we can just put our dot then on here with our response and we can set our lyrics to the response which is res.data dot lyrics and now all we need to do is essentially specify the api for this route here so if we just save this and we go back into our server here we need to download a new library to do our lyrics so just cd into our server here and npm i a library called lyrics finder this is a super simple library it takes a track name and an artist and it's going to get your lyrics for you so we can say here const lyrics equals require lyrics finder and then we can just create a new app route app.git slash lyrics and we want to get request response we're just going to make this a simple async function here so it's really easy to work with and we're going to set our lyrics equal to all we need to do is await our lyrics finder pass it in our request dot query dot artist and our request query dot track and this is going to get our lyrics for us and if it doesn't have any lyrics we're just going to print out the string no lyrics found just like that and we can say res.json of our lyrics that's it that's all it's going to take to get our lyrics it's a really super simple straightforward code but to make sure we can access the query person of our query parameters here we need to make sure we have a body parser set up for that so we need to use the url encoded body parser and pass extended to true just like that and this is going to allow us to actually parse the url parameters since this is a get request right here now if we just make sure we import axios inside of our dashboard all the way up here you want to get it from axios give that extra quotation and you can see we can log in with spotify we can search for example stream beats play the song you can see the lyrics are automatically populated if we search for a different song that doesn't have lyrics for example one of the stream beats really new songs for example these don't have lyrics yet you can see right there that is printing out no lyrics before we wrap up this video i also want to show you how to store these variables in an env file so we can just create a new dot env file here inside of our server and we essentially need to store these variables so i'm just going to copy them over we need to store our redirect uri we need to store our client id and our client secret we just use equals here get rid of all the spacing extra punctuation same thing here get these tabbed in the right place that stores them inside of this env file then what we can do is we can just cd into that server folder we can mpmi.env which is just a simple library we can use to access this env folder and inside of here at the very top before everything else we can say const require i'm not even nomicon so we just say require dot env dot config that is going to load in our env variables and here we can just say process dot env dot and then all those variables are created such as redirect uri did the exact same thing right here with our client id and then we want to get our client secret as well client secret just like that let's just copy these down here paste those in place get rid of this console log and that works just as well and that's all it takes to create this spotify inspired clone if you enjoyed this video make sure to check out my other clone related videos linked over here and subscribe to the channel for more videos just like this thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 132,329
Rating: 4.9467998 out of 5
Keywords: webdevsimplified, spotify clone, tabnine, spotify, spotify js, spotify javascript, spotify js clone, spotify javascript clone, spotify auth, spotify reactjs
Id: Xcet6msf3eE
Channel Id: undefined
Length: 58min 17sec (3497 seconds)
Published: Tue Mar 16 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.