lib/rspotify/playlist.rb in rspotify-1.14.0 vs lib/rspotify/playlist.rb in rspotify-1.15.0

- old
+ new

@@ -5,11 +5,11 @@ # @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. Can be supplied in other requests to target a specific playlist version + # @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. class Playlist < Base @@ -30,12 +30,12 @@ def self.browse_featured(limit: 20, offset: 0, **options) url = "browse/featured-playlists?limit=#{limit}&offset=#{offset}" options.each do |option, value| url << "&#{option}=#{value}" end - json = RSpotify.get(url) - json['playlists']['items'].map { |i| Playlist.new i } + response = RSpotify.get(url) + response['playlists']['items'].map { |i| Playlist.new i } end # Returns Playlist object with user_id and id provided. If id is "starred", returns starred playlist from user. # # @param user_id [String] @@ -50,12 +50,12 @@ url = if id == "starred" "users/#{user_id}/starred" else "users/#{user_id}/playlists/#{id}" end - json = RSpotify.resolve_auth_request(user_id, url) - Playlist.new json + response = RSpotify.resolve_auth_request(user_id, url) + Playlist.new response end # Returns array of Playlist objects matching the query. It's also possible to find the total number of search results for the query # # @param query [String] The search query's keywords. See the q description in {https://developer.spotify.com/web-api/search-item here} for details. @@ -128,14 +128,15 @@ def add_tracks!(tracks, position: nil) track_uris = tracks.map(&:uri).join(',') url = "#{@href}/tracks?uris=#{track_uris}" url << "&position=#{position}" if position - User.oauth_post(@owner.id, url, {}) + response = User.oauth_post(@owner.id, url, {}) + @snapshot_id = response['snapshot_id'] + @total += tracks.size @tracks_cache = nil - tracks end # 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. @@ -155,10 +156,11 @@ def change_details!(**data) User.oauth_put(@owner.id, @href, data.to_json) data.each do |field, value| instance_variable_set("@#{field}", value) end + @snapshot_id = nil self end # 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. @@ -220,12 +222,12 @@ if @tracks_cache && last_track < 100 return @tracks_cache[offset..last_track] end url = "#{@href}/tracks?limit=#{limit}&offset=#{offset}" - json = RSpotify.resolve_auth_request(@owner.id, url) - tracks = json['items'].select { |i| i['track'] } + response = RSpotify.resolve_auth_request(@owner.id, url) + tracks = response['items'].select { |i| i['track'] } @tracks_added_at = hash_for(tracks, 'added_at') do |added_at| Time.parse added_at end @@ -240,10 +242,56 @@ tracks.map! { |t| Track.new t['track'] } @tracks_cache = tracks if limit == 100 && offset == 0 tracks end + # 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...') + def remove_tracks!(tracks, snapshot_id: nil) + positions = tracks if tracks.first.is_a? Fixnum + + 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: "#{@href}/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 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. @@ -281,14 +329,14 @@ # playlist.replace_tracks!(tracks) # playlist.tracks.map(&:name) #=> ["Somebody That I Used To Know", "Do I Wanna Know?"] def replace_tracks!(tracks) track_uris = tracks.map(&:uri).join(',') url = "#{@href}/tracks?uris=#{track_uris}" - User.oauth_put(@owner.id, url, {}) + @total = tracks.size @tracks_cache = nil - + @snapshot_id = nil tracks end end end