For our latest project we were asked to make an app in Electron. Electron is a pretty amazing framework that allows you to create cross-platform desktop apps in HTML5, CSS3 and Javascript. This gives your app access to the file system and all sorts of fun things that native desktop apps can do. My partner and I opted to create an MP3/Audio playing app. Neither of us had worked with building out audio functionality prior to this so there was much to learn.
Initially we looked into various audio libraries on NPM but ultimately found that most of them are simply wrapping the HTML5 audio API and providing a Flash fallback if the browser doesn’t support HTML5. Since electron packages chromium, our app was guaranteed to have HTML5 Audio support so the libraries didn’t offer much additional functionality. In our experimenting and testing we found that we could create a new audio instance and pass it a file for the source in the format of file://filepath/song.mp3
However, even though Electron has access to the file system, chromium is still unable to access a file in this way. To get around the issue we needed to create a DataUrl and pass it to the audio element for it’s source. We pulled in the NPM DataURL package to convert the file. The function returns a promise with the DataURL once the song is converted:
All we need now is a file path. To give the user a file window and allow them to pick a song we wrote a function in the Main process in our Electron app. It looks something like this:
Dialog is provided by Electron and gives methods for things like showOpenDialog and showSaveDialog for saving files. More info can be found here. The filters array is used to limit the file types that can be passed to the app. For our purposes we limited this to mp3 only but it could be expanded to include other audio file types.
The createSongObject function takes a file path and then creates an object that will be pushed to our playlist array. We used id3js to parse the id3 tags on the file to give us the artist, album, track title and track number. We used mp3-duration to get the duration of the song. Using ES6 promises we pass an empty object and a file path to these helper functions and resolve the promise with the full song object to add to our playlist.
Our playlist object now contains all the information we would need to render it in the playlist as well as the original path to the file on the local computer. Playing a song is just a matter of fetching the DataUrl from the function we wrote earlier by passing it the file-path from the song we want to play. This ensures that we’re only generating and using 1 DataUrl at a time to keep memory usage low.
For our app we used Vue for the rendering framework. Mostly because we hadn’t used it before and wanted to try it out. It worked very well for this project and we both enjoyed working with it. For the sake of simplicity you could just as easily take the song object that is returned and put it into a playlist array. To play the song you would call the convertSong function and then pass the source to the html audio element as it’s source once the data URL is returned.