class RSpotify::Playlist

@attr [Boolean] collaborative true if the owner allows other users to modify the playlist @attr [String] description The playlist description @attr [Hash] followers Information about the followers of the playlist @attr [Array<Hash>] images Images for the playlist. The array may be empty or contain up to three images. The images are returned by size in descending order. If returned, the source URL for the image is temporary and will expire in less than one day. @attr [String] name The name of the playlist @attr [User] owner The user who owns the playlist @attr [Boolean] public true if the playlist is not marked as secret @attr [String] snapshot_id The version identifier for the current playlist. This attribute gets updated every time the playlist changes and can be supplied in other requests to target a specific playlist version @attr [Integer] total The total number of tracks in the playlist @attr [Hash] tracks_added_at A hash containing the date and time each track was added to the playlist. Note: the hash is updated only when {#tracks} is used. @attr [Hash] tracks_added_by A hash containing the user that added each track to the playlist. Note: the hash is updated only when {#tracks} is used. @attr [Hash] tracks_is_local A hash showing whether each track is local or not. Note: the hash is updated only when {#tracks} is used.

Public Class Methods

find(user_id, id, market: nil) click to toggle source

Returns Playlist object with user_id and id provided. If id is “starred”, returns starred playlist from user.

@param user_id [String] @param id [String] @param market [String] Optional. An {en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}. Provide this parameter if you want to apply Track Relinking @return [Playlist]

@example

playlist = RSpotify::Playlist.find('wizzler', '00wHcTN0zQiun4xri9pmvX')
playlist.class #=> RSpotify::Playlist
playlist.name  #=> "Movie Soundtrack Masterpieces"
# File lib/rspotify/playlist.rb, line 52
def self.find(user_id, id, market: nil)
  url = "users/#{user_id}/"
  url << (id == 'starred' ? id : "playlists/#{id}")
  url << "?market=#{market}" if market

  response = RSpotify.resolve_auth_request(user_id, url)
  return response if RSpotify.raw_response
  Playlist.new response
end
find_by_id(id, market: nil) click to toggle source

Returns Playlist object with id provided.

@param id [String] @param market [String] Optional. An {en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}. Provide this parameter if you want to apply Track Relinking @return [Playlist]

@example

playlist = RSpotify::Playlist.find_by_id('00wHcTN0zQiun4xri9pmvX')
playlist.class #=> RSpotify::Playlist
playlist.name  #=> "Movie Soundtrack Masterpieces"
# File lib/rspotify/playlist.rb, line 72
def self.find_by_id(id, market: nil)
  url = "playlists/#{id}"
  url << "?market=#{market}" if market
  response = RSpotify.resolve_auth_request(nil, url)
  return response if RSpotify.raw_response
  Playlist.new response
end
new(options = {}) click to toggle source
Calls superclass method RSpotify::Base::new
# File lib/rspotify/playlist.rb, line 96
def initialize(options = {})
  @collaborative = options['collaborative']
  @description   = options['description']
  @followers     = options['followers']
  @images        = options['images']
  @name          = options['name']
  @public        = options['public']
  @snapshot_id   = options['snapshot_id']
  @total         = options['tracks']['total']

  @owner = if options['owner']
    User.new options['owner']
  end

  tracks = options['tracks']['items'] if options['tracks']
  tracks.select! { |t| t['track'] } if tracks

  @tracks_cache = if tracks
    tracks.map { |t| Track.new t['track'] }
  end

  @tracks_added_at = hash_for(tracks, 'added_at') do |added_at|
    Time.parse added_at
  end

  @tracks_added_by = hash_for(tracks, 'added_by') do |added_by|
    User.new added_by
  end

  @tracks_is_local = hash_for(tracks, 'is_local') do |is_local|
    is_local
  end

  super(options)

  @path = if @href =~ /\/starred$/ 
    "users/#{@owner.instance_variable_get('@id').gsub('?','')}/starred" 
  else
    "playlists/#{@id}"
  end
end

Public Instance Methods

add_tracks!(tracks, position: nil) click to toggle source

Adds one or more tracks to a playlist in user’s Spotify account. This method is only available when the current user has granted access to the playlist-modify-public and playlist-modify-private scopes.

@param tracks [Array<Track>, Array<String>] Tracks to be added. Either array of Tracks or strings where each string is a valid spotify track uri. Maximum: 100 per request @param position [Integer, NilClass] The position to insert the tracks, a zero-based index. Default: tracks are appended to the playlist @return [Array<Track>] The tracks added

@example

tracks = RSpotify::Track.search('Know', 30)
playlist = user.create_playlist!('my-awesome-playlist')

playlist.add_tracks!(tracks)
playlist.tracks.size       #=> 30
playlist.tracks.first.name #=> "Somebody That I Used To Know"

playlist.add_tracks!(tracks, position: 20)
playlist.tracks[20].name #=> "Somebody That I Used To Know"
# File lib/rspotify/playlist.rb, line 155
def add_tracks!(tracks, position: nil)
  track_uris = nil
  if tracks.first.is_a? String
    track_uris = tracks.join(',')
  else
    track_uris = tracks.map(&:uri).join(',')
  end
  url = "#{@path}/tracks?uris=#{track_uris}"
  url << "&position=#{position}" if position

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

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

  @snapshot_id = response['snapshot_id']
  tracks
end
change_details!(**data) click to toggle source

Change name and public/private state of playlist in user’s Spotify account. Changing a public playlist requires the playlist-modify-public scope; changing a private playlist requires the playlist-modify-private scope.

@param name [String] Optional. The new name for the playlist. @param public [Boolean] Optional. If true the playlist will be public, if false it will be private. @return [Playlist]

@example

playlist.name   #=> "Movie Soundtrack Masterpieces"
playlist.public #=> true

playlist.change_details!(name: 'Movie Tracks', public: false)

playlist.name   #=> "Movie Tracks"
playlist.public #=> false
# File lib/rspotify/playlist.rb, line 193
def change_details!(**data)
  User.oauth_put(@owner.id, @path, data.to_json)
  data.each do |field, value|
    instance_variable_set("@#{field}", value)
  end
  @snapshot_id = nil
  self
end
complete!() click to toggle source

When an object is obtained undirectly, Spotify usually returns a simplified version of it. This method updates it into a full object, with all attributes filled.

@note It is seldom necessary to use this method explicitly, since RSpotify takes care of it automatically when needed (see {Base#method_missing})

@example

playlist = user.playlists.first
playlist.instance_variable_get("@description") #=> nil
playlist.complete!
playlist.instance_variable_get("@description") #=> "Iconic soundtracks..."
# File lib/rspotify/playlist.rb, line 212
def complete!
  initialize RSpotify.resolve_auth_request(@owner.id, @path)
end
is_followed_by?(users) click to toggle source

Check if one or more Spotify users are following a specified playlist. Checking if the user is privately following a playlist is only possible if he/she has granted access to the playlist-read-private scope.

@param users [Array<User>] The users to check. Maximum: 5. @return [Array<Boolean>]

@example

user1 = RSpotify::User.find('<some-id>')
user2 = RSpotify::User.find('<some-other-id>')
playlist.is_followed_by?([user1, user2]) #=> [true, true] (Users publicly following playlist)

oauth-user = RSpotify::User.new(request.env['omniauth.auth']) # (See OAuth section in readme)
playlist.is_followed_by?([oauth-user]) #=> [true] (User publicly or privately following playlist)
# File lib/rspotify/playlist.rb, line 229
def is_followed_by?(users)
  user_ids = users.map(&:id).join(',')
  url = "#{@path}/followers/contains?ids=#{user_ids}"

  users_credentials = if User.class_variable_defined?('@@users_credentials')
    User.class_variable_get('@@users_credentials')
  end

  auth_users = users.select do |user|
    users_credentials[user.id]
  end if users_credentials

  if auth_users && auth_users.any?
    User.oauth_get(auth_users.first.id, url)
  else
    RSpotify.get(url)
  end
end
remove_tracks!(tracks, snapshot_id: nil) click to toggle source

Remove one or more tracks from a user’s playlist. Removing from a public playlist requires the playlist-modify-public scope; removing from a private playlist requires the playlist-modify-private scope.

@param tracks [Array<Track,Hash>, Array<Integer>] Tracks to be removed. Maximum: 100 per request @param snapshot_id [String] Optional. The playlist’s snapshot ID against which you want to make the changes. @return [Playlist]

@example

# Remove all occurrences of one or more tracks
love_tracks = RSpotify::Track.search('Love')
playlist.remove_tracks!(love_tracks)

# Remove specific occurrences of one or more tracks
track = RSpotify::Track.find('tR3oH...')
playlist.remove_tracks!([{track: track, positions: [0,3]}, other_track])

# Remove tracks based only on their positions (requires snapshot id)
positions = [0,3,8]
playlist.remove_tracks!(positions, snapshot_id: '0ZvtH...')
# File lib/rspotify/playlist.rb, line 308
def remove_tracks!(tracks, snapshot_id: nil)
  positions = tracks if tracks.first.is_a? Integer

  tracks = tracks.map do |track|
    next { uri: track.uri } if track.is_a? Track
    {
      uri: track[:track].uri,
      positions: track[:positions]
    }
  end unless positions

  params = {
    method: :delete,
    url: Addressable::URI.encode(RSpotify::API_URI + @path + '/tracks'),
    headers: User.send(:oauth_header, @owner.id),
    payload: positions ? { positions: positions } : { tracks: tracks }
  }

  params[:payload][:snapshot_id] = snapshot_id if snapshot_id
  params[:payload] = params[:payload].to_json
  response = RestClient::Request.execute(params)

  @snapshot_id = JSON.parse(response)['snapshot_id']
  @tracks_cache = nil
  self
end
reorder_tracks!(range_start, insert_before, **options) click to toggle source

Reorder a track or a group of tracks in a playlist. Changing a public playlist requires the playlist-modify-public scope; changing a private playlist requires the playlist-modify-private scope.

@param range_start [Integer] The position of the first track to be reordered. @param insert_before [Integer] The position where the tracks should be inserted. To reorder the tracks to the end of the playlist, simply set insert_before to the position after the last track. @param range_length [Integer] Optional. The amount of tracks to be reordered. Default: 1. @param snapshot_id [String] Optional. The playlist’s snapshot ID against which you want to make the changes. @return [Playlist]

@example

range_start = 10
insert_before = 0
# Move the tracks at index 10-14 to the start of the playlist
playlist.reorder_tracks!(range_start, insert_before, range_length: 5)
# File lib/rspotify/playlist.rb, line 349
def reorder_tracks!(range_start, insert_before, **options)
  url = "#{@path}/tracks"
  data = {
    range_start: range_start,
    insert_before: insert_before
  }.merge options

  response = User.oauth_put(@owner.id, url, data.to_json)
  json = RSpotify.raw_response ? JSON.parse(response) : response

  @snapshot_id = json['snapshot_id']
  @tracks_cache = nil
  self
end
replace_image!(image, content_type) click to toggle source

Replace the image used to represent a specific playlist. Requires ugc-image-upload scope. Changing a public playlist requires the playlist-modify-public scope; changing a private playlist requires the playlist-modify-private scope.

@param image [String] Base64 encoded JPEG image data, maximum payload size is 256 KB @param content_type [String] The content type of the request body, e.g. “image/jpeg” @return [NilClass] When the image has been provided, Spofity forwards it on to their transcoder service in order to generate the three sizes provided in the playlist’s images object. This operation takes some time, that’s why nothing is returned for this method.

@example

playlist.replace_image!('SkZJRgABA...', 'image/jpeg')
# File lib/rspotify/playlist.rb, line 373
def replace_image!(image, content_type)
  url = "#{@path}/images"
  headers = {
    'Content-Type' => content_type
  }
  User.oauth_put(@owner.id, url, image, { headers: headers })
  nil
end
replace_tracks!(tracks) click to toggle source

Replace all the tracks in a playlist, overwriting its existing tracks. Changing a public playlist requires the playlist-modify-public scope; changing a private playlist requires the playlist-modify-private scope.

@param tracks [Array<Track>] The tracks that will replace the existing ones. Maximum: 100 per request @return [Array<Track>] The tracks that were added.

@example

playlist.tracks.map(&:name) #=> ["All of Me", "Wasted Love", "Love Runs Out"]
tracks = RSpotify::Track.search('Know', limit: 2)
playlist.replace_tracks!(tracks)
playlist.tracks.map(&:name) #=> ["Somebody That I Used To Know", "Do I Wanna Know?"]
# File lib/rspotify/playlist.rb, line 393
def replace_tracks!(tracks)
  track_uris = tracks.map(&:uri).join(',')
  url = "#{@path}/tracks?uris=#{track_uris}"
  User.oauth_put(@owner.id, url, {}.to_json)

  @total = tracks.size
  @tracks_cache = nil
  @snapshot_id = nil
  tracks
end
tracks(limit: 100, offset: 0, market: nil) click to toggle source

Returns array of tracks from the playlist

@param limit [Integer] Maximum number of tracks to return. Maximum: 100. Default: 100. @param offset [Integer] The index of the first track to return. Use with limit to get the next set of objects. Default: 0. @param market [String] Optional. An {en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}. Provide this parameter if you want to apply Track Relinking @return [Array<Track>]

@example

playlist = RSpotify::Playlist.find('wizzler', '00wHcTN0zQiun4xri9pmvX')
playlist.tracks.first.name #=> "Main Theme from Star Wars - Instrumental"
# File lib/rspotify/playlist.rb, line 258
def tracks(limit: 100, offset: 0, market: nil)
  last_track = offset + limit - 1
  if @tracks_cache && last_track < 100 && !RSpotify.raw_response
    return @tracks_cache[offset..last_track]
  end

  url = "#{@href}/tracks?limit=#{limit}&offset=#{offset}"
  url << "&market=#{market}" if market
  response = RSpotify.resolve_auth_request(@owner.id, url)

  json = RSpotify.raw_response ? JSON.parse(response) : response
  tracks = json['items'].select { |i| i['track'] }

  @tracks_added_at = hash_for(tracks, 'added_at') do |added_at|
    Time.parse added_at
  end

  @tracks_added_by = hash_for(tracks, 'added_by') do |added_by|
    User.new added_by
  end

  @tracks_is_local = hash_for(tracks, 'is_local') do |is_local|
    is_local
  end

  tracks.map! { |t| Track.new t['track'] }
  @tracks_cache = tracks if limit == 100 && offset == 0
  return response if RSpotify.raw_response
  tracks
end