spotify 12.2.0 → 12.3.0

Sign up to get free protection for your applications and to get access to all the features.
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