Class: DACPClient::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/dacpclient/client.rb

Overview

The Client class handles communication with the server

Constant Summary collapse

DEFAULT_HEADERS =
{
  'Viewer-Only-Client' => '1',
  'Accept-Encoding' => 'gzip',
  'Connection' => 'keep-alive',
  'User-Agent' => 'RubyDACPClient/' + VERSION
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, host = 'localhost', port = 3689) ⇒ Client

Returns a new instance of Client.



35
36
37
38
39
40
41
42
43
44
# File 'lib/dacpclient/client.rb', line 35

def initialize(name, host = 'localhost', port = 3689)
  @name = name
  @host = host
  @port = port

  @session_id = nil
  @hsgid = nil
  @media_revision = 1
  setup_connection
end

Instance Attribute Details

#guidObject



58
59
60
61
62
# File 'lib/dacpclient/client.rb', line 58

def guid
  return @guid unless @guid.nil?
  d = Digest::SHA2.hexdigest(@name)
  d[0..15].upcase
end

#hostObject (readonly)

Returns the value of attribute host.



26
27
28
# File 'lib/dacpclient/client.rb', line 26

def host
  @host
end

#hsgidObject

Returns the value of attribute hsgid.



24
25
26
# File 'lib/dacpclient/client.rb', line 24

def hsgid
  @hsgid
end

#nameObject (readonly)

Returns the value of attribute name.



26
27
28
# File 'lib/dacpclient/client.rb', line 26

def name
  @name
end

#portObject (readonly)

Returns the value of attribute port.



26
27
28
# File 'lib/dacpclient/client.rb', line 26

def port
  @port
end

#session_idObject (readonly)

Returns the value of attribute session_id.



26
27
28
# File 'lib/dacpclient/client.rb', line 26

def session_id
  @session_id
end

Instance Method Details

#artwork(database, id, width = 320, height = 320) ⇒ Object



225
226
227
228
# File 'lib/dacpclient/client.rb', line 225

def artwork(database, id, width = 320, height = 320)
  url = "databases/#{database}/items/#{id}/extra_data/artwork"
  do_action(url, { mw: width, mh: height }, clean_url: true)
end

#clear_queueObject



191
192
193
# File 'lib/dacpclient/client.rb', line 191

def clear_queue
  do_action('playqueue-edit', command: 'clear')
end

#content_codesObject



102
103
104
# File 'lib/dacpclient/client.rb', line 102

def content_codes
  do_action('content-codes', clean_url: true)
end

#ctrl_intObject



176
177
178
# File 'lib/dacpclient/client.rb', line 176

def ctrl_int
  do_action('ctrl-int', clean_url: true)
end

#cue(command, query, index = 0) ⇒ Object



145
146
147
# File 'lib/dacpclient/client.rb', line 145

def cue(command, query, index = 0)
  do_action(:cue, command: command, query: query, index: index)
end

#databasesObject



199
200
201
202
203
204
205
# File 'lib/dacpclient/client.rb', line 199

def databases
  meta = %w(dmap.itemname dmap.itemcount dmap.itemid dmap.persistentid
            daap.baseplaylist com.apple.itunes.special-playlist
            com.apple.itunes.smart-playlist com.apple.itunes.saved-genius
            dmap.parentcontainerid dmap.editcommandssupported).join(',')
  do_action('databases', clean_url: true, meta: meta, model: Databases)
end

#default_dbObject



217
218
219
# File 'lib/dacpclient/client.rb', line 217

def default_db
  databases.items.find { |item| item.default_db == 1 }
end

#default_playlist(db = default_db) ⇒ Object



221
222
223
# File 'lib/dacpclient/client.rb', line 221

def default_playlist(db = default_db)
  playlists(db).find { |item| item.base_playlist? }
end

#list_queueObject



195
196
197
# File 'lib/dacpclient/client.rb', line 195

def list_queue
  do_action('playqueue-contents', model: PlayQueue)
end

#loginObject



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/dacpclient/client.rb', line 74

def 
  response = nil
  if @hsgid.nil?
    pairing_guid = '0x' + guid
    response = do_action(:login,  :'pairing-guid' => pairing_guid)
  else
    response = do_action(:login, hasFP: 1)
  end
  @session_id = response[:mlid]
  response
end

#logoutObject



180
181
182
183
184
# File 'lib/dacpclient/client.rb', line 180

def logout
  do_action(:logout)
  @media_revision = 1
  @session_id = nil
end

#now_playing_artwork(width = 320, height = 320) ⇒ Object



230
231
232
# File 'lib/dacpclient/client.rb', line 230

def now_playing_artwork(width = 320, height = 320)
  do_action(:nowplayingartwork, mw: width, mh: height)
end

#pair(pin) ⇒ Object



64
65
66
67
68
# File 'lib/dacpclient/client.rb', line 64

def pair(pin)
  pairingserver = PairingServer.new(name, guid)
  pairingserver.pin = pin
  pairingserver.start
end

#pair_and_login(pin = nil) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/dacpclient/client.rb', line 86

def (pin = nil)
  
rescue DACPForbiddenError, Faraday::ConnectionFailed => e
  pin = 4.times.map { Random.rand(10) } if pin.nil?
  if e.instance_of? DACPForbiddenError
    message = e.result.status
  else
    message = e
  end
  warn "#{message} error: Cannot login, starting pairing process"
  warn "Pincode: #{pin}"
  @host = pair(pin).host
  setup_connection
  retry
end

#playlists(db = default_db) ⇒ Object



207
208
209
210
211
212
213
214
215
# File 'lib/dacpclient/client.rb', line 207

def playlists(db = default_db)
  meta = %w(dmap.itemname dmap.itemcount dmap.itemid dmap.persistentid
            daap.baseplaylist com.apple.itunes.special-playlist
            com.apple.itunes.smart-playlist com.apple.itunes.saved-genius
            dmap.parentcontainerid dmap.editcommandssupported).join(',')
  do_action("databases/#{db.item_id}/containers", clean_url: true,
                                                  meta: meta,
                                                  model: Playlists).items
end

#playspec(playlist, db = default_db) ⇒ Object



149
150
151
152
153
154
155
156
# File 'lib/dacpclient/client.rb', line 149

def playspec(playlist, db = default_db)
  dbspec = "'dmap.persistentid:0x#{db.persistent_id.to_s(16)}'"
  cspec = "'dmap.persistentid:0x#{playlist.persistent_id.to_s(16)}'"
  # don't worry about playing item's from playlists yet..
  # container-item-spec='dmap.containeritemid:%s'
  do_action(:playspec, database_spec: dbspec,
                       container_spec: cspec)
end

#positionObject



115
116
117
118
# File 'lib/dacpclient/client.rb', line 115

def position
  response = do_action(:getproperty, properties: 'dacp.playingtime')
  response.cast? ? (response['cast'] - response['cant']) : 0
end

#queue(id) ⇒ Object



186
187
188
189
# File 'lib/dacpclient/client.rb', line 186

def queue(id)
  do_action('playqueue-edit', command: 'add',
                              query: "\'dmap.itemid:#{id}\'")
end

#repeatObject



158
159
160
161
# File 'lib/dacpclient/client.rb', line 158

def repeat
  response = do_action(:getproperty, properties: 'dacp.repeatstate')
  response[:carp]
end

#repeat=(repeatstate) ⇒ Object



163
164
165
# File 'lib/dacpclient/client.rb', line 163

def repeat=(repeatstate)
  set_property('dacp.repeatstate', repeatstate)
end

#search(search, type = nil, db = default_db, container = default_playlist(default_db)) ⇒ Object



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/dacpclient/client.rb', line 234

def search(search, type = nil, db = default_db,
           container = default_playlist(default_db))
  search = URI.escape(search)
  types = {
    title: 'dmap.itemname',
    artist: 'daap.songartist',
    album: 'daap.songalbum',
    genre: 'daap.songgenre',
    composer: 'daap.songcomposer'
  }
  queries = []
  type = types.keys if type.nil?
  Array(type).each do |t|
    queries << "'#{types[t]}:#{search}'"
  end

  q = queries.join(',')
  q = '(' + q + ')' if queries.length > 1
  meta  = %w(dmap.itemname dmap.itemid com.apple.itunes.has-chapter-data
             daap.songalbum com.apple.itunes.cloud-id dmap.containeritemid
             com.apple.itunes.has-video com.apple.itunes.itms-songid
             com.apple.itunes.extended-media-kind dmap.downloadstatus
             daap.songdisabled daap.songhasbeenplayed daap.songbookmark
             com.apple.itunes.is-hd-video daap.songlongcontentdescription
             daap.songtime daap.songuserplaycount daap.songartist
             com.apple.itunes.content-rating daap.songdatereleased
             com.apple.itunes.movie-info-xml daap.songalbumartist
             com.apple.itunes.extended-media-kind).join(',')
  url = "databases/#{db.miid}/containers/#{container.miid}/items"
  do_action(url, { query: q, type: 'music', sort: 'album', meta: meta,
                   :'include-sort-headers' => 1 }, clean_url: true)
end

#seek(ms) ⇒ Object Also known as: position=



111
112
113
# File 'lib/dacpclient/client.rb', line 111

def seek(ms)
  set_property('dacp.playingtime', ms)
end

#serverinfoObject



70
71
72
# File 'lib/dacpclient/client.rb', line 70

def serverinfo
  do_action('server-info', clean_url: true)
end

#shuffleObject



167
168
169
170
# File 'lib/dacpclient/client.rb', line 167

def shuffle
  response = do_action(:getproperty, properties: 'dmcp.shufflestate')
  response[:cash]
end

#shuffle=(shufflestate) ⇒ Object



172
173
174
# File 'lib/dacpclient/client.rb', line 172

def shuffle=(shufflestate)
  set_property('dmcp.shufflestate', shufflestate)
end

#status(wait = false) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/dacpclient/client.rb', line 122

def status(wait = false)
  revision = wait ? @media_revision : 1
  result = do_action(:playstatusupdate, :'revision-number' => revision,
                                        model: Status)
  @media_revision = result.media_revision
  result
rescue Faraday::Error::TimeoutError => e
  if wait
    retry
  else
    raise e
  end
end

#track_lengthObject



106
107
108
109
# File 'lib/dacpclient/client.rb', line 106

def track_length
  response = do_action(:getproperty, properties: 'dacp.playingtime')
  response.cast? ? response['cast'] : 0
end

#volumeObject



136
137
138
139
# File 'lib/dacpclient/client.rb', line 136

def volume
  response = do_action(:getproperty, properties: 'dmcp.volume')
  response[:cmvo]
end

#volume=(volume) ⇒ Object



141
142
143
# File 'lib/dacpclient/client.rb', line 141

def volume=(volume)
  set_property('dmcp.volume', volume)
end