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:

If a Spotify user logs out of your SDA or becomes inactive, you will delete any Spotify Content related to that user stored on your servers.

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.