This repository has been archived by the owner on Aug 6, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
session.rb
175 lines (152 loc) · 5.04 KB
/
session.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# coding: utf-8
require 'singleton'
module Hallon
# The Session is fundamental for all communication with Spotify.
# Pretty much all API calls require you to have established a session
# with Spotify before using them.
#
# @see https://developer.spotify.com/en/libspotify/docs/group__session.html
class Session
# The options Hallon used at {Session#initialize}.
#
# @return [Hash]
attr_reader :options
# Application key used at {Session#initialize}
#
# @return [String]
attr_reader :appkey
# libspotify only allows one session per process.
include Singleton
# Session allows you to define your own callbacks.
include Hallon::Base
# Allows you to create a Spotify session. Subsequent calls to this method
# will return the previous instance, ignoring any passed arguments.
#
# @param (see Session#initialize)
# @see Session#initialize
# @return [Session]
def Session.instance(*args, &block)
@__instance__ ||= new(*args, &block)
end
# Create a new Spotify session.
#
# @param [#to_s] appkey
# @param [Hash] options
# @option options [String] :user_agent ("Hallon") User-Agent to use (length < 256)
# @option options [String] :settings_path ("tmp") where to save settings and user-specific cache
# @option options [String] :cache_path ("") where to save cache files (set to "" to disable)
# @option options [Bool] :load_playlists (true) load playlists into RAM on startup
# @option options [Bool] :compress_playlists (true) compress local copies of playlists
# @option options [Bool] :cache_playlist_metadata (true) cache metadata for playlists locally
# @yield allows you to define handlers for events (see {Hallon::Base#on})
# @raise [ArgumentError] if `options[:user_agent]` is more than 256 characters long
# @raise [Hallon::Error] if `sp_session_create` fails
# @see http://developer.spotify.com/en/libspotify/docs/structsp__session__config.html
def initialize(appkey, options = {}, &block)
@appkey = appkey.to_s
@options = {
:user_agent => "Hallon",
:settings_path => "tmp",
:cache_path => "",
:load_playlists => true,
:compress_playlists => true,
:cache_playlist_metadata => true
}.merge(options)
if @options[:user_agent].bytesize > 255
raise ArgumentError, "User-agent must be less than 256 bytes long"
end
# Set configuration, as well as callbacks
config = Spotify::SessionConfig.new
config[:api_version] = Hallon::API_VERSION
config.application_key = @appkey
@options.each { |(key, value)| config.send(:"#{key}=", value) }
config[:callbacks] = Spotify::SessionCallbacks.new(self, @sp_callbacks = {})
instance_eval(&block) if block_given?
# You pass a pointer to the session pointer to libspotify >:)
FFI::MemoryPointer.new(:pointer) do |p|
Hallon::Error::maybe_raise Spotify::session_create(config, p)
@pointer = p.read_pointer
end
end
# Process pending Spotify events (might fire callbacks).
#
# @return [Fixnum] minimum time until it should be called again
def process_events
FFI::MemoryPointer.new(:int) do |p|
Spotify::session_process_events(@pointer, p)
return p.read_int
end
end
# Process events on each event until the block returns true.
#
# @param [Symbol, ] events
# @return [Hash<Event, Arguments>]
def process_events_on(*events, &block)
notify = new_cond
result = Hash.new do |h, k|
h[k] = []
end
protecting_handlers do
synchronize do
on(:notify_main_thread) do
synchronize { notify.signal }
end
on(*events) do |event, *args|
synchronize do
result[event] << args
notify.signal
end
end
notify.wait_for(1) do
process_events
block.call
end
return result
end
end
end
# Log into Spotify using the given credentials.
#
# @param [String] username
# @param [String] password
# @return [self]
def login(username, password)
Spotify::session_login(@pointer, username, password)
self
end
# Logs out of Spotify. Does nothing if not logged in.
#
# @return [self]
def logout
Spotify::session_logout(@pointer) if logged_in?
self
end
# Retrieve current connection status.
#
# @return [Symbol]
def status
Spotify::session_connectionstate(@pointer)
end
# True if currently logged in.
# @see #status
def logged_in?
status == :logged_in
end
# True if logged out.
# @see #status
def logged_out?
status == :logged_out
end
# True if session has been disconnected.
# @see #status
def disconnected?
status == :disconnected
end
# String representation of the Session.
#
# @return [String]
def to_s
"<#{self.class.name}>"
end
end
end