Dropify is a full-stack music-streaming web application inspired by the Spotify Web Player. It utilizes Ruby on Rails on the backend, a PostgreSQL database, and React.js with a Redux architectural framework on the frontend.
The main feature of Dropify is the ability for users to explore and discover new music. Using a PostgreSQL database with artists
, albums
and songs
tables, linked to an Amazon Web Services (AWS) S3 cloud storage bucket, Dropify maintains a library of music ready for streaming at the touch of a button.
In order for users to be able to search through artists
, albums
, songs
, users
and playlists
, Dropify utilizes the pg_search
gem, and specifically the multi-search
option to query all five Active Record classes in one global search.
By making use of the Postgres pg_trgm
trigram search module, Dropify is able to perform 'fuzzy' search, matching all search results against the measure of similarity between the search query string and each result using trigrams.
PgSearch.multisearch_options = {
:using => {
:tsearch => {
:prefix => true
},
:trigram => {
:threshold => 0.4
}
}
}
In order to keep the code base DRY and the UI consistent, Dropify utilizes several modular React components including a <ContentCard/>
functional component that can render artist
, album
or playlist
information based upon the props given.
const ContentCard = ({ cardType, image, primaryContent, primaryLink, secondaryContent, secondaryLink }) => {
if (cardType === "album") {
secondaryContent = (<p className="secondary"><Link to={ secondaryLink } >{ secondaryContent }</Link></p>)
}
return (
<div className={`content-card ${cardType}`}>
<div className="content-card-image">
<img src={ image } />
</div>
<div className="content-card-content">
<p className="primary"><Link to={ primaryLink }>{ primaryContent }</Link></p>
{ secondaryContent }
</div>
</div>
)
}
Somewhat behind the scenes, Dropify relies on a playQueue
object in the redux state that tracks the currentSong
in play, as well as any queuedSongs
that may be added individually or from albums or playlist.
A sidebar NowPlaying
component displays information about the currentSong
and allows users to control the playQueue
either by directly visiting the Play Queue page or clicking control buttons to shuffle or repeat the songs in the playQueue
. To achieve this, the playQueue
stores information about the shuffledOrder
and unshuffled song order
of the queue.
const _defaultState = {
currentSong: {
song: {},
playing: false,
restart: false
},
queuedSongs: {
songs: {},
order: [],
shuffledOrder: [],
},
shuffled: false,
repeat: false
};
A key feature of Spotify is for users to be able to create, read, update and delete playlists. Dropify implements a playlists
and playlist_songs
association table to store information about the songs user's have added to their playlists.
In order for users to be able to create, update and delete playlists as well as add and remove songs
from playlists, Dropify implements dropdown menus that are conditionally rendered based upon a global modalOpen
variable on the app's Redux state that stores the id of the currently open dropdown menu, if any.
const Dropdown = ({ isOpen, children }) => {
if (!isOpen) return null;
return <div onClick={e => e.stopPropagation() }>{ children }</div>
};
As soon as a user clicks on an option from the dropdown menu, the menu is cleared by dispatching an action to the store. If the user decides not perform an action and clicks off of the menu, the menu is cleared from the global state and no longer rendered.
In order to allow users to be able to follow multiple types of models, such as other users
and playlists
, Dropify utilizes Rails polymorphic associations to implement a follow
class and follows
association table that stores information about the follow type.
class User
has_many :follows, as: :followable
has_many :followers,
through: :follows,
source: :follower
has_many :out_follows,
foreign_key: :follower_id,
class_name: 'Follow'
has_many :followed_users,
through: :out_follows,
source: :followable,
source_type: 'User'
has_many :followed_playlists,
through: :out_follows,
source: :followable,
source_type: 'Playlist'
end
The flexibility of this model allows for any model to be followable, including artists
in the future.
In addition to the features already implemented, I plan to continue work on this project. The next steps for Dropify are outlined below.
Using MP3 ID3 Tags, I have access to genre tags for songs. I plan to utilize genres to setup a radio feature that plays songs from various artists and albums with similar genres. Additionally, I plan to add a genres view to browse to allow users to search through playlists from various genres.
Spotify enables users to save music from the global library into their own personal collection. Users can save songs, artists, albums and playlists into their music. While I have implemented the collection for playlists, I plan to add functionality for songs, artists and albums.
In order to allow users to continue their session from the desktop to their mobile device, I plan to implement a sessions table to track user logins from different device types, allowing them to sign in on two devices. I also plan to implement responsive CSS styles for mobile screen widths.