spotify 12.2.0 → 12.3.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 (80) hide show
  1. data/.gitignore +3 -1
  2. data/.rspec +5 -0
  3. data/CHANGELOG.md +45 -27
  4. data/Gemfile +4 -0
  5. data/README.markdown +52 -19
  6. data/Rakefile +16 -7
  7. data/lib/spotify.rb +109 -8
  8. data/lib/spotify/api.rb +61 -0
  9. data/lib/spotify/api/album.rb +14 -0
  10. data/lib/spotify/api/album_browse.rb +18 -0
  11. data/lib/spotify/api/artist.rb +10 -0
  12. data/lib/spotify/api/artist_browse.rb +23 -0
  13. data/lib/spotify/api/error.rb +6 -0
  14. data/lib/spotify/api/image.rb +16 -0
  15. data/lib/spotify/api/inbox.rb +9 -0
  16. data/lib/spotify/api/link.rb +25 -0
  17. data/lib/spotify/api/playlist.rb +39 -0
  18. data/lib/spotify/api/playlist_container.rb +23 -0
  19. data/lib/spotify/api/search.rb +27 -0
  20. data/lib/spotify/api/session.rb +46 -0
  21. data/lib/spotify/api/toplist_browse.rb +17 -0
  22. data/lib/spotify/api/track.rb +26 -0
  23. data/lib/spotify/api/user.rb +10 -0
  24. data/lib/spotify/defines.rb +109 -0
  25. data/lib/spotify/error.rb +62 -0
  26. data/lib/spotify/managed_pointer.rb +90 -0
  27. data/lib/spotify/objects.rb +16 -0
  28. data/lib/spotify/objects/album.rb +5 -0
  29. data/lib/spotify/objects/album_browse.rb +5 -0
  30. data/lib/spotify/objects/artist.rb +5 -0
  31. data/lib/spotify/objects/artist_browse.rb +5 -0
  32. data/lib/spotify/objects/image.rb +5 -0
  33. data/lib/spotify/objects/inbox.rb +5 -0
  34. data/lib/spotify/objects/link.rb +5 -0
  35. data/lib/spotify/objects/playlist.rb +5 -0
  36. data/lib/spotify/objects/playlist_container.rb +5 -0
  37. data/lib/spotify/objects/search.rb +5 -0
  38. data/lib/spotify/objects/session.rb +20 -0
  39. data/lib/spotify/objects/toplist_browse.rb +5 -0
  40. data/lib/spotify/objects/track.rb +5 -0
  41. data/lib/spotify/objects/user.rb +5 -0
  42. data/lib/spotify/structs.rb +46 -0
  43. data/lib/spotify/structs/audio_buffer_stats.rb +10 -0
  44. data/lib/spotify/structs/audio_format.rb +12 -0
  45. data/lib/spotify/structs/offline_sync_status.rb +24 -0
  46. data/lib/spotify/structs/playlist_callbacks.rb +32 -0
  47. data/lib/spotify/structs/playlist_container_callbacks.rb +14 -0
  48. data/lib/spotify/structs/session_callbacks.rb +48 -0
  49. data/lib/spotify/structs/session_config.rb +64 -0
  50. data/lib/spotify/structs/subscribers.rb +31 -0
  51. data/lib/spotify/types.rb +3 -0
  52. data/lib/spotify/types/image_id.rb +5 -0
  53. data/lib/spotify/types/nul_string.rb +51 -0
  54. data/lib/spotify/types/utf8_string.rb +24 -28
  55. data/lib/spotify/util.rb +36 -0
  56. data/lib/spotify/version.rb +7 -2
  57. data/spec/api-linux.xml +1887 -0
  58. data/spec/api-mac.xml +1886 -0
  59. data/spec/spec_helper.rb +20 -0
  60. data/spec/spotify/api_spec.rb +62 -0
  61. data/spec/spotify/defines_spec.rb +22 -0
  62. data/spec/spotify/enums_spec.rb +9 -0
  63. data/spec/spotify/managed_pointer_spec.rb +75 -0
  64. data/spec/spotify/spotify_spec.rb +69 -0
  65. data/spec/spotify/structs/session_config_spec.rb +20 -0
  66. data/spec/spotify/structs/struct_spec.rb +34 -0
  67. data/spec/spotify/structs/subscribers_spec.rb +31 -0
  68. data/spec/spotify/structs_spec.rb +19 -0
  69. data/spec/spotify/types/image_id_spec.rb +44 -0
  70. data/spec/spotify/types/nul_string_spec.rb +31 -0
  71. data/spec/spotify/types/utf8_string_spec.rb +24 -0
  72. data/spec/support/hook_spotify.rb +37 -0
  73. data/spec/support/spotify_util.rb +17 -0
  74. data/spotify.gemspec +6 -11
  75. metadata +99 -26
  76. data/lib/spotify/error_wrappers.rb +0 -165
  77. data/lib/spotify/functions.rb +0 -755
  78. data/lib/spotify/gc_wrappers.rb +0 -105
  79. data/lib/spotify/types/pointer.rb +0 -59
  80. data/spec/spotify_spec.rb +0 -467
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+ module Spotify
3
+ # An autopointer base class for Spotify pointers.
4
+ #
5
+ # It contains a default implementation for release, retain,
6
+ # and a default constructor. When the underlying pointer is
7
+ # garbage collected, the pointer is released automatically.
8
+ #
9
+ # This class is never instantiated; instead you’ll be dealing
10
+ # with any of it’s subclasses.
11
+ #
12
+ # @note The default ManagedPointer does not retain its pointer after initialization,
13
+ # but provides a class that does through {.retaining_class}. This is better as
14
+ # it allows you to err on the side of segfaulting, instead of leaking memory.
15
+ #
16
+ # @api private
17
+ class ManagedPointer < FFI::AutoPointer
18
+ class << self
19
+ # Releases the given pointer if it is not null.
20
+ #
21
+ # This method derives the release method from the class name.
22
+ #
23
+ # @param [FFI::Pointer] pointer
24
+ def release(pointer)
25
+ unless pointer.null?
26
+ $stderr.puts "Spotify.#{type}_release(#{pointer.inspect})" if $DEBUG
27
+ Spotify.public_send("#{type}_release", pointer)
28
+ end
29
+ end
30
+
31
+ # Retains the given pointer if it is not null.
32
+ #
33
+ # This method derives the retain method from the class name.
34
+ #
35
+ # @param [FFI::Pointer] pointer
36
+ def retain(pointer)
37
+ unless pointer.null?
38
+ $stderr.puts "Spotify.#{type}_add_ref(#{pointer.inspect})" if $DEBUG
39
+ Spotify.public_send("#{type}_add_ref", pointer)
40
+ end
41
+ end
42
+
43
+ # @return [self] subclass that retains its pointer on initialization.
44
+ def retaining_class
45
+ @klass ||= Class.new(self) do
46
+ def initialize(*args, &block)
47
+ superclass = self.class.superclass
48
+ superclass.instance_method(:initialize).bind(self).call(*args, &block)
49
+ superclass.retain(self)
50
+ end
51
+
52
+ class << self
53
+ alias_method :==, :<=
54
+
55
+ # @return [String] delegates to the superclass.
56
+ def name
57
+ superclass.name
58
+ end
59
+
60
+ # @return [String] delegates to the superclass.
61
+ def to_s
62
+ superclass.to_s
63
+ end
64
+
65
+ # @return [String] string representation of object
66
+ def inspect
67
+ "#{superclass}<retaining>"
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ alias_method :==, :>=
74
+
75
+ protected
76
+
77
+ # @return [#to_s] the spotify type of this pointer.
78
+ def type
79
+ name.split('::')[-1].downcase
80
+ end
81
+ end
82
+
83
+ # @return [String] string representation of self.
84
+ def inspect
85
+ "#<#{self.class} address=0x%x>" % address
86
+ end
87
+
88
+ alias_method :to_s, :inspect
89
+ end
90
+ end
@@ -0,0 +1,16 @@
1
+ require 'spotify/managed_pointer'
2
+
3
+ require 'spotify/objects/album'
4
+ require 'spotify/objects/album_browse'
5
+ require 'spotify/objects/artist'
6
+ require 'spotify/objects/artist_browse'
7
+ require 'spotify/objects/image'
8
+ require 'spotify/objects/inbox'
9
+ require 'spotify/objects/link'
10
+ require 'spotify/objects/playlist'
11
+ require 'spotify/objects/playlist_container'
12
+ require 'spotify/objects/search'
13
+ require 'spotify/objects/session'
14
+ require 'spotify/objects/toplist_browse'
15
+ require 'spotify/objects/track'
16
+ require 'spotify/objects/user'
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Album < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class AlbumBrowse < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Artist < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class ArtistBrowse < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Image < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Inbox < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Link < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Playlist < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See the {ManagedPointer} for documentation.
3
+ class PlaylistContainer < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Search < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module Spotify
2
+ # Session pointers are special in that they are created once,
3
+ # never increases or decreases in reference count and should
4
+ # never be released.
5
+ #
6
+ # See the {ManagedPointer} for documentation.
7
+ class Session < ManagedPointer
8
+ class << self
9
+ undef :retaining_class
10
+ end
11
+
12
+ # After initialization sets autorelease to false.
13
+ #
14
+ # @param (see ManagedPointer)
15
+ def initialize(*)
16
+ super
17
+ self.autorelease = false
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class ToplistBrowse < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class Track < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ # See {ManagedPointer} for documentation.
3
+ class User < ManagedPointer
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ module Spotify
2
+ # Spotify::Struct is a regular FFI::Struct, but with type
3
+ # checking that happens in the Spotify::API namespace, and
4
+ # it also allows you to initialize structs with a hash.
5
+ class Struct < FFI::Struct
6
+ # This is used by FFI to do type lookups when creating the
7
+ # struct layout. By overriding this we can trick FFI into
8
+ # looking up types in the right location.
9
+ #
10
+ # @return [Spotify::API]
11
+ def self.enclosing_module
12
+ Spotify::API
13
+ end
14
+
15
+ # When initialized with a hash, assigns each value of the
16
+ # hash to the newly created struct before returning.
17
+ #
18
+ # If not given a hash, it behaves exactly as FFI::Struct.
19
+ #
20
+ # @param [#each_pair, FFI::Pointer, nil] pointer
21
+ # @param [Array<Symbol, Type>] layout
22
+ def initialize(pointer = nil, *layout, &block)
23
+ if pointer.respond_to?(:each_pair)
24
+ options = pointer
25
+ pointer = nil
26
+ else
27
+ options = {}
28
+ end
29
+
30
+ super(pointer, *layout, &block)
31
+
32
+ options.each_pair do |key, value|
33
+ self[key] = value
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ require 'spotify/structs/audio_buffer_stats'
40
+ require 'spotify/structs/audio_format'
41
+ require 'spotify/structs/offline_sync_status'
42
+ require 'spotify/structs/playlist_callbacks'
43
+ require 'spotify/structs/playlist_container_callbacks'
44
+ require 'spotify/structs/session_callbacks'
45
+ require 'spotify/structs/session_config'
46
+ require 'spotify/structs/subscribers'
@@ -0,0 +1,10 @@
1
+ module Spotify
2
+ # Spotify::Struct for Audio Buffer Stats.
3
+ #
4
+ # @attr [Fixnum] samples
5
+ # @attr [Fixnum] stutter
6
+ class AudioBufferStats < Spotify::Struct
7
+ layout :samples => :int,
8
+ :stutter => :int
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Spotify
2
+ # Spotify::Struct for Audio Format.
3
+ #
4
+ # @attr [:sampletype] sample_type
5
+ # @attr [Fixnum] sample_rate
6
+ # @attr [Fixnum] channels
7
+ class AudioFormat < Spotify::Struct
8
+ layout :sample_type => :sampletype,
9
+ :sample_rate => :int,
10
+ :channels => :int
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module Spotify
2
+ # Spotify::Struct for Offline Sync Status
3
+ #
4
+ # @attr [Fixnum] queued_tracks
5
+ # @attr [Fixnum] queued_bytes
6
+ # @attr [Fixnum] done_tracks
7
+ # @attr [Fixnum] done_bytes
8
+ # @attr [Fixnum] copied_tracks
9
+ # @attr [Fixnum] copied_bytes
10
+ # @attr [Fixnum] willnotcopy_tracks
11
+ # @attr [Fixnum] error_tracks
12
+ # @attr [Boolean] syncing
13
+ class OfflineSyncStatus < Spotify::Struct
14
+ layout :queued_tracks => :int,
15
+ :queued_bytes => :uint64,
16
+ :done_tracks => :int,
17
+ :done_bytes => :uint64,
18
+ :copied_tracks => :int,
19
+ :copied_bytes => :uint64,
20
+ :willnotcopy_tracks => :int,
21
+ :error_tracks => :int,
22
+ :syncing => :bool
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ module Spotify
2
+ # Spotify::Struct for Playlist callbacks.
3
+ #
4
+ # @attr [callback(Playlist, :array, :int, :int, :userdata):void] tracks_added
5
+ # @attr [callback(Playlist, :array, :int, :userdata):void] tracks_removed
6
+ # @attr [callback(Playlist, :array, :int, :int, :userdata):void] tracks_moved
7
+ # @attr [callback(Playlist, :userdata):void] playlist_renamed
8
+ # @attr [callback(Playlist, :userdata):void] playlist_state_changed
9
+ # @attr [callback(Playlist, :bool, :userdata):void] playlist_update_in_progress
10
+ # @attr [callback(Playlist, :userdata):void] playlist_metadata_updated
11
+ # @attr [callback(Playlist, :int, User, :int, :userdata):void] track_created_changed
12
+ # @attr [callback(Playlist, :int, :bool, :userdata):void] track_seen_changed
13
+ # @attr [callback(Playlist, UTF8String, :userdata):void] description_changed
14
+ # @attr [callback(Playlist, ImageID, :userdata):void] image_changed
15
+ # @attr [callback(Playlist, :int, UTF8String, :userdata):void] track_message_changed
16
+ # @attr [callback(Playlist, :userdata):void] subscribers_changed
17
+ class PlaylistCallbacks < Spotify::Struct
18
+ layout :tracks_added => callback([ Playlist.retaining_class, :array, :int, :int, :userdata ], :void),
19
+ :tracks_removed => callback([ Playlist.retaining_class, :array, :int, :userdata ], :void),
20
+ :tracks_moved => callback([ Playlist.retaining_class, :array, :int, :int, :userdata ], :void),
21
+ :playlist_renamed => callback([ Playlist.retaining_class, :userdata ], :void),
22
+ :playlist_state_changed => callback([ Playlist.retaining_class, :userdata ], :void),
23
+ :playlist_update_in_progress => callback([ Playlist.retaining_class, :bool, :userdata ], :void),
24
+ :playlist_metadata_updated => callback([ Playlist.retaining_class, :userdata ], :void),
25
+ :track_created_changed => callback([ Playlist.retaining_class, :int, User.retaining_class, :int, :userdata ], :void),
26
+ :track_seen_changed => callback([ Playlist.retaining_class, :int, :bool, :userdata ], :void),
27
+ :description_changed => callback([ Playlist.retaining_class, UTF8String, :userdata ], :void),
28
+ :image_changed => callback([ Playlist.retaining_class, ImageID, :userdata ], :void),
29
+ :track_message_changed => callback([ Playlist.retaining_class, :int, UTF8String, :userdata ], :void),
30
+ :subscribers_changed => callback([ Playlist.retaining_class, :userdata ], :void)
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ module Spotify
2
+ # Spotify::Struct for the PlaylistContainer.
3
+ #
4
+ # @attr [callback(PlaylistContainer, Playlist, :int, :userdata):void] playlist_added
5
+ # @attr [callback(PlaylistContainer, Playlist, :int, :userdata):void] playlist_removed
6
+ # @attr [callback(PlaylistContainer, Playlist, :int, :int, :userdata):void] playlist_moved
7
+ # @attr [callback(PlaylistContainer, :userdata):void] container_loaded
8
+ class PlaylistContainerCallbacks < Spotify::Struct
9
+ layout :playlist_added, callback([ PlaylistContainer.retaining_class, Playlist.retaining_class, :int, :userdata ], :void),
10
+ :playlist_removed, callback([ PlaylistContainer.retaining_class, Playlist.retaining_class, :int, :userdata ], :void),
11
+ :playlist_moved, callback([ PlaylistContainer.retaining_class, Playlist.retaining_class, :int, :int, :userdata ], :void),
12
+ :container_loaded, callback([ PlaylistContainer.retaining_class, :userdata ], :void)
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Spotify
2
+ # Spotify::Struct for Session callbacks.
3
+ #
4
+ # @attr [callback(Session, :error):void] logged_in
5
+ # @attr [callback(Session):void] logged_out
6
+ # @attr [callback(Session):void] metadata_updated
7
+ # @attr [callback(Session, :error):void] connection_error
8
+ # @attr [callback(Session, UTF8String):void] message_to_user
9
+ # @attr [callback(Session):void] notify_main_thread
10
+ # @attr [callback(Session, AudioFormat, :frames, :int):int] music_delivery
11
+ # @attr [callback(Session):void] play_token_lost
12
+ # @attr [callback(Session, UTF8String):void] log_message
13
+ # @attr [callback(Session):void] end_of_track
14
+ # @attr [callback(Session, :error):void] streaming_error
15
+ # @attr [callback(Session):void] userinfo_updated
16
+ # @attr [callback(Session):void] start_playback
17
+ # @attr [callback(Session):void] stop_playback
18
+ # @attr [callback(Session, AudioBufferStats):void] get_audio_buffer_stats
19
+ # @attr [callback(Session):void] offline_status_updated
20
+ # @attr [callback(Session, :error):void] offline_error
21
+ # @attr [callback(Session, :string):void] credentials_blob_updated
22
+ # @attr [callback(Session):void] connectionstate_updated
23
+ # @attr [callback(Session, :error):void] scrobble_error
24
+ # @attr [callback(Session, :bool):void] private_session_mode_changed
25
+ class SessionCallbacks < Spotify::Struct
26
+ layout :logged_in => callback([ Session, :error ], :void),
27
+ :logged_out => callback([ Session ], :void),
28
+ :metadata_updated => callback([ Session ], :void),
29
+ :connection_error => callback([ Session, :error ], :void),
30
+ :message_to_user => callback([ Session, UTF8String ], :void),
31
+ :notify_main_thread => callback([ Session ], :void),
32
+ :music_delivery => callback([ Session, AudioFormat, :frames, :int ], :int),
33
+ :play_token_lost => callback([ Session ], :void),
34
+ :log_message => callback([ Session, UTF8String ], :void),
35
+ :end_of_track => callback([ Session ], :void),
36
+ :streaming_error => callback([ Session, :error ], :void),
37
+ :userinfo_updated => callback([ Session ], :void),
38
+ :start_playback => callback([ Session ], :void),
39
+ :stop_playback => callback([ Session ], :void),
40
+ :get_audio_buffer_stats => callback([ Session, AudioBufferStats ], :void),
41
+ :offline_status_updated => callback([ Session ], :void),
42
+ :offline_error => callback([ Session, :error ], :void),
43
+ :credentials_blob_updated => callback([ Session, :string ], :void),
44
+ :connectionstate_updated => callback([ Session ], :void),
45
+ :scrobble_error => callback([ Session, :error ], :void),
46
+ :private_session_mode_changed => callback([ Session, :bool ], :void)
47
+ end
48
+ end
@@ -0,0 +1,64 @@
1
+ module Spotify
2
+ # Spotify::Struct for Session configuration.
3
+ #
4
+ # @attr [Fixnum] api_version
5
+ # @attr [StringPointer] cache_location
6
+ # @attr [StringPointer] settings_location
7
+ # @attr [size_t] application_key_size
8
+ # @attr [StringPointer] user_agent
9
+ # @attr [StructPointer] callbacks
10
+ # @attr [Pointer] userdata
11
+ # @attr [Fixnum] dont_save_metadata_for_playlists
12
+ # @attr [Fixnum] initially_unload_playlists
13
+ # @attr [Boolean] initially_unload_playlists
14
+ # @attr [StringPointer] device_id
15
+ # @attr [StringPointer] proxy
16
+ # @attr [StringPointer] proxy_username
17
+ # @attr [StringPointer] proxy_password
18
+ # @attr [StringPointer] ca_certs_filename
19
+ # @attr [StringPointer] tracefile
20
+ class SessionConfig < Spotify::Struct
21
+ it = {}
22
+ it[:api_version] = :int
23
+ it[:cache_location] = NULString
24
+ it[:settings_location] = NULString
25
+ it[:application_key] = :pointer
26
+ it[:application_key_size] = :size_t
27
+ it[:user_agent] = NULString
28
+ it[:callbacks] = SessionCallbacks.by_ref
29
+ it[:userdata] = :userdata
30
+ it[:compress_playlists] = :bool
31
+ it[:dont_save_metadata_for_playlists] = :bool
32
+ it[:initially_unload_playlists] = :bool
33
+ it[:device_id] = NULString
34
+ it[:proxy] = NULString
35
+ it[:proxy_username] = NULString
36
+ it[:proxy_password] = NULString
37
+ it[:ca_certs_filename] = NULString if Spotify::API.linux?
38
+ it[:tracefile] = NULString
39
+ layout(it)
40
+
41
+ # Overridden for some keys for convenience.
42
+ #
43
+ # @example setting application key
44
+ # struct[:application_key] = "application key"
45
+ # # ^ also sets :application_key_size
46
+ #
47
+ # @param [Symbol] key
48
+ # @param [Object] value
49
+ def []=(key, value)
50
+ case key
51
+ when :application_key
52
+ if value.is_a?(String)
53
+ pointer = FFI::MemoryPointer.new(:char, value.bytesize)
54
+ pointer.write_bytes(value)
55
+ super(key, pointer)
56
+ self[:application_key_size] = pointer.size
57
+ else
58
+ super
59
+ end
60
+ else super
61
+ end
62
+ end
63
+ end
64
+ end