GithubHelp home page GithubHelp logo

rspotify's Introduction

RSpotify

Gem Version Build Status

This is a ruby wrapper for the Spotify Web API.

Features

Installation

Add this line to your application's Gemfile:

gem 'rspotify'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rspotify

Usage

RSpotify was designed with usability as its primary goal, so that you can forget the API and intuitively interact with your playlists, favorite artists, users and so on.

You can write things like my_playlist.tracks.sort_by(&:popularity).last.album without having to think which API calls must be done. RSpotify fills the gaps for you.

Below are some basic usage examples. Check the documentation for the complete reference.

require 'rspotify'

artists = RSpotify::Artist.search('Arctic Monkeys')

arctic_monkeys = artists.first
arctic_monkeys.popularity      #=> 74
arctic_monkeys.genres          #=> ["Alternative Pop/Rock", "Indie", ...]
arctic_monkeys.top_tracks(:US) #=> (Track array)

albums = arctic_monkeys.albums
albums.first.name #=> "AM"

am = albums.first
am.release_date      #=> "2013-09-10"
am.images            #=> (Image array)
am.available_markets #=> ["AR", "BO", "BR", ...]

tracks = am.tracks
tracks.first.name #=> "Do I Wanna Know?"

do_i_wanna_know = tracks.first
do_i_wanna_know.duration_ms  #=> 272386
do_i_wanna_know.track_number #=> 1
do_i_wanna_know.preview_url  #=> "https://p.scdn.co/mp3-preview/<id>"

playlists = RSpotify::Playlist.search('Indie')
playlists.first.name #=> "The Indie Mix"

# You can search within other types too
albums = RSpotify::Album.search('The Wall')
tracks = RSpotify::Track.search('Thriller')

Find by id:

arctic_monkeys = RSpotify::Artist.find('7Ln80lUS6He07XvHI8qqHH')
arctic_monkeys.related_artists #=> (Artist array)

am = RSpotify::Album.find('41vPD50kQ7JeamkxQW7Vuy')
am.album_type #=> "single"

do_i_wanna_know = RSpotify::Track.find('2UzMpPKPhbcC8RbsmuURAZ')
do_i_wanna_know.album #=> (Album object)

me = RSpotify::User.find('guilhermesad')
me.uri #=> "spotify:user:guilhermesad"

# Or find several objects at once:

ids = %w(2UzMpPKPhbcC8RbsmuURAZ 7Jzsc04YpkRwB1zeyM39wE)

my_tracks = RSpotify::Track.find(ids)
my_tracks.size #=> 2

Some data require authentication to be accessed, such as playlists' details. You can easily get your credentials here.

Then just copy and paste them like so:

RSpotify.authenticate("<your_client_id>", "<your_client_secret>")

# Now you can access playlists in detail, browse featured content and more

me = RSpotify::User.find('guilhermesad')
me.playlists #=> (Playlist array)

# Find by id
playlist = RSpotify::Playlist.find('guilhermesad', '1Xi8mgiuHHPLQYOw2Q16xv')
playlist.name               #=> "d33p"
playlist.description        #=> "d33p h0uz"
playlist.followers['total'] #=> 1
playlist.tracks             #=> (Track array)

# Search by category
party = RSpotify::Category.find('party')
party.playlists #=> (Playlist array)
categories = RSpotify::Category.list # See all available categories

# Access featured content from Spotify's Browse tab
featured_playlists = RSpotify::Playlist.browse_featured(country: 'US')
new_releases = RSpotify::Album.new_releases(country: 'ES')

# Access tracks' audio features
sorry = RSpotify::Track.search("Sorry").first
sorry.audio_features.danceability #=> 0.605
sorry.audio_features.energy #=> 0.768
sorry.audio_features.tempo #=> 100.209

# Get recommendations
recommendations = RSpotify::Recommendations.generate(seed_genres: ['blues', 'country'])
recommendations = RSpotify::Recommendations.generate(seed_tracks: my_fav_tracks.map(&:id))
recommendations = RSpotify::Recommendations.generate(seed_artists: my_fav_artists.map(&:id))
recommendations.tracks #=> (Track array)

Rails + OAuth

You might want your application to access a user's Spotify account.

For instance, suppose you want your app to create playlists for the user based on their taste, or to add a feature that syncs user's playlists with some external app.

If so, add the following to your application (Remember to get your credentials)

# config/application.rb

RSpotify::authenticate("<your_client_id>", "<your_client_secret>")
# config/initializers/omniauth.rb

require 'rspotify/oauth'

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :spotify, "<your_client_id>", "<your_client_secret>", scope: 'user-read-email playlist-modify-public user-library-read user-library-modify'
end

OmniAuth.config.allowed_request_methods = [:post, :get]

You should replace the scope values for the ones your own app will require from the user. You can see the list of available scopes in here.

Next, make a link so the user can log in with his Spotify account:

<%= link_to 'Sign in with Spotify', '/auth/spotify', method: :post %>

And create a route to receive the callback:

# config/routes.rb

get '/auth/spotify/callback', to: 'users#spotify'

Remember you need to tell Spotify this address is white-listed. You can do this by adding it to the Redirect URIs list in your application page. An example of Redirect URI would be http://localhost:3000/auth/spotify/callback.

Finally, create a new RSpotify User with the response received:

class UsersController < ApplicationController
  def spotify
    spotify_user = RSpotify::User.new(request.env['omniauth.auth'])
    # Now you can access user's private data, create playlists and much more

    # Access private data
    spotify_user.country #=> "US"
    spotify_user.email   #=> "[email protected]"

    # Create playlist in user's Spotify account
    playlist = spotify_user.create_playlist!('my-awesome-playlist')

    # Add tracks to a playlist in user's Spotify account
    tracks = RSpotify::Track.search('Know')
    playlist.add_tracks!(tracks)
    playlist.tracks.first.name #=> "Somebody That I Used To Know"

    # Access and modify user's music library
    spotify_user.save_tracks!(tracks)
    spotify_user.saved_tracks.size #=> 20
    spotify_user.remove_tracks!(tracks)

    albums = RSpotify::Album.search('launeddas')
    spotify_user.save_albums!(albums)
    spotify_user.saved_albums.size #=> 10
    spotify_user.remove_albums!(albums)

    # Use Spotify Follow features
    spotify_user.follow(playlist)
    spotify_user.follows?(artists)
    spotify_user.unfollow(users)

    # Get user's top played artists and tracks
    spotify_user.top_artists #=> (Artist array)
    spotify_user.top_tracks(time_range: 'short_term') #=> (Track array)

    # Check doc for more
  end
end

Refreshing the access token

The user's access token is automatically refreshed by RSpotify when needed. This is especially useful if you persist the user data on a database. This way, the user only need log in to Spotify once during the use of the application.

Additionally, you can store a proc that is invoked when a new access token is generated. This give you the opportunity to persist the new access token for future use. The proc will be invoked with two arguments: the new access token and the lifetime of the token in seconds. For example, if lifetime value returned from Spotify is 3600, you know that the token will be good for one hour.

In the sample code below, the credentials have been retrieved from some persistent store such as AWS SecretsManager.

callback_proc = Proc.new { |new_access_token, token_lifetime |
   now = Time.now.utc.to_i  # seconds since 1/1/1970, midnight UTC
   deadline = now+token_lifetime
   #puts("new access token will expire at #{Time.at(deadline).utc.to_s}")
   self.save_new_access_token(new_access_token)
 }

spotify_user = RSpotify::User.new(
  {
    'credentials' => {
       "token" => self.credentials["access_token"],
       "refresh_token" => self.credentials["refresh_token"],
       "access_refresh_callback" => callback_proc
    } ,
    'id' => self.credentials["user_id"]
  })

RSpotify provides a way to facilitate persistence:

hash = spotify_user.to_hash
# hash containing all user attributes, including access tokens

# Use the hash to persist the data the way you prefer...

# Then recover the Spotify user whenever you like
spotify_user = RSpotify::User.new(hash)
spotify_user.create_playlist!('my_awesome_playlist') # automatically refreshes token

Getting raw response

To get the raw response from Spotify API requests, just toggle the raw_response variable:

RSpotify.raw_response = true
RSpotify::Artist.search('Cher') #=> (String with raw json response)

Notes

If you'd like to use OAuth outside rails, have a look here for the requests that need to be made. You should be able to pass the response to RSpotify::User.new just as well, and from there easily create playlists and more for your user.

Contributing

  1. Fork it ( https://github.com/guilhermesad/rspotify/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Test your changes (bundle exec rspec)
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request

rspotify's People

Contributors

alexquintino avatar bolandrm avatar cameronstanley avatar carlosefonseca avatar chriswren avatar d4rky-pl avatar godoy avatar guilhermesad avatar ivancevich avatar jcmorrow avatar juanmanuelramallo avatar katpadi avatar krausefx avatar mitchellhenke avatar oliverprater avatar patrickcook avatar patrickmryan avatar philnash avatar pooza avatar ppicazo avatar rickpern avatar scottopell avatar shaicoleman avatar shanecav84 avatar sophiedeziel avatar stephendolan avatar suzannehamilton avatar thomascarli avatar trevors avatar victorpre avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rspotify's Issues

Rails app requests become unauthorised

I'm finding that I need to keep restarting my Rails app by touching tmp/restart.txt.

Otherwise all requests start off ok, but after a while the response is:

RestClient::Unauthorized (401 Unauthorized)

Getting unauthorized error from api.

I wanted to extract a bunch of playlist information since my api search comes up with a lot of results.

RestClient::Unauthorized: 401 Unauthorized
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in `return!'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/request.rb:495:in `process_result'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/request.rb:421:in `block in transmit'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/request.rb:413:in `transmit'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/request.rb:176:in `execute'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient/request.rb:41:in `execute'
/usr/local/bundle/gems/rest-client-1.8.0/lib/restclient.rb:65:in `get'
/usr/local/bundle/gems/rspotify-1.16.0/lib/rspotify/connection.rb:66:in `rescue in send_request'
/usr/local/bundle/gems/rspotify-1.16.0/lib/rspotify/connection.rb:61:in `send_request'
/usr/local/bundle/gems/rspotify-1.16.0/lib/rspotify/connection.rb:36:in `block (2 levels) in singleton class'
/usr/local/bundle/gems/rspotify-1.16.0/lib/rspotify/connection.rb:48:in `resolve_auth_request'
/usr/local/bundle/gems/rspotify-1.16.0/lib/rspotify/playlist.rb:236:in `tracks'

When I restart the script it continues working fine, so I don't think spotify is rate limiting me or preventing me from doing further call outs.

Looks like the exception is happening when it's trying to reauthenticate:

response = RestClient.send(verb, url, *params)

raw_response Error

I try to get the raw response but I get the Error 'undefined method 'raw_response=' for RSpotify:Modul'.

Is there a way to fix this?

invalid_grant: Invalid redirect URI {"error":"invalid_grant","error_description":"Invalid redirect URI"}

Hello,

I tried to connect my Spotify account to my private app on localhost as described here.

After entering my credentials, my app shows me the following error:
invalid_grant: Invalid redirect URI {"error":"invalid_grant","error_description":"Invalid redirect URI"}

I read a lot of that error on the internet. However, I wasn't able to fix it myself. Furthermore, I tried it out with several combinations of redirect URLs (e. g. with or without a trailing slash).

What's the problem and how to fix it?

Thanks in advance

Getting users' saved tracks throws error

Followed example in readme:

require 'rspotify'
require 'pry'

RSpotify.authenticate("...", "...")

wizzler = RSpotify::User.find('1242781307')
wizzler.saved_tracks

That throws the error:

NameError: uninitialized class variable @@users_credentials in RSpotify::User
from /Users/senthil/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rspotify-1.8.0/lib/rspotify/user.rb:43:in `oauth_header'

wizzler.playlists works so the token is right.

Ruby 1.9 support

Any chance to support Ruby <=1.9.3? It currently throws syntax errors on the method definitions using keyword arguments.

Encoding nested objects to json

Hi,

Recently trying to get nested objects encoded to json in Rails. I am searching a query like this:
results = RSpotify::Album.search(q, limit:5)
And then trying to return to the front-end in json format:
render json: results
The problem is that I get an array of albums which have Artists object in them. And these Artists become null in json when I encode. Is there a way to encode this nested objects?
Actually if there would be a method to return raw json from Spotify's original response, it'd be awesome.

Thanks,
/Said

Api-calls not URL-safe

Hi there,

First of all, great gem! Over a year time a lot of issues have been solved and a works like a charm right now.

I may have found one possible issue. If I want to make a playlist for a user with an username with non-url-safe characters, the api calls will break.

From the Rollbar-log:
bad URI(is not URI?): https://api.spotify.com/v1/users/tést_user/ (real username has been replaced by tést_user). I assume that this call tries to retrieve the playlists of the user.

Why am I getting this error? 400 bad request?

Gavins-MBP:crowdtune gmaister$ rails s
/Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in return!': 400 Bad Request (RestClient::BadRequest) from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/request.rb:495:inprocess_result'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/request.rb:421:in block in transmit' from /Users/gmaister/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/net/http.rb:853:instart'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/request.rb:413:in transmit' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/request.rb:176:inexecute'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient/request.rb:41:in execute' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rest-client-1.8.0/lib/restclient.rb:69:inpost'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/rspotify-1.16.0/lib/rspotify/connection.rb:28:in authenticate' from /Users/gmaister/Desktop/crowdtune/config/application.rb:12:inclass:Application'
from /Users/gmaister/Desktop/crowdtune/config/application.rb:10:in <module:Crowdtune>' from /Users/gmaister/Desktop/crowdtune/config/application.rb:9:in<top (required)>'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:78:in require' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:78:inblock in server'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:75:in tap' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:75:inserver'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in run_command!' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/railties-4.2.5/lib/rails/commands.rb:17:in<top (required)>'
from /Users/gmaister/Desktop/crowdtune/bin/rails:9:in require' from /Users/gmaister/Desktop/crowdtune/bin/rails:9:in<top (required)>'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/client/rails.rb:28:in load' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/client/rails.rb:28:incall'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/client/command.rb:7:in call' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/client.rb:28:inrun'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/bin/spring:51:in <top (required)>' from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/binstub.rb:11:inload'
from /Users/gmaister/.rvm/gems/ruby-2.1.0/gems/spring-1.6.1/lib/spring/binstub.rb:11:in <top (required)>' from /Users/gmaister/Desktop/crowdtune/bin/spring:13:inrequire'
from /Users/gmaister/Desktop/crowdtune/bin/spring:13:in <top (required)>' from bin/rails:3:inload'
from bin/rails:3:in `

'

Encode error

when i search or find a artist, if the artist with Chinese name it may cause errors.
ex:

require 'rspotify'

arctic_monkeys = RSpotify::Artist.find('2elBjNSdBE2Y3f0j1mjrql')
puts arctic_monkeys.name
arctic_monkeys.related_artists.each do |i|
    puts i.name
end

output

C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `encode': "\xE5" followed by "\x91"
 on CP950 (Encoding::InvalidByteSequenceError)
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `initialize'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `new'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `parse'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/rspotify-1.14.0/lib/rspotify/conne
ction.rb:56:in `send_request'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/rspotify-1.14.0/lib/rspotify/conne
ction.rb:35:in `block (2 levels) in singleton class'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/rspotify-1.14.0/lib/rspotify/base.
rb:51:in `find_one'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/rspotify-1.14.0/lib/rspotify/base.
rb:36:in `find'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/rspotify-1.14.0/lib/rspotify/artis
t.rb:25:in `find'
        from test.rb:3:in `<main>'

how to deal with it?

Nice work this API!!

Show Dialogue

Hi,

  1. Thanks for the library, its great.
  2. Im trying to add "show_dialog" to the auth process so that the user is always prompted to approve the app. (API Doc for Reference: https://developer.spotify.com/web-api/authorization-guide/)

I've tried adding it in omniauth.rb:
provider :spotify, client_id, client_secret, show_dialog: true, scope: 'scopes'

Is currently possible?

Thanks again.

Can't initialize a user from OmniAuth

Following the docs, I tried this:

spotify_user = RSpotify::User.new(request.env['omniauth.auth'])

Which failed with a 404 resource not found from RestClient as soon as I tried to fetch the user's playlists. Turning on RestClient debugging I found the following

RestClient.get "https://api.spotify.com/v1/users//playlists?limit=50&offset=0"

Note the missing username... Looking at the source for User it looks like OmniAuth's info hash is being used (https://github.com/guilhermesad/rspotify/blob/master/lib/rspotify/user.rb#L71). This gets passed into the constructor for Base, which looks for an id key. There isn't one returned from OmniAuth (keys present are email, image, name, nickname, urls) so all subsequent calls will fail.

I've monkey patched this in my code as follows:

auth_hash = request.env['omniauth.auth']
auth_hash["info"].merge!({ "id" => auth_hash["uid"] })
spotify_user = RSpotify::User.new(auth_hash)

Would you like me to submit a pull request with this fix rolled into User or do you have any ideas for a more elegant solution?

SSL connection issue

I recently ran into an issue with my SSL connection:

OpenSSL::SSL::SSLError in WelcomeController#index

SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: sslv3 alert handshake failure

I think I need to change the version of SSL that RestClient uses, but I can't seem to do that for the Rspotify.authenticate method. On line 27 of connection.rb.

429 handling

Would be nice with some type of inbuilt handling of Spotify's rate limit flow.

They set a limit and when it is reached they send a 429 with a retry after header which includes seconds when you can retry after.

Is it anyway to fix this?

Thread safety?

RSpotify.authenticate("<your_client_id>", "<your_client_secret>") does not seem like threadsafe way to authenticate client. Is this expected?

User#initialize isn't assigning fields such as 'id' and 'display_name'

First of all, I'm using Rails 3-2-stable and ruby 2.2.2p95
Here's the versions in my Gemfile.lock for the relevant gems:
rspotify (1.15.3)
omniauth-spotify (0.0.9)
omniauth-oauth2 (1.1.2)

In my request.env['omniauth.auth'], it looks like the spotify "id" and "display_name" are nested under the "raw_info" key which is nested under "extra". User#initialize expects the fields to be nested under "info".

Here's what my request.env['omniauth.auth'] looks like:

pp request.env['omniauth.auth']
{"provider"=>"spotify",
 "uid"=>"mattruzicka",
 "info"=>
  {"name"=>"Matt Ruzicka",
   "nickname"=>"mattruzicka",
   "email"=>"*****@example.com",
   "urls"=>{"spotify"=>"https://open.spotify.com/user/mattruzicka"},
   "image"=>
    "https://scontent.xx.fbcdn.net/hprofile-xap1/v/t1.0-1/p200x200/11057843_10204097127210872_3694592387270341086_n.jpg?oh=80a54722dc3858c18d330efc27e18d4b&oe=56D0284B"},
 "credentials"=>
  {"token"=>
    "***TOKEN***",
   "refresh_token"=>
    "***REFRESH_TOKEN***",
   "expires_at"=>1444865059,
   "expires"=>true},
 "extra"=>
  {"raw_info"=>
    {"display_name"=>"Matt Ruzicka",
     "email"=>"*****@example.com",
     "external_urls"=>{"spotify"=>"https://open.spotify.com/user/mattruzicka"},
     "followers"=>{"href"=>nil, "total"=>12},
     "href"=>"https://api.spotify.com/v1/users/mattruzicka",
     "id"=>"mattruzicka",
     "images"=>
      [{"height"=>nil,
        "url"=>
         "https://scontent.xx.fbcdn.net/hprofile-xap1/v/t1.0-1/p200x200/11057843_10204097127210872_3694592387270341086_n.jpg?oh=80a54722dc3858c18d330efc27e18d4b&oe=56D0284B",
        "width"=>nil}],
     "type"=>"user",
     "uri"=>"spotify:user:mattruzicka"}}}

So when I initialize a RSpotify::User user, the id and display_name are nil:

spotify_user = RSpotify::User.new(request.env['omniauth.auth'])
pp spotify_user =>
#<RSpotify::User:0x007febd87a4268
 @birthdate=nil,
 @country=nil,
 @credentials=
  {"token"=>
    "***TOKEN***",
   "refresh_token"=>
    "***REFRESH_TOKEN***",
   "expires_at"=>1444865059,
   "expires"=>true},
 @display_name=nil,
 @email="*****@example.com",
 @external_urls=nil,
 @followers=nil,
 @href=nil,
 @id=nil,
 @images=nil,
 @product=nil,
 @type=nil,
 @uri=nil>

Maybe this is specific to my environment. Is anyone else seeing this?

RSpotify::User.new(request.env['omniauth.auth']) returns incomplete user

It looks like Spotify changed the structure of the data returned during the authorization process.

Several fields have moved from the info section to a extra.raw_info. Below is an example:

{
    'provider' => 'spotify',
    'uid' => 'spilth',
    'info' => {
        'name' => 'Brian Kelly',
        'nickname' => 'spilth', 'email' => '[email protected]',
        'urls' => {'spotify' => 'https://open.spotify.com/user/spilth'},
        'image' => 'foo'
    },
    'credentials' => {
        'token' => 'foo',
        'refresh_token' => 'bar',
        'expires_at' => 1423766850,
        'expires' => true
    },
    'extra' => {
        'raw_info' => {
            'country' => 'US',
            'display_name' => 'Brian Kelly',
            'email' => '[email protected]',
            'external_urls' => {'spotify' => 'https://open.spotify.com/user/spilth'},
            'followers' => {
                'href' => nil,
                'total' => 4
            },
            'href' => 'https://api.spotify.com/v1/users/spilth',
            'id' => 'spilth',
            'images' => [
                {
                    'height' => nil,
                    'url' => 'bar',
                    'width' => nil
                }
            ],
            'product' => 'premium',
            'type' => 'user',
            'uri' => 'spotify:user:spilth'
        }
    }
}

Which results in me ending up with the following:

spotify_user
=> #<RSpotify::User:0x007fa0084c2f70
 @country=nil,
 @display_name=nil,
 @email="[email protected]",
 @external_urls=nil,
 @followers=nil,
 @href=nil,
 @id=nil,
 @images=nil,
 @product=nil,
 @type=nil,
 @uri=nil>

Retrieve when a track was added to a playlist

I'd like to be able to access the added_at when a track was added, but that data isn't recorded when the tracks for a playlist are fetched in Playlist#tracks.

I'd be happy to submit a PR if you would like to add this and if you might give me a little bit of guidance on how you would like it added.

It's a little funny since it's data that describes the relationship between the objects, and not exactly an attribute on the Track or Playlist.

Paging object

Top work on the pagination.

However, I was trying to figure out a nice way of getting all tracks from a playlist and I noticed in the Spotify api they return some handy information in the json response that's not being stored in the Playlist class.

The API documentation details the following in the response:

"limit" : 100,
"next" : https://api.spotify.com/v1/users/spotify/playlists/59ZbFPES4DQwEjBpWHzrtC/tracks?offset=100&limit=100",
"offset" : 0,
"previous" : null,
"total" : 105

Where next is the url to grab the next page of results.

I'm trying to get my head around a nice way to implement this.

displaying more than 20 albums

When I have an artist selected and I call .albums on him/her, it returns a maximum of 20 albums.

Any way to adjust this?

Thanks in advance.

Fix usage with omniauth

I followed the tutorial to use this gem with omniauth-spotify but saw that the user id wasn't populated.

I see that the info property gets copied into options here when instantiating a user:

options = options['info'] if options['info']

And the options are then used here:
https://github.com/guilhermesad/rspotify/blob/master/lib/rspotify/base.rb#L92

However, omniauth-spotify does not provide the user's id in the info hash, instead it is a top-level key, uid.

To fix this I had to do the following:

user['info']['id'] = user['uid']
spotify_user = RSpotify::User.new(user)

To fix this, should we add a line to copy the id into the options hash to be passed to the parent constructor? I am pretty new to Ruby, so I wanted to ask before submitting a PR.

Please re-release gem

For some reason rspotify 1.4.0 from rubygems does not have fixes I've added recently (just before you pushed the new version). Please re-release gem.

RSpotify doesn't authenticate all requests

Hi,

It seems that RSpotify doesn't authenticate all requests. This leads to lower rate limits being applied to read-only API requests such as RSpotify::Track.search(). Can we change this behaviour when RSpotify.authenticate has already been called? Specifically, https://github.com/guilhermesad/rspotify/blob/master/lib/rspotify/base.rb#L97 is calling the bare get instead of auth_get.

https://developer.spotify.com/web-api/user-guide/#rate-limiting

Thanks!

Possibly switch the HTTP client to Faraday?

Would you be willing to accept a PR to swap restclient for Faraday? It would be crazy useful to have a configurable HTTP client.

Let me know and we can put some engineering time into this right away.

Question about retrieving other peoples playlists

Hi,

Here is my gist: https://gist.github.com/emperorliu/178cbb86c660f296b091

When I'm logged in myself, I can retrieve my own playlists, but I can't do it when it's with another user_id, it gives me the error

RSpotify::Playlist.find("seanarturo", "1sPEU0bs81JzaRXpyQWNCm")
!! 400 Bad Request: {
"error": {
"status": 400,
"message": "Only valid bearer authentication supported"
}
}

This happens for both other users's public and private playlists.. I'm a little confused. I'm logged in with Oath, my omniauth.rb file is as so:

provider :spotify, ENV["SPOTIFY_CLIENT_ID"], ENV["SPOTIFY_CLIENT_SECRET"], scope: 'user-read-email playlist-modify-public playlist-modify-private playlist-read-private user-library-read user-library-modify'

Any help is very much appreciated. Thank You!

remove tracks from playlists

I'm trying to open a PR with a delete tracks from playlists feature.
For now, I'm monkey-patching the Playlist class in my app as a proof of concept, but, I can't figure out
how to make a request with request parameters..

Code:

module RSpotify
  class Playlist < Base
    def remove_tracks(tracks)
      url = "#{@href}/tracks"
      User.oauth_delete(@owner.id, url, tracks)
      @total -= tracks.size
      @tracks_cache = nil
    end
  end
end

The problem is that oauth_delete accepts only 2 parameters and the spotify api requires the tracks as a hash of {uri: URL, positions: [1]} as a request parameter, not as a path param.

How can I do that?

RSpotify::Album should support calls to #total

Album should support calls to total so a client can load all the tracks of an album. The current implementation hides this value away.

An example of an album that has 60 tracks but only 50 are loaded by RSpotify:
spotify:album:1tNYWgvzsqA4OqNDX9Qhoq

RSpotify::Artist#id will crash for some artists

If artist on the playlist is either removed, do not have an account on Spotify or is coming from hard drive, it is not possible to retrieve id and it should return nil instead. Otherwise this happens:

[1] pry(#<HomeController>)> artist
=> #<RSpotify::Artist:0x00000101f78328
 @external_urls={"spotify"=>"https://open.spotify.com/artist/null"},
 @genres=nil,
 @href="https://api.spotify.com/v1/artists/null",
 @id=nil,
 @images=nil,
 @name="Vedrim",
 @popularity=nil,
 @top_tracks={},
 @type="artist",
 @uri="spotify:artist:null">
[2] pry(#<HomeController>)> artist.id
RestClient::BadRequest: 400 Bad Request
from /Users/d4rky/.rvm/gems/ruby-2.1.1/gems/rest_client-1.7.3/lib/restclient/abstract_response.rb:48:in `return!'

The solution would probably be to check in RSpotify::Base#method_missing if the object is actualy loaded instead of reloading on nil).

Genres doesn't return genres for most artists

Genres doesn't return genres for most artists.
I have taken the example of Arctic Monkeys in the docs and printed to the terminal and genres doesn't seem to return correctly.
Popularity, top tracks ect all work correctly. Maybe Spotify have changed the way they handle genres?
('Bruce Springsteen' still returns "[roots rock, singer-songwriter]")

require 'rspotify'

artists = RSpotify::Artist.search('Arctic Monkeys')

arctic_monkeys = artists.first
arctic_monkeys.popularity #=> 74
puts arctic_monkeys.genres

--Returns nil --

Setting the current user in a one-off script

I'm working on a quick script to scrape twitter and add tracks to one of my playlists. I have already authenticated with my application keys:

RSpotify.authenticate(keys["spotify"]["CLIENT_ID"], keys["spotify"]["CLIENT_SECRET"])

but when I try to call add_tracks! to a playlist object, I get the following:

/Users/jordan/.rvm/gems/ruby-2.1.0/gems/rspotify-0.9.0/lib/rspotify/user.rb:26:in `oauth_headers': uninitialized class variable @@users_credentials in RSpotify::User (NameError)

It is my understanding that I need to do a little more work using OAuth, but unfortunately I can only find Rails examples in the README. Could you explain how I would go about setting a current user (with the appropriate scope)?

Best way to handle user creation with credentials?

I'm using rspotify outside of rails in an IRC bot, and I have the Oauth flow working correctly, I've been able to get my user's token.

What I'm having trouble figuring out is how to get that token applied to my user when I create it in the next request. I see that I can use RSpotify::User.new({'credentials' => {'token' => 'blah'}}) but that doesn't have the rest of the user state attached. I can also User.find, but then I can't attach the credentials. What's your recommended method for finding the user and attaching the token to them?

Support for query parameters

This is a brilliant wrapper, I've found it very easy to use. I just wanted to flag up something that may also effect how pagination is implemented...

Currently the artist.albums doesn't allow for any query parameters. The Spotify API allows the following query parameters when retrieving the albums for an artist:

album_type, country, limit, offset

Detailed here: https://developer.spotify.com/web-api/get-artists-albums/

undefined local variable or method `json'

json does not exist in the add_tracks! method

NameError: undefined local variable or method `json' for #<RSpotify::Playlist:0x007f970c3df748>
/Users/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.2/lib/rspotify/base.rb:150:in `method_missing'
/Users/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.2/lib/rspotify/playlist.rb:146:in `add_tracks!'
def add_tracks!(tracks, position: nil)
      track_uris = tracks.map(&:uri).join(',')
      url = "#{@href}/tracks?uris=#{track_uris}"
      url << "&position=#{position}" if position

      response = User.oauth_post(@owner.id, url, {})
      @total += tracks.size
      @tracks_cache = nil

      if RSpotify::raw_response
        @snapshot_id = JSON.parse(response)['snapshot_id']
        return response
      end

      @snapshot_id = json['snapshot_id']
      tracks
    end

Documentation Has Disappeared!

Hey! Great gem.

The documentation has disappeared this afternoon. Was using the link and then at some point it stopped resolving properly.

Playlist.tracks not authenticated when @owner != current_user

I know this is an edge case, and probably not really an issue, but I noticed the following:
When getting the tracks of a playlist that is "mine", but has a different @owner, the request is not authenticated, so the lower rate limits are being applied. This happens for example when getting the tracks for the Discover Weekly playlist. Wouldn't it make sense to always use the actual current User for accessing the tracks of a playlist?
Thanks a lot, and also thanks for this great gem :-)

unexpected tLABEL in controller

Hi,

First of all, thank you for developing this gem! Everything seems very straightforward and in combination with your documentation it was very easy to set-up.

Unfortunately I got an error in my controller:

syntax error, unexpected tLABEL
because of the following line in the controller:
spotify_user = RSpotify::User.new(request.env['omniauth.auth'])

For your information:
Ruby 1.9.3
Also uses omniauth with Facebook

update: a bit more specific:

!! #<SyntaxError: /Users/bob.loos/.rvm/gems/ruby-1.9.3-p545/gems/rspotify-1.0.0/lib/rspotify/user.rb:101: syntax error, unexpected tLABEL
def create_playlist!(name, public: true)
^
/Users/bob.loos/.rvm/gems/ruby-1.9.3-p545/gems/rspotify-1.0.0/lib/rspotify/user.rb:130: syntax error, unexpected keyword_end, expecting $end>

Might you know the solution for my problem? You would make me very happy with that.

With kind regards,
Bob

Need help with authentication

Hi,

I'm following the ReadMe, and I'm a little bit confused about where it says

<%= link_to 'Sign in with Spotify', '/auth/spotify' %>

And then after that, there's the link to the /auth/spotify/callback in routes.rb. I'm a little confused how I'm supposed to get the /auth/spotify button to click to the authentication page, since it doesn't build a route for it. I followed all the steps under Rails + Oath.

Crashing with certain old playlist(s).

This is one of my playlists http://open.spotify.com/user/wulffeld/playlist/22q3jbavyro92n3q96HyqM.

One item in what the Spotify API returns for this playlist is missing 'track'.

Doing:

RSpotify::Playlist.find('wulffeld', '22q3jbavyro92n3q96HyqM')

Backtrace:

NoMethodError: undefined method `[]' for nil:NilClass
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/track.rb:51:in `initialize'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:90:in `new'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:90:in `block in initialize'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:90:in `map'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:90:in `initialize'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:53:in `new'
    from /Users/m/.bundler/gems/rspotify-1.9.0/lib/rspotify/playlist.rb:53:in `find'
    from (irb):1
    from /Users/m/.bundler/gems/railties-4.1.2/lib/rails/commands/console.rb:90:in `start'
    from /Users/m/.bundler/gems/railties-4.1.2/lib/rails/commands/console.rb:9:in `start'
    from /Users/m/.bundler/gems/railties-4.1.2/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /Users/m/.bundler/gems/railties-4.1.2/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /Users/m/.bundler/gems/railties-4.1.2/lib/rails/commands.rb:17:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

Follow Playlist

Hi, I am trying to build an app which will allow users to post and follow spotify playlist.
Users login is implemented through devise like:
config.omniauth :spotify, '<<app_id>>', '<<app_secret>>', :scope => 'playlist-read-private user-follow-modify'
Now I am able to fetch a user and a playlist:

[2] pry(#)> spotify_user
=> #<RSpotify::User:0x00000003558b80
@birthdate=nil,
@Country=nil,
@display_name="Yaroslav Filyk",
@email=nil,
@external_urls={"spotify"=>"https://open.spotify.com/user/11178419014"},
@followers={"href"=>nil, "total"=>1},
@href="https://api.spotify.com/v1/users/11178419014",
@id="11178419014",
@images=
[{"height"=>nil,
"url"=>"https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xap1/v/t1.0-1/1185646_569428653117203_1802750611_n.jpg?oh=d94d6fdfa782b4c73b0faf2cebcdab6b&oe=55AAA2B1&gda=1441124271_1c26dec8fe9e8a660a735a8021ade0e3",
"width"=>nil}],
@Product=nil,
@type="user",
@uri="spotify:user:11178419014">

[3] pry(#)> playlist
=> #<RSpotify::Playlist:0x000000036e2050
@collaborative=false,
@description="Futuristic retro in the modern world. Artwork by Kilian Eng.",
@external_urls={"spotify"=>"http://open.spotify.com/user/wizzler/playlist/6cWcjjZlVb8UGW1ZiMKf3l"},
@followers={"href"=>nil, "total"=>586},
...

The problem is: I can't do anything related to rspotify follow features it gives me this error:

[4] pry(#)> spotify_user.follows?(playlist)
NameError: uninitialized class variable @@users_credentials in RSpotify::User

Can you help me out with this? Maybe I've picked the wrong scope or smth?

Question about refresh tokens

Hi @guilhermesad

I have a question regarding refresh tokens.

I've come across this issue where, when I authenticate into my app, I can see all my playlists and when I click them, I can see my tracks. However, if I click on a playlist that's made by someone else (I pull the tracks by using RSpotify::Playlist.find(owner, id), it gives me the error of:

RSpotify::Playlist.find(params[:owner], params[:id])
!! 401 Unauthorized: {
"error": {
"status": 401,
"message": "The access token expired"
}
}

I usually have to restart my server for it to work, but then after a small while, the access token expires, so I believe it's a refresh token issue. This only happens for playlists owned by other people. It never happens for my own playlists.. I can leave my computer on for however long I want and I'll still be able to enter my own playlists.

I've initialized correctly this time (both omniauth and RSpotify::authenticate), however I don't really know how to refresh the tokens. I looked into the app code and it seems like the gem provides this functionality. I also followed the tutorial where I did spotify_user = RSpotify::User.new(hash), and did spotify_user.create_playlist("hi")... and when I checked spotify_user, my access token and refresh token are the same as from when they were before I hashed it.

I would love some clarity on this issue when you get the chance. Thank you so much!

Playlists: bad URI(is not URI?) on accented characters

Hi,

Finding your Gem really useful, but am having issues polling for data on playlists where the user_id contains accents etc.

For example; https://api.spotify.com/v1/users/spotifyenespañol/playlists/02mIh5SWa1vGk9P93c8zGb produces the error: bad URI(is not URI?): https://api.spotify.com/v1/users/spotifyenespañol/playlists/02mIh5SWa1vGk9P93c8zGb

I've tried to encode the user_id but it's still failing. Without digging into the Gem's source, i'm not sure how to get around it. Have you encountered this problem before?

Many thanks in advance.
Ryan

1.15.2 breaks some search functionality?

In 1.14.0, I could search with a query specifying artist, track, album, etc:

RSpotify::Track.search("artist:who track:who are you")

But this returns nil in 1.15.2. Is this broken or do I need to do something different?

How can I add tracks to "starred" playlist in Spotify?

Hi,
By using this gem, I'm able to add tracks in other playlists but not in "starred" playlist. I'm getting 500 Internal server error. Anyone can please let me know how can do this?

I just want to make a track as starred track in spotify, is there any other way using spotify web api to perform this?

Thanks

Error when recovering spotify user

Hello,
Im working with Rails.
I just could not find the error in my code when authentication with spotify. The following code works:

def spotify
    spotify_user = RSpotify::User.new(request.env['omniauth.auth'])
    hash = spotify_user.to_hash
    @a = current_user
    @a.spotify = hash
    @a.save
    puts spotify_user.saved_tracks.size
    redirect_to root_url
end

But when trying to run the following code that recovers a spotify user

def spotify
    spotify_user = RSpotify::User.new(request.env['omniauth.auth'])
    hash = spotify_user.to_hash
    @a = current_user
    @a.spotify = hash
    @a.save
    spotify_user2 = RSpotify::User.new(current_user.spotify)
    puts spotify_user2.saved_tracks.size     
    redirect_to root_url
end

crashes on puts spotify_user2.saved_tracks.size

with the following error

RestClient::Unauthorized in UsersController#spotify
401 Unauthorized

Any help is greatly appreciated

Track.find should handle an invalid Spotify id

Thanks for sharing this cool gem!

t = RSpotify::Track.find %w(2UzMpPKPhbcC8RbsmuURAZ 7Jzsc04YpkRwB1zeyM39wE 44)
NoMethodError: undefined method `[]' for nil:NilClass
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/track.rb:53:in `initialize'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:46:in `new'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:46:in `block in find_many'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:46:in `map'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:46:in `find_many'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:33:in `find'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/track.rb:31:in `find'
    from (irb):21
    from /Users/joel/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'

RSpotify should not raise a NoMethodError here. Instead, it should handle the case where an invalid id, '44', returns no corresponding track.

Note that the behavior is different here than doing a search on that single bad id 44. For example:

RSpotify::Track.find '4'
RestClient::BadRequest: 400 Bad Request
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in `return!'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/request.rb:495:in `process_result'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/request.rb:421:in `block in transmit'
    from /Users/joel/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/net/http.rb:853:in `start'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/request.rb:413:in `transmit'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/request.rb:176:in `execute'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient/request.rb:41:in `execute'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rest-client-1.8.0/lib/restclient.rb:65:in `get'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/connection.rb:62:in `send_request'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/connection.rb:36:in `block (2 levels) in singleton class'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:54:in `find_one'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/base.rb:36:in `find'
    from /Users/joel/.rvm/gems/ruby-2.2.2/gems/rspotify-1.15.4/lib/rspotify/track.rb:31:in `find'
    from (irb):20
    from /Users/joel/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'

I would expect RSpotify::Track.find to return nil here instead of raising an exception. However, it looks like the implementation that takes an array of ids doesn't handle the case where some of the ids return no results and it falsely assumes that all results will be valid.

Why would this happen? Suppose we're doing analytics on user track plays. It could happen that we recorded a user playback of track id X and then before we try to query the Spotify API, they delete that track. Or the track id somehow becomes corrupt.

Either way, find should return nil here, not raise an exception.

Thanks. :-)

refreshing client_credentials

Hi, I noticed that the client_credentials are not refreshed when they have expired, like for example with the users' access_tokens. Would you say it'd make sense to do the same here? Are you even planning to add that? Maybe I could give it a try. Any additional information would be highly appreciated :-)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.