Shufflizer gets its name from the combination of the terms shuffle and randomize. This has been formally acknowledged now, in a ceremony that was like the one for Sir Bedevere.
Some technical design decisions
Not a Progressive Web App
Shufflizer has no Progressive Web App service workers. There is no off-line scenario. Bad Internet connection? It’s best if you come back later.
No lazy loading
Lazy loading is the idea of incrementally obtaining only the data necessary to render the viewport.
The user is going to reorder the entire playlist. So I need the entire playlist. I don’t lazy load it. This is what Spotify’s native Windows app does when you click on a playlist. I can tell by the way it performs. It loads the whole thing.
I am not downloading songs. The playlist is just the track listing, not the audio itself. Even for a few thousand songs this is not a challenging amount of data for today’s hardware – even a phone.
I do get all of the album art. I did try lazy loading these images but I did not like the results. It made the user experience more sluggish and strange. I prefer the user wait a couple more seconds up front to get a smooth, normal scrolling experience.
No server-side code
Shufflizer is pure Angular/TypeScript. MEAN stack? Nope. It’s just the A.
Having no server-side code makes it easy to comply with this rule in the Spotify Developer Terms of Service:
My only server is my web server, and it is totally stock.
There are some trade-offs for this simplicity. I will talk about them in a future post.
Beenhere listen indicator
Shufflizer knows what songs you have listened to recently. These are indicated with a beenhere icon. Beenhere is a concept from maps, a symbol to indicate places on a map that you have visited. Shufflizer uses it to indicate songs that you have listened to.
Beenhere songs will be put at the end of the playlist the next time you randomize. Sometimes you don’t want this. Maybe you were auditioning a song deciding whether to add it to the playlist and don’t want this to count as a listen.
Beenhere can be cleared
You can clear the beenhere indicator by clicking on it. Now the song is treated as a song that has not yet played.
Adding new songs
You want to hear your playlist randomized. You don’t want to hear recently played songs. So you are using Shufflizer instead of Spotify shuffle play, and you listen to the playlist in its song order.
Adding new songs
In Spotify you find some new songs and add them to the playlist. Spotify always puts them last. You might want to hear some of these songs early in your mix because you are excited about them. If not, then you at least want them randomized into the mix, instead of at the end. So before you resume listening to the playlist, you use Shufflizer again:
- Download playlist from Spotify
- Jump to the end (where the new songs are)
- Clear the beenhere listen indicator on some songs
- Shoot some songs to the top
- Jump to the top
- Change the order of the first few songs
- Shufflize
- Upload playlist to Spotify
Now in Spotify, simply start listening from the top.
Once you are accustomed to doing this, it doesn’t take more than sixty seconds.
Problem with height:calc
I’ve been setting the height of one of my div tags using the calc construct. Here is a simplified example:
<div style="height:calc(100%-230px); overflow:auto"> my div stuff </div>
This keeps my div on the screen and when the div gets big enough (my div stuff is replaced with a ton of stuff) it sprouts its own scrollbar instead of the scrollbar for the whole window appearing.
After upgrading from Angular 5.0 to 5.2, this stopped working. It was as if my specification for height simply was not there. The window scrollbar would appear and my whole app would scroll.
I found a work-around. Specify the percent instead as a vh (viewport height):
<div style="height:calc(100vh-230px); overflow:auto"> my div stuff </div>
When I upgraded Angular, I also obtained the latest flex-layout and angular-material. It could be that this problem is from one of these libraries, instead of Angular 5.2 itself.
Upgrading Angular
When the Google Angular team releases a new version I like to move onto it. I do this by upgrading Angular, starting a new project, and then bringing in the source code from my existing project.
I’ve been doing my Angular development on an Amazon Web Services Ubuntu Linux server. The examples I show here are Linux operating system commands that overwrite files. Please be careful and do not expect that I will be accountable if you try this and anything goes wrong. Consider making a backup of your system before you begin.
[10-May-2018: I don’t have this working yet for Angular 6. I think the problem is that flex-layout is not yet published for Angular 6. Waiting for that.]
Record the old version numbers
As a reference, I issue the ng version command in my existing project and keep a copy of the results in an open text editing window. Here my old existing project is randomizer:
cd ~/randomizer/ ng version
Then I proceed with my upgrade process.
Upgrade Angular and create new project
To upgrade Angular I actually just install it again. Here my new project name is shufflizer:
npm install -g @angular/cli npm install --save @angular/material @angular/cdk npm install @angular/flex-layout --save ng new shufflizer
I do a build of the new project at this point to confirm. It’s the stock starter project. There should be no error messages:
cd ~/shufflizer/ ng build --target=production --base-href '/trashthis/'
Also at this point I can issue the ng version command in the new project and confirm that I am running a new version of Angular. I look to see that the version numbers are mostly higher than the ng version results from my old project. If they are then I figure I must be on the right track:
cd ~/shufflizer/ ng version
Example results:
Angular CLI: 1.7.4 Node: 9.0.0 OS: linux x64 Angular: 5.2.10 ... animations, common, compiler, compiler-cli, core, forms ... http, language-service, platform-browser ... platform-browser-dynamic, router @angular/cdk: 5.2.5 @angular/cli: 1.7.4 @angular/flex-layout: 5.0.0-beta.14 @angular/material: 5.2.5 @angular-devkit/build-optimizer: 0.3.2 @angular-devkit/core: 0.3.2 @angular-devkit/schematics: 0.3.2 @ngtools/json-schema: 1.2.0 @ngtools/webpack: 1.10.2 @schematics/angular: 0.3.2 @schematics/package-update: 0.3.2 typescript: 2.5.3 webpack: 3.11.0
Bring in the source code from my existing project
Again, my old project is randomizer. The new project is shufflizer.
The cp ~- command syntax is the Unix/Linux way to copy a file from the previous directory into the current directory. The cp -r gets subdirectories and their contents too:
cd ~/randomizer/src/ cd ~/shufflizer/src/ cp ~-/index.html . cp ~-/styles.css . cd ~/shufflizer/src/app/ cp -r ~/randomizer/src/app/* .
Now I can build the new project. It’s a new version of the project that I have been working on. It builds totally clean, with the latest version of Angular.
My Spotify app
I am creating a Spotify app using Angular. I aim to provide an alternative to Spotify’s shuffle play.
Spotify shuffle play
Spotify does not document for us the internals of their shuffle play mechanism, but it seems to construct a new random selection from your playlist whenever you return to the playlist after listening to something else. I call this resampling. The problem with resampling is that a song that you have recently heard might play again while there are other songs in your playlist that have not yet played once.
Use my shuffle instead
My solution is to provide an external utility that shuffles the playlist itself, rather than just making random selections from it for the play queue. Then the user can turn off Spotify’s shuffle and listen to the randomized playlist in its new order. The effect is much like Spotify’s shuffle play but each song plays just once.
Until you start from the top again.
Or give up and simply go back to using Spotify’s shuffle play.
Because you got lost.
When you return to a big playlist it’s practically impossible find where you left off, assuming you even remember.
Use my shuffle again
So there is a bit more to my solution. My shuffle knows what you have listened to and puts these songs at the end.
Returning to your big playlist? Use my utility to shuffle it again. Then in Spotify simply start listening from the top. The songs will be in random order. You will not hear recently played songs. You don’t have to find where you left off.
Still under development
My shuffle utility is my project for learning Angular. So I am taking my time with it. But it’s pretty far along now, so I expect to make a version of it available soon. I will continue to talk about it – a few more features it has, and also some of the challenges behind the scenes both with Angular and with the Spotify API – in future blog posts.
Why Angular
Please understand that these are the reasons I decided to learn Angular. I am not saying that this is why you should choose Angular.
It’s free
I’ve marveled over the years at the quality of free software, whether from Google or open source. It seems like it’s more reliable sometimes than software enterprises pay for.
It’s for web-based development
I like the reach of the web. I liked Angular’s pitch that it is what HTML would have been, had it been designed for building web-apps. I also liked that AngularJS models are plain old JavaScript objects. This makes your code easy to test, maintain, reuse…. This prose is from the old AngularJS, however, and so not entirely true for the new Angular, the Angular that I am learning. The big difference is TypeScript. Yes the models are JavaScript objects, but they are in TypeScript which IMHO disqualifies them for the adjectives plain and old. It is technically possible to use the new Angular with JavaScript instead of TypeScript, but I didn’t want to put myself outside of normal Angular conventions. People who work in Angular work in TypeScript.
It claims to facilitate creating software that is readily testable
Effective testing is critical for mature production quality systems. By effective I mean testing that really does prevent problems from getting introduced, but at the same time does not hinder creativity and productivity.
My impression is that it is more complete
This means Angular programmers will have more in common with each other, something good for everyone involved with Angular. This is the classic debate of composite of best-of-breeds verses integrated solution. There isn’t a universally right and wrong side of this debate. I just decided if I was going to learn something new, and so new that I would not just be learning it, but learning from it, I would let Google guide me in what is cool. Maybe this sounds a little strange. I am just being honest here.
It claims to be for all devices (phones, tablets, pc’s)
I am still learning about this. All I can say is it sure did sound nice when I was deciding to go for Angular.
What about React, Vue, Ember, and Meteor?
These competitors all sound worthy. I just wanted to pick one and dive deeper than I could if I tried them all.