spotify 12.5.3 → 12.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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