Skip to content

Making a music player app using only JavaScript and jQuery

A few months ago… I started out a quest to make a streaming radio app using only JavaScript and jQuery. After many late nights of hunting for semicolons and debugging I succeeded to bring that vision to life. Some might argue this was not the best way to accomplish this task (and that’s probably true), but I felt it was a great learning experience for myself to take on a task like this within the limitations of one language, one library and the browser. Colleagues argued that using a framework like React or Angular would be a better way to go. I felt that for such a simple app there was no need to take on the additional memory load of a large framework, or to complicate things with a database when in reality the app only needs to save each individual users favorite stations and visual theme preferences. The end result is a tiny app that weighs in under 7 MB streams a few hundred stations, saves your favorites, shuffles and advances, and has several colorful visual themes to choose from. It remembers your last station, theme choice and favorites using local storage. I even ported it to Android when it was done.

It was truly a challenge, and I learned a lot, so I’d like to share some of that journey with you. So let’s think about the problem. We need to play music, store a list of stations, have a way to advance through the stations, save your favorites, and have several views for menus. Sounds like a lot, but like any algorithm if you break it into small pieces it’s MUCH easier.

I started with some planning, I thought – I’ll have a player object that holds what’s currently playing and make some nice reusable methods that just assign the station to play, and manipulate the player. One array will hold all of the stations, another will hold the favorite stations, another for the colorful themes. Something like that. How hard could this be?

Then I got started. 

The first step was – get some audio playing. I searched out and reviewed internet stations and collected their URLs and Information. Great so I’ve got my music, how do I play it? Well, in JavaScript all you have to do is create an audio object, and then call the .play() method. Awesome. This was going to be a piece of cake. I started with a simple HTML document with just a single button and got the music playing.

javascript code

So I started with an audio object and a single button, and made a click function that calls .play() on the audio object.

THE MUSIC IS PLAYING!

OK, cool. I guess I’m done I can go home. but… not really. There was lots more to do. I still need to store all the stations and all the other stuff. So the next step was to make the ‘player’ object that holds the current station, a variable for whether it’s paused or not, stuff like that.
So that ended up looking like this[below] Initially I set the player to the first station in the array with musicarray[0][0] In my array the first bracketed number represents the genre number, the second represents the station. So this gives us a place to put the entire music station object, along with a number for the genre, and station so that we can advance through the stations easier later on.

javascript code

Pretty easy to follow?

Now you remember that I said I was going to use an array to hold all the station info? I ended up making a two dimensional array. Genres first, then stations inside each of those genre array elements. The classic player interface has buttons 1 through 6 to play each of the 6 stations from each genre, so I put 6 stations in each genre, and made a great big two dimensional array. Each genre is its own array inside the musicarray, and each genre contains 6 station objects that look like this. We’ve got a info about the station, a URL, a genre name, the genre number, and the station number. These are all here so that they can be assigned to the player object, so that we’ll know exactly where each station we’re playing is inside this array, all the time.

So this array goes on for about… 1,300 lines of JavaScript. phew, my fingers were so tired. I obviously could have used an API from some major music provider or something like that to load all of the station information, but for this case I wanted to code it all on my own as a challenge. I also wanted to hand-select the stations that I liked the best so I wouldn’t end up with a bunch of terrible stations. It took a great deal of time, but it was worth it.

OK So we’ve got a player object, and we’ve got our stations, but how do we play the music, and change the station?

We’re going to be changing the station a lot, so it’s probably a good idea to make an easily reusable method for that. Let’s call it setStation() and we’re going to need to start and stop the music, so let’s make another method called playMusic()

JavaScript-A-mundo

OK so first you can see we check to see if there is a station object inside the player, if there isn’t – set it to the first station in the music array using the setStation method. – This helps to avoid bugs that would occur if for some reason the playMusic() method gets called and there’s no station to play (just in case). We set the audio object (currentAudio.src) source property to the URL from inside the player station object. Player.station.url returns the URL that we need because we’ve already assigned player.station to be the music station that we want before calling playMusic() Next we set player.paused to false, then there are two lines that switch css classes to start an animation, and finally… We call currentAudio.play()   – and..

THE MUSIC PLAYS.

Now we’ve gotta work out how to change the stations. OK so we setup the setStation() method to accept a parameter which will be the new station. So we call this method and pass in a radio station object from the musicarray and it assigns the station to the player.station property so that when we call the play music method it will use that stations url for the currentAudio.src and we will hear the new station. I grab the values for the genre number and station number and set them to the player object so they can be used to iterate through the stations . I also print the station information to the document using the jQuery .text() method so the user can see which station is playing. You can see the storeIt() method used here which I will explain later, just know that all it does is store the last used station so that it can be reloaded when you reopen the app.

you guessed it, more javascript

Here’s a function that starts and stops the music, and a few click functions. I won’t bore you with ALL of the click functions though. that’s pretty easy to understand. These ones here go to numbered buttons on the app 1 through 6 that play stations 1 through 6 from whichever your current genre is.

OK so we need a ‘next’ button to advance to the next station. Here’s what that looks like. if you’re already on the 6th [last] station in the genre, it sets you back to the first station [0] We console.log the new station for testing purposes.

See how we use the player.genreNumber to target the current genre in the musicarray? 

javascript-amundo

Now we follow a similar structure to advance through genres. If you’ve reached the last genre, it sets it to the first [0]

javascript

Advancing through stations is great, but having a random station button seems like a great idea too.
See how handy it is to have those setStation and playMusic methods? No need to repeat ourselves in the code.

Seems like a good idea to be able to scan through our favorite stations, so I’ve added that in here. I had to handle the case in which you didn’t have any favorites saved yet, so I just call randomPlay() instead of having it do nothing at all.

Now we’ve got some good functionality going here, but we haven’t gotten into any of the visual stuff yet. Let’s start with…

How are we going to change the theme / look of this app anyway?

So here’s a shot of the head of the HTML document.

Do you notice anything funny here [besides the comments?] Take a look at line 17.

html head

I’ve created an empty link tag here for a stylesheet and given it an ID of theme-switcher.

I also placed this tag AFTER all of the other stylesheets. but why?  Well, we need to be able to override any CSS rules to create a new theme/look for the app.

 

There’s quite a bit going on here, You can see I created a way to save the names of the stylesheets in local storage and call them back and set them. This means the app will remember what theme you choose and reload it. Let’s look at line 269 and 280. Those are going to grab values from the html document that correspond with the stylesheet names of each theme and on lines 271, and 282 we use the jQuery attr() method to change that empty tag in the html head so that it now points to our theme and overrides the other CSS rules. We then use local storage to store the name of the theme so that it will be reloaded when the app opens up again, and finally, we run showPlayer(), which will show the appropriate divs for the main screen of the player. You can see there’s also a value here for the player style of classic or modern, which just helps the showPlayer function to know which divs to show or hide when it’s called.

Let’s talk about the rest of the views. Now…

This is a single page application that doesn’t use react or redux, or angular or vue, or any other magical voodoo to control the components…

So how are we going to hide and show the parts of the app that we need when we need to?

jQuery!  So first we start off by just hiding all the things that aren’t the main player, then we define a function that hides everything, and finally we define a function that shows the player based and takes into account our player style so that it will show either the classic look [section] or the modern look [robotview] I know the naming could be better here, I should refactor that. Anyhow just know that the classic view looks like a car stereo, and the modern look has little random robots and big buttons and is easier to use. You can see also I add the social icons on the bottom.

Now we can’t stop there, because there’s a whole lot more views to create and control for the app. We have an about view, a genre list, a stations list, a favorites list… We need functions to control all that. See how I use the hideAllViews function here to hide everything else and then only show the div that we want to see? When we’re done with the view, we just call showPlayer() again and the player comes back because we’ve already defined a function for that.

You can see I made a few toggle buttons here.

When we’re done with all that we need some click functions that correspond to those view methods so that we can actually call up those methods from inside our app.

All of our views have this navigation-buttons div inside of them, and that gives us the ability to navigate through the app. 

Now… We haven’t gotten much into the HTML yet, so let’s think about this. We need lists for the stations and genres, and we need to populate them from the musicarray variable [that huge two dimensional array] but…

How can we possibly do that with JavaScript? It’s not a templating language like PHP. We certainly can’t hard-code the values for each station and genre every-time that we add one to the app, so how would we handle that?

Well I’m going to show you what the answer looks like. We’re going to start with the favorites list, because that’s the most complicated. Here goes:

So this will take an empty div with the id of ‘favorites’ in the html document and populate it with an H3 element for each favorite station. It iterates through the array and creates the html string for each H3 in the list, but… As it does so, do you notice that it’s doing something else? It’s also including the iterator variable into the html as a data-favorite value. And there’s a trashcan icon with a data attribute value equal to the iterator also. but why?
Well, when the user clicks on these later, we have to know which index in the array that station is so that we can set it, and play it. And we also have to know which index in the array it is if they click the trash can to delete it. 

So let’s take a look at the HTML that the makeFavorites() method generates in the app.

Our previously empty #favorites div has become THIS when the makeFavorites method is called! We’ve got a span that you can click with the name of the station, which will be used to play the station, and also a trash-can which will be used to delete the station. These each have a data attribute that corresponds to it’s index in the favorites array so that it can be played, or deleted with a single click function for either operation.

But… wait… How would that even work?  Well, we have to pass the event to the click method to access those data attributes. 

Now, this one has to be wrapped in a document.ready because… when the document first loads the makeFavorites method hasn’t finished running yet, and therefore the #favorites div is still empty. So we run this after the document becomes ready so that these clicks can bind to the elements, because they weren’t there when the page initially loads.

We’ve got our fav-triggers [from above] with the data attributes, and we’re clicking them, the event gets passed into the method, then the method makes a newStation variable that accesses the data attribute, setStation is called, and the newStation is passed in from the favorites array. We call showPlayer [which makes the favorites list go away, and the player appear] and finally…
We play the music!  

Now we’re really getting somewhere with this app!  This is as complicated as the whole thing gets, I PROMISE…  and if you ask me, it’s pretty easy to follow, but I guess some would disagree. Any complicated app will have some form of dynamically generated content with a loop, a way to store things, get them back and view them. We’ve done all that here, without a database, using only the browser, JavaScript, jQuery and local storage.

I follow this same pattern for the genre list, and stations list [but without the trashcans. With the genre list you can see we grab the genre data attribute and then set it to the first station in the genre [0] line 529
For the stations list we need both genre, and station. Take a look at the nested loop that starts on 537. I loop through the genres, and also loop through each station, using iterators for each, I then use those iterator variables to output in the HTML which genre, and which station is being printer out along with it’s name: musicarray[i][j].info

By now you’re probably having some lightbulb moments [hopefully] about how you could use JavaScript dynamically like this in your own apps. Or maybe you’re thinking to yourself ‘Why on earth would anyone build an app this way?” and that’s a very valid objection and conclusion to reach from looking at this. There are great frameworks out there that are designed specifically to create reusable components and single-page applications, so you should probably use those, but if you want a tiny simple app that isn’t bogged down by loading a framework, you can definitely do it this way.

What I’ve managed to achieve with this bit of code is –  You can add more stations and you’ll never have to rewrite any of the functions to handle it. Just add a new genre, with 6 stations to the musicarray, and the code takes care of the rest!

Here’s what the completed lists look like inside the app:

 

Odds and ends:

OK so let’s go through this quick. Local storage stores everything as a string, So you can’t just save an array ‘as is’ and pass it into local storage and have it ‘just work’.  So… the storeIt() and retreiveIt() methods here take that JSON object and turn it into a string before it’s stored, and then decode it back from a string into an array when you retrieve it. This was crucial for saving the ‘favorites‘ array of stations that we modify with the app. You can see that we have an add-fav button where we simple push the current station into the favorites array, store it, and then reload the app so that if can rewrite the favorites list, and the new favorite station appears. We have another button for this on the modern theme so that method is repeated with robot-add-fav.

There’s a button for removing all favorites which calls the #clear.click function.  On line 596 we just set the savedStations to an empty array, but on line 597 something truly magical happens – we successfully retrieve the users favorite stations out of local storage in their browser so they can play all of their favorite stations. We assign it to the favorites variable, and then run makeFavorites which writes all the HTML for the favorites list.

Now there’s really just a couple things left. We need to make that delete function that removes the favorites with the trashcan. I used the .splice() method to take care of that. The first parameter is the index of the array element to delete, and the second parameter is the amount of elements to delete [1] Then we storeIt [which turns the JSON into a string and pushes it into local storage. And then we reload to reload the changes and remake the list.

OK now for the most fun part of this whole example…

 

What app would be complete without random robot images?

How do we get random robot images into our app? Well I found a great site online called robohash that provides random robot images based on whatever hash or alphanumeric characters that you pass in.

So… First I made a string of characters, then, I split it into an array and then randomly choose 24 characters to add into a URL to get a robot image using the loop on line 643. See how we select a character and then use += to add it to the slug? Once we have all 24, we add the beginning of the url [line 647] and specify the size for our image.

I created an IMG tag with #robot-image as it’s ID to hold our little robot image and now we’re just going to change the src url out and animate that robot with a flip [courtesy of animate.css library] We do so by removing the previous class ‘flip’ and then adding it back after a short settimeout which allows time for the robot image to load, and of course using the .attr() method from jquery to change the src attribute to the new robot image.

 

I hope this has been a fun adventure into JavaScript and that maybe you learned something about what to do, or what not to do in your JavaScript jQuery app. 

The RoboRadio app is available for Android from the google play store. Download it HERE.