Skip to content

Latest commit

 

History

History
114 lines (96 loc) · 3.09 KB

presentation.md

File metadata and controls

114 lines (96 loc) · 3.09 KB

##Intro Purpose: add ratings to songs

What API: Spotify

##Live Demo Features:

  • rate songs
  • view saved songs
  • view rated songs (ordered)
  • view top rated songs (ordered)
  • search
  • create playlists (option and show in Spotify app)
  • live updating (demo with multiple users/private channel)

##Features in depth #####Rate songs:

  • Songs fetched via API call w/ JSON
  • Done via channels (public vs private)
let channel = this.socket.channel(`song:${song.id}`);
channel.join();
  • Tested and works well with hundreds of songs. Not sure how it will scale/potential problems in future.

#####Viewing Songs

  • Database stores user_id, song_id
  • Spotify API prevents storing song meta-data
  • Must call API with each song id to get the information
  • Have to load in 50's (so my API mirrors Spotify's offset)
  • Some more complicated queries, (fetching globally top rated 50 songs)
    query = from sr in SongRating,
      group_by: :song_id,
      select: %{song_id: sr.song_id, stars: avg(sr.stars)},
      order_by: [desc: 2], #second col (b/c group_by)
      limit: ^limit,
      offset: ^offset
    Repo.all(query)
  • BENEFIT: results come back sorted
  • Handling loading all songs (send response code with result)

#####Creating playlists

  • 1 API to make the playlist (get back id)
  • Add songs to playlist
  • COMPLICATION: only 100 songs added max by Spotify, but I support many.
  • SOLUTION: chunk song id's by 100, and make multiple API calls

#####Creating reusable React component

  • API call to load songs at construction (via props)
  • Optional props to handle search
  • PROBLEM: API calls/channel messages come to unmounted component
  • SOLUTION: Leverage React life-cycle
    • componentDidMount: make API call and join channels
    • componentWillUnmount: cancel API calls and leave channels
        constructor() {
             ...
            this.CancelToken = axios.CancelToken; //for canceling axios request
            this.source = this.CancelToken.source(); //for canceling axios request
            ...
        }
    
        componentWillUnmount() {
            this.source.cancel();
            this.channels.forEach((channel) => {
                channel.leave(); //leave any previously joined channels
            });
        }
    

#####Handling authentication https://developer.spotify.com/assets/AuthG_AuthoriztionCode.png

#Authorization
defmodule SpotifyratingWeb.AuthorizationController do
  use SpotifyratingWeb, :controller

  def authorize(conn, _params) do
    redirect conn, external: Spotify.Authorization.url
  end
end


#Authentication
defmodule SpotifyratingWeb.AuthenticationController do
  use SpotifyratingWeb, :controller

  def authenticate(conn, params) do
    case Spotify.Authentication.authenticate(conn, params) do
      {:ok, conn } ->
        redirect conn, to: "/top_rated"
      {:error, _reason, conn} -> redirect conn, to: "/error"
    end
  end
end

#####Libraries used Javascript

  • "axios": "^0.18.0",
  • "bootstrap": "^4.1.3",
  • "prop-types": "^15.6.2",
  • "react-router-dom": "^4.3.1",
  • "react-alert": "^4.0.4",

Elixir

  • {:spotify_ex, "~> 2.0.9"}

#Questions?