posytif is a semi-functional web-based Music Player interface using HTML5 and JavaScript technologies.
In a nutshell, it's an AngularJS application in front of Firebase and Spotify Web API.
make sure npm is installed on your system. then:
npm install
bower install
this will install the dependencies. then, you can start a server with:
grunt serve
visit localhost:9000
to use the app.
to build the distribution version run:
grunt build
the app will be in the dist/
folder.
that's understandable. just grab the pre-built app here, and put it on some server that can serve static files.
Semi-detailed documentation lives below, in the README. However, the distribution folder contains detailed documentation generated with docco
. To generate this documentation, run grunt build
.
The generated files will be inside the dist/docs
folder.
In the root directory, the following files are present:
package.json
: definition of the npm module of this application, and development dependenciesbower.json
: declares client-side dependenciesGruntfile.js
: build file
This folder is the home to the application's source files. Also index.html
, the "entry point" of the app lives here.
All the JavaScript code resides here. The code is organized into folders according to its nature; controllers live in controllers
, directives live in directives
etc.
All our views are here. Views are AngularJS views. Also, templates used in directives are found here, under app/views/templates
CSS files are found here. Like in views
, styles used by directives are found here under app/styles/templates
Managed client-side libraries are stored here.
Managed npm modules are stored here.
many, many unit tests live here.
The distributable build of the application can be found here. Generated using grunt build
.
posytif is an AngularJS Single-Page Application. Pages and fragments are organized into views, who are controlled by controllers, who use services to store data, authenticate, or maintain playback state.
posytif uses Firebase via angularfire to store playlist data. Firebase and angularfire are really easy to use and integrate, and that was the primary reason they were selected. Three-way data binding is sweet.
Authentication, too, is provided by Firebase. Facebook, Twitter and Google log-ins via OAuth2 are available.
Authorization is handled by Firebase. A mis-configuration or non-configuration is a security issue. It should be configured, using Firebase console, to grant permission only to owners of playlists, for playlist operations.
The great Spotify Web API is used. To limit the volume of queries made to Spotify, the built-in cache of $http service is used.
No audio playback is implemented. That's because I don't know of any APIs to stream music.
This is the application module. Lists the dependencies and configures the routes used in the application by mapping URL fragments to views and controllers.
The dependencies at the time of writing were:
firebase
: to handle communications with firebasengRoute
: to have routing capabilities required to build a SPAui.bootstrap
: to have directives such astabset
available in templatesngAnimate
: to have angular animation support
This module is defined in app/scripts/app.js
.
This is the main controller of the application. All the other controllers are nested inside this one. This way, common controller behaviour can be shared; such as queuing songs, adding to playlist or responding to login status changes.
This module is defined in app/scripts/controllers/main.js
.
This controller is responsible of the left navigation menu, that contains the list of playlists.
This module is defined in app/scripts/controllers/navigation.js
.
This controller controls the album page.
This module is defined in app/scripts/controllers/album.js
.
This controller is responsible for the behaviour of the Album Art section. It holds a reference to the current playing song, allowing display of Title, Artist and Album Art. If no song is currently playing, it helpfully displays a picture of a kitten (via placekitten.com).
This module is defined in app/scripts/controllers/albumArt.js
.
This controller controls the artist page.
This module is defined in app/scripts/controllers/artist.js
.
This funny named controller defines the behaviour of the playback controls.
This module is defined in app/scripts/controllers/controls.js
.
This controller controls the playlist page.
This module is defined in app/scripts/controllers/playlist.js
.
This controller controls the queue view..
This module is defined in app/scripts/controllers/queue.js
.
This controller controls the search page.
This module is defined in app/scripts/controllers/search.js
.
This controller defines the authorization behaviour.
This module is defined in app/scripts/controllers/user.js
.
This service uses Firebase to authorize users via OAuth2 providers such as Facebook, Twitter and Google. All its methods return promises (provided by the $q
dependency) to handle the asynchronous operations.
It exposes the following methods:
- thirdPartyLogin
- passwordLogin
- createUserAndLogin
- logout
- getUser
- checkPersistentLoginState
- onLoginStatus
This module is defined in app/scripts/services/auth.js
.
This service maintains the playback status, such as the current song or position. As no audio playback actually occurs, playback is merely simulated, using $interval
service. This service heavily uses the QueueService
.
It exposes the following methods:
- getCurrent
- play
- pause
- stop
- next
- previous
- getPosition
- getState
This module is defined in app/scripts/services/player.js
.
This service uses Firebase to store playlist data. Thanks to angularfire's $asObject
and $asArray
methods, the references returned by this service can be used in three-way data bindings. So, for example, a data change on the firebase console can trigger a view update in a client.
It exposes the following methods:
- getPlaylistsOfUser
- addTrackToPlaylist
- removeTrackFromPlaylist
- deletePlaylist
This module is defined in app/scripts/services/playlist.js
.
This service maintains a playback queue to be mainly consumed by PlayerService
. It keeps track of two lists as priority queues, so that the "normal" playback sequence can have "priority" songs inserted in between. The behaviour is very similar, if not identical, to that of Spotify Desktop Client.
It exposes the following methods:
- enqueue
- setQueue
- getNext
- getPrevious
- empty
- getUpcoming
This module is defined in app/scripts/services/queue.js
.
This service makes HTTP calls to Spotify Web API, using $http
service. All the calls are cached using the native caching capabilities of the $http
service. This effectively eliminates duplicate HTTP requests. As the responses practically never change (in the lifetime of the application, at least), this is a very suitable caching policy.
It exposes the following functions:
- search
- getTopTracks
- getArtist
- getAlbum
- getAlbumsOfArtist
- getTracksOfAlbum
This module is defined in app/scripts/services/spotify.js
.
This module defines 3 constants used throughout the application to represent playback states:
- PLAYING
- PAUSED
- STOPPED
This module is defined in app/scripts/constants/playerStates.js
.
pstTrack, or pst-track
defines an element that represents a track. It displays the title, names of artists, name of the album and the duration. In addition to these, it provides the user with the following actions where appropriate:
- add to playlist (if logged in)
- play now
- queue (play next)
- remove from playlist (if in current playlist)
This module is defined in app/scripts/directives/track.js
.
This directive allows us to show a confirmation dialog before taking an action, such as deleting a playlist. It also uses the sweetalert
library to show beautiful modal dialogs.
This module is defined in app/scripts/directives/confirmClick.js
.
This directive temporarily adds a CSS class to an element, whenever the value of an expression changes. This is used to provide visual feedback to the user when she adds a track to a playlist, by momentarily highlighting that playlist in the navigation bar.
This module is defined in app/scripts/directives/highlightOnChange.js
.
This filter takes a list of artists and returns their names joined with commas. This comes in handy, because all tracks returned from Spotify have an array for the artists
property, even if there's a single artist.
This module is defined in app/scripts/filters/joinArtistNames.js
.
This filter calculates the total length of a set of tracks. It merely sums the duration_ms
field of Spotify track objects. Comes in handy in the playlist page.
This module is defined in app/scripts/filters/totalLength.js
.
This filter counts the number of tracks in a playlist. Normally, this filter should have been unnecessary, but the way the playlist data is stored in Firebase prevents us to have an array of track objects in a playlist.
This module is defined in app/scripts/filters/trackCount.js
.
The album page shows the album art and the track listing of the album.
This view is defined in app/views/album.html
.
The album art view shows the album art of the current playing track, along with the title and artist information on top of it.
This view is defined in app/views/album-art.html
.
The artist page shows top tracks and albums of an artist.
This view is defined in app/views/artist.html
.
This view consists of playback control buttons, and a slider to represent the current position of the song.
This view is defined in app/views/controls.html
.
This view defines the left navigation bar. The bar shows the list of playlists of the user, and an input field to allow the user to create new playlists. It expands with the number of playlists, and eventually scrolls inside itself. It also expands and gets fixed
on scroll down.
This view is defined in app/views/navigation.html
.
This view shows the track listing of a playlist. It also exposes the following actions to the user:
- Play playlist
- Rename playlist
- Delete playist
This view is defined in app/views/playlist.html
.
This view shows the upcoming tracks. At most 6 lines are shown, so up to 6 tracks will be displayed. For 7 and more tracks, 5 tracks will be displayed along with a line indicating the number of tracks not displayed.
This view is defined in app/views/queue.html
.
This view, is the main view of the application. It consists of a search bar and search results. The search results are shown in 3 tabs: Tracks, Albums and Artists.
This view is defined in app/views/search.html
.
This view shows login buttons ot user information depending on the login state.
This view is defined in app/views/user.html
.