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.



39
40
41
42
43
44
45
46
47
48
# File 'lib/dacpclient/client.rb', line 39

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



62
63
64
65
66
# File 'lib/dacpclient/client.rb', line 62

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.



30
31
32
# File 'lib/dacpclient/client.rb', line 30

def host
  @host
end

#hsgidObject

Returns the value of attribute hsgid.



28
29
30
# File 'lib/dacpclient/client.rb', line 28

def hsgid
  @hsgid
end

#nameObject (readonly)

Returns the value of attribute name.



30
31
32
# File 'lib/dacpclient/client.rb', line 30

def name
  @name
end

#portObject (readonly)

Returns the value of attribute port.



30
31
32
# File 'lib/dacpclient/client.rb', line 30

def port
  @port
end

#session_idObject (readonly)

Returns the value of attribute session_id.



30
31
32
# File 'lib/dacpclient/client.rb', line 30

def session_id
  @session_id
end

Instance Method Details

#albums(db = default_db) ⇒ Object



278
279
280
281
282
283
# File 'lib/dacpclient/client.rb', line 278

def albums(db = default_db)
  url = "databases/#{db.item_id}/groups"
  meta = 'dmap.itemname,dmap.itemid,dmap.persistentid,daap.songartist,daap.songalbumartist'
  query = "('daap.songartist!:'+('com.apple.itunes.extended-media-kind:1','com.apple.itunes.extended-media-kind:32'))"
  do_action(url, meta: meta, type: 'music', :'group-type' => 'albums', sort: 'artist', :'include-sort-headers' => 1, query: query, clean_url: true, model: Albums).items
end

#artists(db = default_db) ⇒ Object



271
272
273
274
275
276
# File 'lib/dacpclient/client.rb', line 271

def artists(db = default_db)
  url = "databases/#{db.item_id}/groups"
  meta = 'dmap.itemname,dmap.itemid,dmap.persistentid,daap.songartist,daap.groupalbumcount,daap.songartistid'
  query = "('daap.songartist!:'+('com.apple.itunes.extended-media-kind:1','com.apple.itunes.extended-media-kind:32'))"
  do_action(url, meta: meta, type: 'music', :'group-type' => 'artists', sort: 'album', :'include-sort-headers' => 1, query: query, clean_url: true, model: Artists).items
end

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



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

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



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

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

#content_codesObject



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

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

#ctrl_intObject



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

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

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



149
150
151
# File 'lib/dacpclient/client.rb', line 149

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

#databasesObject



203
204
205
206
207
208
209
# File 'lib/dacpclient/client.rb', line 203

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



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

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

#default_playlist(db = default_db) ⇒ Object



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

def default_playlist(db = default_db)
  playlists(db).find(&:base_playlist?)
end

#list_queueObject



199
200
201
# File 'lib/dacpclient/client.rb', line 199

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

#loginObject



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/dacpclient/client.rb', line 78

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



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

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

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



234
235
236
# File 'lib/dacpclient/client.rb', line 234

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

#pair(pin) ⇒ Object



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

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

#pair_and_login(pin = nil) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/dacpclient/client.rb', line 90

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



211
212
213
214
215
216
217
218
219
# File 'lib/dacpclient/client.rb', line 211

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



153
154
155
156
157
158
159
160
# File 'lib/dacpclient/client.rb', line 153

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



119
120
121
122
# File 'lib/dacpclient/client.rb', line 119

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

#queue(id) ⇒ Object



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

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

#repeatObject



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

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

#repeat=(repeatstate) ⇒ Object



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

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

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



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
266
267
268
269
# File 'lib/dacpclient/client.rb', line 238

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.item_id}/containers/#{container.item_id}/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=



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

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

#serverinfoObject



74
75
76
# File 'lib/dacpclient/client.rb', line 74

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

#shuffleObject



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

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

#shuffle=(shufflestate) ⇒ Object



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

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

#status(wait = false) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/dacpclient/client.rb', line 126

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



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

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

#volumeObject



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

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

#volume=(volume) ⇒ Object



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

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