spotify 12.5.3 → 12.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +20 -5
  4. data/CHANGELOG.md +29 -1
  5. data/Gemfile +5 -0
  6. data/MIT-LICENSE +21 -0
  7. data/README.markdown +75 -50
  8. data/Rakefile +1 -1
  9. data/examples/example-audio_delivery_speed.rb +48 -0
  10. data/examples/{audio-stream_example.rb → example-audio_stream.rb} +14 -29
  11. data/examples/example-console.rb +9 -0
  12. data/examples/example-listing_playlists.rb +89 -0
  13. data/examples/example-loading_object.rb +25 -0
  14. data/examples/example-random_related_artists.rb +53 -0
  15. data/examples/support.rb +106 -0
  16. data/lib/spotify.rb +36 -55
  17. data/lib/spotify/api.rb +54 -26
  18. data/lib/spotify/api/album.rb +45 -2
  19. data/lib/spotify/api/album_browse.rb +81 -3
  20. data/lib/spotify/api/artist.rb +21 -2
  21. data/lib/spotify/api/artist_browse.rb +121 -3
  22. data/lib/spotify/api/error.rb +5 -1
  23. data/lib/spotify/api/image.rb +72 -6
  24. data/lib/spotify/api/inbox.rb +33 -4
  25. data/lib/spotify/api/link.rb +117 -4
  26. data/lib/spotify/api/miscellaneous.rb +12 -0
  27. data/lib/spotify/api/playlist.rb +321 -16
  28. data/lib/spotify/api/playlist_container.rb +168 -9
  29. data/lib/spotify/api/search.rb +156 -3
  30. data/lib/spotify/api/session.rb +390 -26
  31. data/lib/spotify/api/toplist_browse.rb +74 -3
  32. data/lib/spotify/api/track.rb +134 -4
  33. data/lib/spotify/api/user.rb +18 -2
  34. data/lib/spotify/api_helpers.rb +47 -0
  35. data/lib/spotify/data_converters.rb +7 -0
  36. data/lib/spotify/{types → data_converters}/best_effort_string.rb +1 -1
  37. data/lib/spotify/{types → data_converters}/byte_string.rb +0 -0
  38. data/lib/spotify/data_converters/country_code.rb +30 -0
  39. data/lib/spotify/{types → data_converters}/image_id.rb +1 -1
  40. data/lib/spotify/{type_safety.rb → data_converters/type_safety.rb} +0 -0
  41. data/lib/spotify/{types → data_converters}/utf8_string.rb +2 -2
  42. data/lib/spotify/{types → data_converters}/utf8_string_pointer.rb +2 -2
  43. data/lib/spotify/error.rb +180 -47
  44. data/lib/spotify/managed_pointer.rb +32 -12
  45. data/lib/spotify/monkey_patches/ffi_buffer.rb +11 -0
  46. data/lib/spotify/monkey_patches/ffi_enums.rb +4 -0
  47. data/lib/spotify/monkey_patches/ffi_pointer.rb +1 -0
  48. data/lib/spotify/structs.rb +4 -0
  49. data/lib/spotify/structs/session_callbacks.rb +97 -26
  50. data/lib/spotify/structs/session_config.rb +1 -1
  51. data/lib/spotify/structs/subscribers.rb +4 -3
  52. data/lib/spotify/types.rb +104 -5
  53. data/lib/spotify/{objects → types}/album.rb +0 -0
  54. data/lib/spotify/{objects → types}/album_browse.rb +0 -0
  55. data/lib/spotify/{objects → types}/artist.rb +0 -0
  56. data/lib/spotify/{objects → types}/artist_browse.rb +0 -0
  57. data/lib/spotify/{objects → types}/image.rb +0 -0
  58. data/lib/spotify/{objects → types}/inbox.rb +0 -0
  59. data/lib/spotify/{objects → types}/link.rb +0 -0
  60. data/lib/spotify/{objects → types}/playlist.rb +0 -0
  61. data/lib/spotify/{objects → types}/playlist_container.rb +0 -0
  62. data/lib/spotify/{objects → types}/search.rb +0 -0
  63. data/lib/spotify/{objects → types}/session.rb +0 -0
  64. data/lib/spotify/{objects → types}/toplist_browse.rb +0 -0
  65. data/lib/spotify/{objects → types}/track.rb +0 -0
  66. data/lib/spotify/{objects → types}/user.rb +0 -0
  67. data/lib/spotify/util.rb +38 -35
  68. data/lib/spotify/version.rb +1 -1
  69. data/spec/spec_helper.rb +24 -13
  70. data/spec/spotify/api/image_spec.rb +32 -0
  71. data/spec/spotify/api/inbox_spec.rb +34 -0
  72. data/spec/spotify/api/link_spec.rb +40 -0
  73. data/spec/spotify/api/playlist_spec.rb +99 -0
  74. data/spec/spotify/api/playlistcontainer_spec.rb +82 -0
  75. data/spec/spotify/api/session_spec.rb +97 -0
  76. data/spec/spotify/api/track_spec.rb +29 -0
  77. data/spec/spotify/api_error_spec.rb +55 -0
  78. data/spec/spotify/api_spec.rb +17 -11
  79. data/spec/spotify/{types → data_converters}/best_effort_string_spec.rb +4 -4
  80. data/spec/spotify/{types → data_converters}/byte_string_spec.rb +0 -0
  81. data/spec/spotify/data_converters/country_code_spec.rb +16 -0
  82. data/spec/spotify/{types → data_converters}/image_id_spec.rb +1 -1
  83. data/spec/spotify/{type_safety_spec.rb → data_converters/type_safety_spec.rb} +0 -0
  84. data/spec/spotify/{types → data_converters}/utf8_string_pointer_spec.rb +0 -0
  85. data/spec/spotify/{types → data_converters}/utf8_string_spec.rb +1 -1
  86. data/spec/spotify/{api/functions_spec.rb → functions_spec.rb} +2 -0
  87. data/spec/spotify/managed_pointer_spec.rb +13 -13
  88. data/spec/spotify/structs/subscribers_spec.rb +5 -3
  89. data/spec/spotify/{defines_spec.rb → types_spec.rb} +16 -3
  90. data/spec/spotify/util_spec.rb +24 -0
  91. data/spec/spotify_spec.rb +74 -0
  92. data/spec/support/spotify_util.rb +6 -2
  93. data/spec/support/spy_output.rb +16 -0
  94. data/spotify.gemspec +4 -2
  95. metadata +111 -71
  96. data/examples/README.md +0 -15
  97. data/examples/console_example.rb +0 -22
  98. data/examples/example_support.rb +0 -66
  99. data/examples/loading-object_example.rb +0 -43
  100. data/examples/logging-in_example.rb +0 -58
  101. data/lib/spotify/defines.rb +0 -109
  102. data/lib/spotify/objects.rb +0 -17
  103. data/spec/spotify/enums_spec.rb +0 -9
  104. data/spec/spotify/spotify_spec.rb +0 -69
@@ -0,0 +1,12 @@
1
+ module Spotify
2
+ class API
3
+ # @!group Miscellaneous
4
+
5
+ # @method build_id
6
+ # @see Spotify::API_BUILD
7
+ # @return [String] libspotify build ID
8
+ attach_function :build_id, [], UTF8String
9
+
10
+ # @!endgroup
11
+ end
12
+ end
@@ -1,39 +1,344 @@
1
1
  module Spotify
2
2
  class API
3
3
  # @!group Playlist
4
+
5
+ # @param [Playlist] playlist
6
+ # @return [Boolean] true if playlist is loaded
7
+ # @method playlist_is_loaded(playlist)
4
8
  attach_function :playlist_is_loaded, [ Playlist ], :bool
5
- attach_function :playlist_add_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], :error
6
- attach_function :playlist_remove_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], :error
9
+
10
+ # Attach callbacks to the playlist, used for getting change notifications.
11
+ #
12
+ # @example
13
+ # callbacks = Spotify::PlaylistCallbacks.new({
14
+ # tracks_added: proc do |playlist, tracks_pointer, count, position|
15
+ # puts "#{count} tracks added at #{position}."
16
+ # end,
17
+ # playlist_renamed: proc { |playlist| puts "Playlist renamed!" },
18
+ # })
19
+ # Spotify.playlist_add_callbacks(playlist, callbacks, nil) # => ok
20
+ #
21
+ # @note it is *very* important that the callbacks are not garbage collected before they are called!
22
+ # @param [Playlist] playlist
23
+ # @param [PlaylistCallbacks] playlist_callbacks
24
+ # @param [FFI::Pointer] userdata
25
+ # @return [Symbol] error code
26
+ # @method playlist_add_callbacks(playlist, playlist_callbacks, userdata)
27
+ attach_function :playlist_add_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], APIError
28
+
29
+ # Remove playlist callbacks previously added with {#playlist_add_callbacks}.
30
+ #
31
+ # @see #playlist_add_callbacks
32
+ # @param [Playlist] playlist
33
+ # @param [PlaylistCallbacks] playlist_callbacks
34
+ # @param [FFI::Pointer] userdata
35
+ # @return [Symbol] error code
36
+ # @method playlist_remove_callbacks(playlist, playlist_callbacks, userdata)
37
+ attach_function :playlist_remove_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], APIError
38
+
39
+ # @see #playlist_track
40
+ # @note if playlist is not loaded, the function always return 0.
41
+ # @param [Playlist] playlist
42
+ # @return [Integer] number of tracks in the playlist
43
+ # @method playlist_num_tracks(playlist)
7
44
  attach_function :playlist_num_tracks, [ Playlist ], :int
45
+
46
+ # @see #playlist_num_tracks
47
+ # @note if index is out of range, the function always return nil.
48
+ # @param [Playlist] playlist
49
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
50
+ # @return [Track, nil] track at index
51
+ # @method playlist_track(playlist, index)
8
52
  attach_function :playlist_track, [ Playlist, :int ], Track
53
+
54
+ # @see #playlist_num_tracks
55
+ # @note if index is out of range, the function always return -1.
56
+ # @param [Playlist] playlist
57
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
58
+ # @return [Integer] time in seconds since unix epoch that track was added at index in the playlist
59
+ # @method playlist_track_create_time(playlist, index)
9
60
  attach_function :playlist_track_create_time, [ Playlist, :int ], :int
61
+
62
+ # @see #playlist_num_tracks
63
+ # @note if index is out of range, the function always return nil.
64
+ # @param [Playlist] playlist
65
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
66
+ # @return [User, nil] user that added the track at index in the playlist
67
+ # @method playlist_track_creator(playlist, index)
10
68
  attach_function :playlist_track_creator, [ Playlist, :int ], User
69
+
70
+ # @see #playlist_num_tracks
71
+ # @see #playlist_track_set_seen
72
+ # @note if index is out of range, the function always return false.
73
+ # @param [Playlist] playlist
74
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
75
+ # @return [Boolean] true if playlist has been marked as seen with {#playlist_track_set_seen}.
76
+ # @method playlist_track_seen(playlist, index)
11
77
  attach_function :playlist_track_seen, [ Playlist, :int ], :bool
12
- attach_function :playlist_track_set_seen, [ Playlist, :int, :bool ], :error
78
+
79
+ # Set `seen` flag on track. The flag can be retrieved by {#playlist_track_seen}.
80
+ #
81
+ # @see #playlist_num_tracks
82
+ # @see #playlist_track_seen
83
+ # @param [Playlist] playlist
84
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
85
+ # @param [Boolean] seen
86
+ # @return [Symbol] error code
87
+ # @method playlist_track_set_seen(playlist, index, seen)
88
+ attach_function :playlist_track_set_seen, [ Playlist, :int, :bool ], APIError
89
+
90
+ # @see #playlist_num_tracks
91
+ # @note if index is out of range, the function always return nil.
92
+ # @param [Playlist] playlist
93
+ # @param [Integer] index number between 0...{#playlist_num_tracks}
94
+ # @return [String] message attached to a playlist item
95
+ # @method playlist_track_message(playlist, index)
13
96
  attach_function :playlist_track_message, [ Playlist, :int ], UTF8String
97
+
98
+ # @see #playlist_is_loaded
99
+ # @note if playlist is not loaded, the function always return an empty string.
100
+ # @param [Playlist] playlist
101
+ # @return [String] name of the playlist
102
+ # @method playlist_name(playlist)
14
103
  attach_function :playlist_name, [ Playlist ], UTF8String
15
- attach_function :playlist_rename, [ Playlist, UTF8String ], :error
104
+
105
+ # Rename the playlist.
106
+ #
107
+ # @see #playlist_is_loaded
108
+ # @note if playlist is not loaded, the function always return :permission_denied.
109
+ # @param [Playlist] playlist
110
+ # @param [String] new_name new name of the playlist
111
+ # @return [Symbol] error code
112
+ # @method playlist_rename(playlist, new_name)
113
+ attach_function :playlist_rename, [ Playlist, UTF8String ], APIError
114
+
115
+ # @param [Playlist] playlist
116
+ # @return [User] owner of the playlist
117
+ # @method playlist_owner(playlist)
16
118
  attach_function :playlist_owner, [ Playlist ], User
119
+
120
+ # @see #playlist_is_loaded
121
+ # @see #playlist_set_collaborative
122
+ # @note if {#playlist_set_collaborative} was used, the final value will not be
123
+ # visible until after libspotify has negotiated with Spotify backend.
124
+ # @note if playlist is not loaded, the function always return false.
125
+ # @param [Playlist] playlist
126
+ # @return [Boolean] true if the playlist is collaborative, i.e. editable by others.
127
+ # @method playlist_is_collaborative(playlist)
17
128
  attach_function :playlist_is_collaborative, [ Playlist ], :bool
18
- attach_function :playlist_set_collaborative, [ Playlist, :bool ], :error
19
- attach_function :playlist_set_autolink_tracks, [ Playlist, :bool ], :error
129
+
130
+ # Set collaborative status on a playlist.
131
+ #
132
+ # @see #playlist_is_collaborative
133
+ # @note the function always return :ok.
134
+ # @param [Playlist] playlist
135
+ # @param [Boolean] collaborative
136
+ # @return [Symbol] error code
137
+ # @method playlist_set_collaborative(playlist, collaborative)
138
+ attach_function :playlist_set_collaborative, [ Playlist, :bool ], APIError
139
+
140
+ # Set autolinking state for a playlist.
141
+ #
142
+ # If a playlist is set to autolink, unplayable tracks will be made playable by
143
+ # linking them to an equivalent playable track when possible.
144
+ #
145
+ # @note the function always return :ok.
146
+ # @param [Playlist] playlist
147
+ # @param [Boolean] autolink
148
+ # @return [Symbol] error code
149
+ # @method playlist_set_autolink_tracks(playlist, autolink)
150
+ attach_function :playlist_set_autolink_tracks, [ Playlist, :bool ], APIError
151
+
152
+ # @see #playlist_is_loaded
153
+ # @note if the playlist is not loaded, the function always return nil.
154
+ # @param [Playlist] playlist
155
+ # @return [String, nil] playlist description, if available
156
+ # @method playlist_get_description(playlist)
20
157
  attach_function :playlist_get_description, [ Playlist ], UTF8String
21
- attach_function :playlist_get_image, [ Playlist, :buffer_out ], :bool
158
+
159
+ # Retrieve playlist image ID as a string.
160
+ #
161
+ # @example
162
+ # Spotify.playlist_get_image(playlist) # =>
163
+ #
164
+ # @see #playlist_is_loaded
165
+ # @see #image_create
166
+ # @note if the playlist is not loaded, the function always return nil.
167
+ # @param [Playlist] playlist
168
+ # @return [String, nil] image ID for playlist image, or nil if no image available.
169
+ # @method playlist_get_image(playlist)
170
+ attach_function :playlist_get_image, [ Playlist, :buffer_out ], :bool do |playlist|
171
+ with_buffer(Spotify::ImageID) do |image_id_buffer|
172
+ if sp_playlist_get_image(playlist, image_id_buffer)
173
+ ImageID.from_native(image_id_buffer, nil)
174
+ end
175
+ end
176
+ end
177
+
178
+ # @see #playlist_is_loaded
179
+ # @note if the playlist is not loaded, the function always return true.
180
+ # @param [Playlist] playlist
181
+ # @return [Boolean] true if the playlist has local changes that have not yet been acknowledged by Spotify backend
182
+ # @method playlist_has_pending_changes(playlist)
22
183
  attach_function :playlist_has_pending_changes, [ Playlist ], :bool
23
- attach_function :playlist_add_tracks, [ Playlist, :array, :int, :int, Session ], :error
24
- attach_function :playlist_remove_tracks, [ Playlist, :array, :int ], :error
25
- attach_function :playlist_reorder_tracks, [ Playlist, :array, :int, :int ], :error
184
+
185
+ # Add tracks to the playlist.
186
+ #
187
+ # @example single track
188
+ # Spotify.playlist_add_tracks(playlist, track, offset, session) # => :ok
189
+ #
190
+ # @example array of tracks
191
+ # Spotify.playlist_add_tracks(playlist, tracks, offset, session) # => :ok
192
+ #
193
+ # @see #playlist_is_loaded
194
+ # @note if the playlist is not loaded, the function always return an error.
195
+ #
196
+ # @param [Playlist] playlist
197
+ # @param [Array<Track>, Track] tracks
198
+ # @param [Integer] offset starting index to add tracks from
199
+ # @param [Session] session
200
+ # @return [Symbol] error code
201
+ # @method playlist_add_tracks(playlist, tracks, offset, session)
202
+ attach_function :playlist_add_tracks, [ Playlist, :array, :int, :int, Session ], APIError do |playlist, tracks, offset, session|
203
+ tracks = Array(tracks)
204
+
205
+ with_buffer(Spotify::Track, size: tracks.length) do |tracks_buffer|
206
+ tracks_buffer.write_array_of_pointer(tracks)
207
+ sp_playlist_add_tracks(playlist, tracks_buffer, tracks.length, offset, session)
208
+ end
209
+ end
210
+
211
+ # Remove tracks from the playlist at the given indices.
212
+ #
213
+ # @example single index
214
+ # Spotify.playlist_remove_tracks(playlist, 3) # => :ok
215
+ #
216
+ # @example array of indices
217
+ # Spotify.playlist_remove_tracks(playlist, [1, 3]) # => :ok
218
+ #
219
+ # @see #playlist_is_loaded
220
+ # @note if the playlist is not loaded, the function always return an error.
221
+ # @note any index in indices_pointer must exist at most once, i.e. [0,1,2] is valid, [0,0,1] is not.
222
+ # @param [Playlist] playlist
223
+ # @param [Array<Integer>, Integer] indices_pointer pointer to array of track indices
224
+ # @return [Symbol] error code
225
+ # @method playlist_remove_tracks(playlist, indices)
226
+ attach_function :playlist_remove_tracks, [ Playlist, :array, :int ], APIError do |playlist, indices|
227
+ indices = Array(indices)
228
+
229
+ with_buffer(:int, size: indices.length) do |indices_buffer|
230
+ indices_buffer.write_array_of_int(indices)
231
+ sp_playlist_remove_tracks(playlist, indices_buffer, indices.length)
232
+ end
233
+ end
234
+
235
+ # Move tracks at the given indices to position index and forward.
236
+ #
237
+ # @example
238
+ # Spotify.playlist_reorder_tracks(playlist, [1, 7], 0) # => :ok
239
+ #
240
+ # @see #playlist_is_loaded
241
+ # @note if the playlist is not loaded, the function always return an error.
242
+ # @note any index in indices_pointer must exist at most once, i.e. [0,1,2] is valid, [0,0,1] is not.
243
+ # @param [Playlist] playlist
244
+ # @param [Array<Integer>] indices_pointer pointer to array of track indices
245
+ # @param [Integer] index starting position of tracks to be placed at, number between 0..{#playlist_num_tracks}
246
+ # @return [Symbol] error code
247
+ # @method playlist_reorder_tracks(playlist, indices, index)
248
+ attach_function :playlist_reorder_tracks, [ Playlist, :array, :int, :int ], APIError do |playlist, indices, index|
249
+ indices = Array(indices)
250
+
251
+ with_buffer(:int, size: indices.length) do |indices_buffer|
252
+ indices_buffer.write_array_of_int(indices)
253
+ sp_playlist_reorder_tracks(playlist, indices_buffer, indices.length, index)
254
+ end
255
+ end
256
+
257
+ # @see #playlist_is_loaded
258
+ # @see #playlist_update_subscribers
259
+ # @note if the playlist is not loaded, the function always return 0.
260
+ # @note if {#playlist_update_subscribers} have not been called, the function always return 0.
261
+ # @param [Playlist] playlist
262
+ # @return [Integer] number of playlist subscribers
263
+ # @method playlist_num_subscribers(playlist)
26
264
  attach_function :playlist_num_subscribers, [ Playlist ], :uint
265
+
266
+ # @example
267
+ # subscribers = Spotify.playlist_subscribers(playlist).to_a
268
+ # puts "Subscribers: ", subscribers.join(", ")
269
+ #
270
+ # @see #playlist_is_loaded
271
+ # @see #playlist_update_subscribers
272
+ # @see Subscribers
273
+ # @note if the playlist is not loaded, the function always return an empty structure.
274
+ # @note if {#playlist_update_subscribers} have not been called, the function always return an empty structure.
275
+ # @param [Playlist] playlist
276
+ # @return [Subscribers]
277
+ # @method playlist_subscribers(playlist)
27
278
  attach_function :playlist_subscribers, [ Playlist ], Subscribers.auto_ptr
28
- attach_function :playlist_subscribers_free, [ Subscribers.by_ref ], :error
29
- attach_function :playlist_update_subscribers, [ Session, Playlist ], :error
279
+ attach_function :playlist_subscribers_free, [ Subscribers.by_ref ], APIError
280
+
281
+ # Request download of the subscribers list.
282
+ #
283
+ # @note the function updates subscribers asynchronously, see {PlaylistCallbacks#subscribers_changed} for callback.
284
+ # @param [Session] session
285
+ # @param [Playlist] playlist
286
+ # @return [Symbol] error code
287
+ # @method playlist_update_subscribers(session, playlist)
288
+ attach_function :playlist_update_subscribers, [ Session, Playlist ], APIError
289
+
290
+ # @see https://developer.spotify.com/docs/libspotify/12.1.51/group__playlist.html#ga967ad87f0db702513ecda82546f667c5
291
+ # @param [Session] session
292
+ # @param [Playlist] playlist
293
+ # @return [Boolean] true if playlist is loaded in memory, as opposed to only stored on disk.
294
+ # @method playlist_is_in_ram(session, playlist)
30
295
  attach_function :playlist_is_in_ram, [ Session, Playlist ], :bool
31
- attach_function :playlist_set_in_ram, [ Session, Playlist, :bool ], :error
296
+
297
+ # Set if playlist should be loaded into memory, as opposed to only read from on disk.
298
+ #
299
+ # @see https://developer.spotify.com/docs/libspotify/12.1.51/group__playlist.html#ga967ad87f0db702513ecda82546f667c5
300
+ # @param [Session] session
301
+ # @param [Playlist] playlist
302
+ # @param [Boolean] in_ram
303
+ # @return [Symbol] error code
304
+ # @method playlist_set_in_ram(session, playlist, in_ram)
305
+ attach_function :playlist_set_in_ram, [ Session, Playlist, :bool ], APIError
306
+
307
+ # Instantiate a Playlist from a Link.
308
+ #
309
+ # @param [Session] session
310
+ # @param [Link] link
311
+ # @return [Playlist, nil] playlist, or nil if link was not a valid playlist link
312
+ # @method playlist_create(session, link)
32
313
  attach_function :playlist_create, [ Session, Link ], Playlist
314
+
315
+ # @see #playlist_is_loaded
316
+ # @see #playlist_set_offline_mode
317
+ # @note if the playlist is not loaded, the function always return :no.
318
+ # @param [Session] session
319
+ # @param [Playlist] playlist
320
+ # @return [Symbol] playlist offline status, one of :no, :yes, :downloading, or :waiting
321
+ # @method playlist_get_offline_status(session, playlist)
33
322
  attach_function :playlist_get_offline_status, [ Session, Playlist ], :playlist_offline_status
323
+
324
+ # @note if the playlist is not loaded, the function always return 0.
325
+ # @note if the playlist is not marked for offline download, the function always return 0.
326
+ # @param [Session] session
327
+ # @param [Playlist] playlist
328
+ # @return [Integer] percentage of playlist downloaded, 0..100
329
+ # @method playlist_get_offline_download_completed(session, playlist)
34
330
  attach_function :playlist_get_offline_download_completed, [ Session, Playlist ], :int
35
- attach_function :playlist_set_offline_mode, [ Session, Playlist, :bool ], :error
36
- attach_function :playlist_add_ref, [ Playlist ], :error
37
- attach_function :playlist_release, [ Playlist ], :error
331
+
332
+ # Set if playlist should be marked for offline playback.
333
+ #
334
+ # @param [Session] session
335
+ # @param [Playlist] playlist
336
+ # @param [Boolean] offline true if playlist should be downloaded for offline usage
337
+ # @return [Symbol] error code
338
+ # @method playlist_set_offline_mode(session, playlist, offline)
339
+ attach_function :playlist_set_offline_mode, [ Session, Playlist, :bool ], APIError
340
+
341
+ attach_function :playlist_add_ref, [ Playlist ], APIError
342
+ attach_function :playlist_release, [ Playlist ], APIError
38
343
  end
39
344
  end
@@ -1,23 +1,182 @@
1
1
  module Spotify
2
2
  class API
3
3
  # @!group PlaylistContainer
4
- attach_function :playlistcontainer_add_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], :error
5
- attach_function :playlistcontainer_remove_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], :error
4
+
5
+ # Attach callbacks to the container, used for getting change notifications.
6
+ #
7
+ # @example
8
+ # callbacks = Spotify::PlaylistContainerCallbacks.new({
9
+ # container_loaded: proc { |playlist| puts "Container loaded!" },
10
+ # })
11
+ # Spotify.playlistcontainer_add_callbacks(container, callbacks, nil) # => :ok
12
+ #
13
+ # @note it is *very* important that the callbacks are not garbage collected before they are called!
14
+ # @param [PlaylistContainer] container
15
+ # @param [PlaylistContainerCallbacks] container_callbacks
16
+ # @param [FFI::Pointer] userdata
17
+ # @return [Symbol] error code
18
+ # @method playlistcontainer_add_callbacks(container, container_callbacks, userdata)
19
+ attach_function :playlistcontainer_add_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], APIError
20
+
21
+ # Remove container callbacks previously added with {#playlistcontainer_add_callbacks}.
22
+ #
23
+ # @see #playlistcontainer_add_callbacks
24
+ # @param [PlaylistContainer] container
25
+ # @param [PlaylistCallbacks] container_callbacks
26
+ # @param [FFI::Pointer] userdata
27
+ # @return [Symbol] error code
28
+ # @method playlistcontainer_remove_callbacks(container, container_callbacks, userdata)
29
+ attach_function :playlistcontainer_remove_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], APIError
30
+
31
+ # @see #playlistcontainer_is_loaded
32
+ # @see #playlistcontainer_playlist
33
+ # @note if the container is not loaded, the function will always return 0.
34
+ # @param [PlaylistContainer] container
35
+ # @return [Integer] number of playlists in container
36
+ # @method playlistcontainer_num_playlists(container)
6
37
  attach_function :playlistcontainer_num_playlists, [ PlaylistContainer ], :int
38
+
39
+ # @see #playlistcontainer_num_playlists
40
+ # @note if index is out of range, the function always return nil.
41
+ # @param [PlaylistContainer] container
42
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
43
+ # @return [Playlist, nil] playlist at index
44
+ # @method playlistcontainer_playlist(container)
7
45
  attach_function :playlistcontainer_playlist, [ PlaylistContainer, :int ], Playlist
46
+
47
+ # @see #playlistcontainer_num_playlists
48
+ # @note if index is out of range, the function always return :playlist.
49
+ # @param [PlaylistContainer] container
50
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
51
+ # @return [Symbol] playlist type of playlist at index, one of :playlist, :start_folder, :end_folder, :placeholder
52
+ # @method playlistcontainer_playlist_type(container, index)
8
53
  attach_function :playlistcontainer_playlist_type, [ PlaylistContainer, :int ], :playlist_type
9
- attach_function :playlistcontainer_playlist_folder_name, [ PlaylistContainer, :int, :buffer_out, :int ], :error
54
+
55
+ # Retrieve folder name of a folder in a container.
56
+ #
57
+ # @example
58
+ # Spotify.playlistcontainer_playlist_folder_name(container, index = 0) # => "Summer Playlists"
59
+ #
60
+ # @see #playlistcontainer_num_playlists
61
+ #
62
+ # @note the spotify client appear to constrain the name to 255 chars, so this function does too.
63
+ # @note if index is out of range, the function always return nil.
64
+ #
65
+ # @param [PlaylistContainer] container
66
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
67
+ # @return [String, nil] name of the folder as a string, or nil if not a folder, or out of range
68
+ # @method playlistcontainer_playlist_folder_name(container, index)
69
+ attach_function :playlistcontainer_playlist_folder_name, [ PlaylistContainer, :int, :buffer_out, :int ], APIError do |container, index|
70
+ folder_name = with_string_buffer(255) do |folder_name_buffer, size|
71
+ sp_playlistcontainer_playlist_folder_name(container, index, folder_name_buffer, size)
72
+ end
73
+
74
+ folder_name unless folder_name.empty?
75
+ end
76
+
77
+ # @note if the index is out of range, the function always return 0.
78
+ # @param [PlaylistContainer] container
79
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
80
+ # @return [Integer] folder id at index
81
+ # @method playlistcontainer_playlist_folder_id(container, index)
10
82
  attach_function :playlistcontainer_playlist_folder_id, [ PlaylistContainer, :int ], :uint64
83
+
84
+ # Add a new playlist to the end of the container.
85
+ #
86
+ # @note the name must not constist of only spaces, and it must be shorter than 256 bytes.
87
+ # @param [PlaylistContainer] container
88
+ # @param [String] playlist_name name of the playlist
89
+ # @return [Playlist, nil] the new playlist, or nil if creation failed
90
+ # @method playlistcontainer_add_new_playlist(container, playlist_name)
11
91
  attach_function :playlistcontainer_add_new_playlist, [ PlaylistContainer, UTF8String ], Playlist
92
+
93
+ # Add an existing playlist to the end of the container.
94
+ #
95
+ # @param [PlaylistContainer] container
96
+ # @param [Link] link link to a playlist
97
+ # @return [Playlist, nil] the playlist, or nil if the playlist already exists, or if the link was not a valid playlist link
98
+ # @method playlistcontainer_add_playlist(container, link)
12
99
  attach_function :playlistcontainer_add_playlist, [ PlaylistContainer, Link ], Playlist
13
- attach_function :playlistcontainer_remove_playlist, [ PlaylistContainer, :int ], :error
14
- attach_function :playlistcontainer_move_playlist, [ PlaylistContainer, :int, :int, :bool ], :error
15
- attach_function :playlistcontainer_add_folder, [ PlaylistContainer, :int, UTF8String ], :error
100
+
101
+ # Remove a playlist from a container.
102
+ #
103
+ # @note if you remove a folder marker, remove the other corresponding (start or stop) marker
104
+ # as well, or the playlist will be left in an inconsistent state.
105
+ #
106
+ # @note if the index is out of range, the function always return an error.
107
+ # @param [PlaylistContainer] container
108
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
109
+ # @return [Symbol] error code
110
+ # @method playlistcontainer_remove_playlist(container, index)
111
+ attach_function :playlistcontainer_remove_playlist, [ PlaylistContainer, :int ], APIError
112
+
113
+ # Move a playlist to another position in the container.
114
+ #
115
+ # @note if the index is out of range, the function always return an error.
116
+ # @param [PlaylistContainer] container
117
+ # @param [Integer] index number between 0...{#playlistcontainer_num_playlists}
118
+ # @param [Integer] new_position
119
+ # @param [Boolean] dry_run do not move the playlist, only check if it is possible
120
+ # @return [Symbol] error code
121
+ # @method playlistcontainer_move_playlist(container, index, new_position, dry_run)
122
+ attach_function :playlistcontainer_move_playlist, [ PlaylistContainer, :int, :int, :bool ], APIError
123
+
124
+ # Create a new folder in the container.
125
+ #
126
+ # This creates a start_folder marker, and an end_folder marker right after it, at
127
+ # specified index.
128
+ #
129
+ # @note you cannot rename folders, if you want to do so you have to destroy the folder and recreate it
130
+ # @param [PlaylistContainer] container
131
+ # @param [Integer] index number between 0..{#playlistcontainer_num_playlists}
132
+ # @param [String] folder_name
133
+ # @method playlistcontainer_add_folder(container, index, folder_name)
134
+ attach_function :playlistcontainer_add_folder, [ PlaylistContainer, :int, UTF8String ], APIError
135
+
136
+ # @param [PlaylistContainer] container
137
+ # @return [User] owner of the container
138
+ # @method playlistcontainer_owner(container)
16
139
  attach_function :playlistcontainer_owner, [ PlaylistContainer ], User
140
+
141
+ # @param [PlaylistContainer] container
142
+ # @return [Boolean] true if the container is loaded
143
+ # @method playlistcontainer_is_loaded(container)
17
144
  attach_function :playlistcontainer_is_loaded, [ PlaylistContainer ], :bool
18
- attach_function :playlistcontainer_get_unseen_tracks, [ PlaylistContainer, Playlist, :array, :int ], :int
145
+
146
+ # Number of new tracks in playlist since {#playlistcontainer_clear_unseen_tracks} was called.
147
+ #
148
+ # @example number of unseen tracks in playlist
149
+ # Spotify.playlistcontainer_get_unseen_tracks(container, playlist) # => [#<Spotify::Track::Retaining address=0x103a36c10>…
150
+ #
151
+ # @note if the playlist is not in the container, this function always return an empty array.
152
+ #
153
+ # @param [PlaylistContainer] container
154
+ # @param [Playlist] playlist
155
+ # @return [Array<Track>] an array of unseen tracks
156
+ # @method playlistcontainer_get_unseen_tracks(container, playlist)
157
+ attach_function :playlistcontainer_get_unseen_tracks, [ PlaylistContainer, Playlist, :array, :int ], :int do |container, playlist|
158
+ count = sp_playlistcontainer_get_unseen_tracks(container, playlist, nil, 0)
159
+ tracks = with_buffer(Spotify::Track, size: count) do |tracks_buffer|
160
+ sp_playlistcontainer_get_unseen_tracks(container, playlist, tracks_buffer, count)
161
+ tracks_buffer.read_array_of_pointer(count).map do |pointer|
162
+ Spotify::Track.retaining_class.from_native(pointer, nil)
163
+ end
164
+ end
165
+
166
+ tracks || []
167
+ end
168
+
169
+ # Clear unseen tracks for a playlist on a container
170
+ #
171
+ # This will cause the next{#playlistcontainer_get_unseen_tracks} call to return 0.
172
+ #
173
+ # @param [PlaylistContainer] container
174
+ # @param [Playlist] playlist
175
+ # @return [Integer] 0 on success, and -1 on failure
176
+ # @method playlistcontainer_clear_unseen_tracks(container, playlist)
19
177
  attach_function :playlistcontainer_clear_unseen_tracks, [ PlaylistContainer, Playlist ], :int
20
- attach_function :playlistcontainer_add_ref, [ PlaylistContainer ], :error
21
- attach_function :playlistcontainer_release, [ PlaylistContainer ], :error
178
+
179
+ attach_function :playlistcontainer_add_ref, [ PlaylistContainer ], APIError
180
+ attach_function :playlistcontainer_release, [ PlaylistContainer ], APIError
22
181
  end
23
182
  end