dacpclient 0.2.11 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +18 -26
- data/bin/dacpclient +31 -18
- data/dacpclient.gemspec +1 -0
- data/lib/dacpclient/browser.rb +1 -1
- data/lib/dacpclient/client.rb +37 -22
- data/lib/dacpclient/faraday/gzip.rb +1 -1
- data/lib/dacpclient/model.rb +4 -0
- data/lib/dacpclient/models/database.rb +11 -0
- data/lib/dacpclient/models/databases.rb +10 -0
- data/lib/dacpclient/models/playlist.rb +1 -0
- data/lib/dacpclient/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0168ee84709980d66f477982404c0d5cddbb2f92
|
4
|
+
data.tar.gz: e105474bc17e7127c0d0f9427219152df7a83d0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 508242daaf50dacc3c003d4e0d033ea0ed06df405dae77ce27d2ab34e3d0199e10a77143a1ab7b0fb1214b210873f5b1c29708616dcba7562109c984142064cc
|
7
|
+
data.tar.gz: f2f2dfd1c2238ae09d217ce4128032bbb174ef2e027042d687c5b8a6c8869ac1493002ee42f6df3dde07274f747fc450064f83da8b43155295d5c725c36e77ae
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
A DACP (iTunes Remote protocol) client written in the wonderful Ruby language.
|
6
6
|
You can use this for controlling iTunes. It uses the same protocol as the iTunes remote iOS app.
|
7
7
|
|
8
|
-
You can control iTunes by connecting and entering a pin
|
8
|
+
You can control iTunes by connecting and entering a pin.
|
9
9
|
|
10
10
|
Look at the [bin/dacpclient](https://github.com/jurriaan/ruby-dacpclient/blob/master/bin/dacpclient) file for an example client.
|
11
11
|
|
@@ -29,33 +29,25 @@ Or install it yourself using:
|
|
29
29
|
|
30
30
|
See [bin/dacpclient](https://github.com/jurriaan/ruby-dacpclient/blob/master/bin/dacpclient)
|
31
31
|
|
32
|
-
|
32
|
+
DACPClient v0.3.0
|
33
33
|
(c) 2014 Jurriaan Pruis <email@jurriaanpruis.nl>
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
help
|
52
|
-
|
53
|
-
## Todo
|
54
|
-
|
55
|
-
- Use bonjour
|
56
|
-
- Add tests
|
57
|
-
- Add more tagdefinitions
|
58
|
-
- Documentation
|
35
|
+
DACPClient commands:
|
36
|
+
dacpclient help # Display all possible commands
|
37
|
+
dacpclient help [COMMAND] # Describe available commands or one specific command
|
38
|
+
dacpclient hostname # Set the hostname
|
39
|
+
dacpclient next # Go to next item
|
40
|
+
dacpclient pause # Pause Playing
|
41
|
+
dacpclient play # Start playing
|
42
|
+
dacpclient play_playlist # Plays a playlist
|
43
|
+
dacpclient playlists # Show the playlists
|
44
|
+
dacpclient playpause # Toggle Playing
|
45
|
+
dacpclient prev # Go to previous item
|
46
|
+
dacpclient status # Shows the status of the DACP server
|
47
|
+
dacpclient stop # Stop playing
|
48
|
+
dacpclient upnext # Show what's up next
|
49
|
+
dacpclient version # Show DACPClient Version
|
50
|
+
dacpclient volume # Get or set volume
|
59
51
|
|
60
52
|
## Contributing
|
61
53
|
|
data/bin/dacpclient
CHANGED
@@ -6,11 +6,13 @@ require 'socket'
|
|
6
6
|
require 'yaml'
|
7
7
|
require 'fileutils'
|
8
8
|
require 'io/console'
|
9
|
+
require 'fuzzy_match'
|
9
10
|
require 'thor'
|
10
11
|
|
11
12
|
# This is the CLI DACP Client. Normally installed as `dacpclient`
|
12
13
|
class CLIClient < Thor
|
13
|
-
package_name
|
14
|
+
package_name 'DACPClient'
|
15
|
+
|
14
16
|
include Thor::Actions
|
15
17
|
def initialize(*)
|
16
18
|
@config = {}
|
@@ -59,21 +61,6 @@ class CLIClient < Thor
|
|
59
61
|
show_status
|
60
62
|
end
|
61
63
|
|
62
|
-
desc :home_sharing, 'Setup Home Sharing (Not fully functional)'
|
63
|
-
def home_sharing
|
64
|
-
puts 'Setting up Home Sharing. Saving Home Sharing GUID to ' + config_file
|
65
|
-
puts "\nPlease enter your Apple ID credentials:"
|
66
|
-
email = ask('Apple ID (e-mail address):').strip
|
67
|
-
password = ask('Password:')
|
68
|
-
guid = @client.setup_home_sharing(email, password)
|
69
|
-
@config['appleid'] = email
|
70
|
-
@config['hsgid'] = guid
|
71
|
-
save_config
|
72
|
-
puts "\n\n"
|
73
|
-
puts "Got your Home Sharing GUID (#{guid}). Logging in.."
|
74
|
-
login
|
75
|
-
end
|
76
|
-
|
77
64
|
desc :hostname, 'Set the hostname'
|
78
65
|
def hostname
|
79
66
|
@config['host'] = ask('Please enter a new hostname to connect to:').strip
|
@@ -125,13 +112,29 @@ class CLIClient < Thor
|
|
125
112
|
playlist_items = @client.playlists
|
126
113
|
puts 'Playlists:'
|
127
114
|
puts '----------'
|
115
|
+
count = 0
|
116
|
+
num = Math.log10(playlist_items.length).floor + 1
|
128
117
|
playlist_items.each do |playlist|
|
129
|
-
|
118
|
+
printf("%#{num}d. ", count += 1) unless playlist.base_playlist?
|
119
|
+
|
130
120
|
puts "#{playlist.name} (#{playlist.count})"
|
131
121
|
end
|
132
122
|
puts
|
133
123
|
end
|
134
124
|
|
125
|
+
desc :play_playlist, 'Plays a playlist'
|
126
|
+
def play_playlist(playlist)
|
127
|
+
login
|
128
|
+
playlists = @client.playlists
|
129
|
+
if playlist =~ /^\d+$/
|
130
|
+
playlist = playlists[playlist.to_i]
|
131
|
+
else
|
132
|
+
fz = FuzzyMatch.new(playlists, read: :name)
|
133
|
+
playlist = fz.find(playlist)
|
134
|
+
end
|
135
|
+
@client.playspec(playlist)
|
136
|
+
end
|
137
|
+
|
135
138
|
desc :upnext, 'Show what\'s up next'
|
136
139
|
def upnext
|
137
140
|
login
|
@@ -183,7 +186,17 @@ class CLIClient < Thor
|
|
183
186
|
puts "DACPClient v#{DACPClient::VERSION}"
|
184
187
|
puts "using DMAPParser v#{DMAPParser::VERSION}"
|
185
188
|
print 'DACPClient and DMAPParser are Copyright (c) '
|
186
|
-
puts "#{Time.now.year} Jurriaan Pruis"
|
189
|
+
puts "#{Time.now.year} Jurriaan Pruis <email@jurriaanpruis.nl>"
|
190
|
+
end
|
191
|
+
|
192
|
+
default_task :banner
|
193
|
+
|
194
|
+
desc :help, 'Display all possible commands'
|
195
|
+
def banner
|
196
|
+
puts "DACPClient v#{DACPClient::VERSION}"
|
197
|
+
puts "(c) #{Time.now.year} Jurriaan Pruis <email@jurriaanpruis.nl>"
|
198
|
+
puts
|
199
|
+
help
|
187
200
|
end
|
188
201
|
|
189
202
|
private
|
data/dacpclient.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_runtime_dependency 'plist', '~> 3.1.0'
|
25
25
|
spec.add_runtime_dependency 'dmapparser', '~> 0.1.0'
|
26
26
|
spec.add_runtime_dependency 'thor', '~> 0.19.1'
|
27
|
+
spec.add_runtime_dependency 'fuzzy_match', '~> 2.0.4'
|
27
28
|
|
28
29
|
spec.add_development_dependency 'yard'
|
29
30
|
spec.add_development_dependency 'redcarpet'
|
data/lib/dacpclient/browser.rb
CHANGED
data/lib/dacpclient/client.rb
CHANGED
@@ -11,6 +11,8 @@ require 'dacpclient/version'
|
|
11
11
|
require 'dacpclient/model'
|
12
12
|
require 'dacpclient/models/status'
|
13
13
|
require 'dacpclient/models/pair_info'
|
14
|
+
require 'dacpclient/models/database'
|
15
|
+
require 'dacpclient/models/databases'
|
14
16
|
require 'dacpclient/models/playlist'
|
15
17
|
require 'dacpclient/models/playlists'
|
16
18
|
require 'dacpclient/models/play_queue_item'
|
@@ -23,9 +25,6 @@ module DACPClient
|
|
23
25
|
attr_writer :guid
|
24
26
|
attr_reader :name, :host, :port, :session_id
|
25
27
|
|
26
|
-
HOME_SHARING_HOST = 'https://homesharing.itunes.apple.com'.freeze
|
27
|
-
HOME_SHARING_PATH = '/WebObjects/MZHomeSharing.woa/wa/getShareIdentifiers'.freeze
|
28
|
-
|
29
28
|
DEFAULT_HEADERS = {
|
30
29
|
'Viewer-Only-Client' => '1',
|
31
30
|
'Accept-Encoding' => 'gzip',
|
@@ -56,19 +55,6 @@ module DACPClient
|
|
56
55
|
alias_method :next, :nextitem
|
57
56
|
alias_method :speakers, :getspeakers
|
58
57
|
|
59
|
-
def setup_home_sharing(user, password)
|
60
|
-
hs_client = Faraday.new(url: HOME_SHARING_HOST)
|
61
|
-
result = hs_client.post do |request|
|
62
|
-
request.url HOME_SHARING_PATH
|
63
|
-
request.headers['Content-Type'] = 'text/xml'
|
64
|
-
request.headers.merge!(DEFAULT_HEADERS)
|
65
|
-
request.body = { 'appleId' => user, 'guid' => 'empty',
|
66
|
-
'password' => password }.to_plist
|
67
|
-
end
|
68
|
-
response = Plist.parse_xml(result.body)
|
69
|
-
@hsgid = response['sgid']
|
70
|
-
end
|
71
|
-
|
72
58
|
def guid
|
73
59
|
return @guid unless @guid.nil?
|
74
60
|
d = Digest::SHA2.hexdigest(@name)
|
@@ -156,6 +142,19 @@ module DACPClient
|
|
156
142
|
set_property('dmcp.volume', volume)
|
157
143
|
end
|
158
144
|
|
145
|
+
def cue(command, query, index = 0)
|
146
|
+
do_action(:cue, command: command, query: query, index: index)
|
147
|
+
end
|
148
|
+
|
149
|
+
def playspec(playlist, db = default_db)
|
150
|
+
dbspec = "'dmap.persistentid:0x#{db.persistent_id.to_s(16)}'"
|
151
|
+
cspec = "'dmap.persistentid:0x#{playlist.persistent_id.to_s(16)}'"
|
152
|
+
# don't worry about playing item's from playlists yet..
|
153
|
+
# container-item-spec='dmap.containeritemid:%s'
|
154
|
+
do_action(:playspec, database_spec: dbspec,
|
155
|
+
container_spec: cspec)
|
156
|
+
end
|
157
|
+
|
159
158
|
def repeat
|
160
159
|
response = do_action(:getproperty, properties: 'dacp.repeatstate')
|
161
160
|
response[:carp]
|
@@ -198,16 +197,25 @@ module DACPClient
|
|
198
197
|
end
|
199
198
|
|
200
199
|
def databases
|
201
|
-
|
200
|
+
meta = %w(dmap.itemname dmap.itemcount dmap.itemid dmap.persistentid
|
201
|
+
daap.baseplaylist com.apple.itunes.special-playlist
|
202
|
+
com.apple.itunes.smart-playlist com.apple.itunes.saved-genius
|
203
|
+
dmap.parentcontainerid dmap.editcommandssupported).join(',')
|
204
|
+
do_action('databases', clean_url: true, meta: meta, model: Databases)
|
202
205
|
end
|
203
206
|
|
204
207
|
def playlists(db = default_db)
|
205
|
-
|
206
|
-
|
208
|
+
meta = %w(dmap.itemname dmap.itemcount dmap.itemid dmap.persistentid
|
209
|
+
daap.baseplaylist com.apple.itunes.special-playlist
|
210
|
+
com.apple.itunes.smart-playlist com.apple.itunes.saved-genius
|
211
|
+
dmap.parentcontainerid dmap.editcommandssupported).join(',')
|
212
|
+
do_action("databases/#{db.item_id}/containers", clean_url: true,
|
213
|
+
meta: meta,
|
214
|
+
model: Playlists).items
|
207
215
|
end
|
208
216
|
|
209
217
|
def default_db
|
210
|
-
databases.
|
218
|
+
databases.items.find { |item| item.default_db == 1 }
|
211
219
|
end
|
212
220
|
|
213
221
|
def default_playlist(db = default_db)
|
@@ -269,14 +277,17 @@ module DACPClient
|
|
269
277
|
do_action(:setproperty, property => value)
|
270
278
|
end
|
271
279
|
|
272
|
-
def do_action(action,
|
280
|
+
def do_action(action, params = {})
|
281
|
+
clean_url = params.delete(:clean_url) || false
|
282
|
+
model = params.delete(:model)
|
283
|
+
|
273
284
|
action = '/' + action.to_s
|
274
285
|
unless @session_id.nil?
|
275
286
|
params['session-id'] = @session_id.to_s
|
276
287
|
action = '/ctrl-int/1' + action unless clean_url
|
277
288
|
end
|
278
289
|
params['hsgid'] = @hsgid unless @hsgid.nil?
|
279
|
-
|
290
|
+
params = filter_param_keys(params)
|
280
291
|
result = @client.get do |request|
|
281
292
|
request.options.params_encoder = Faraday::FlatterParamsEncoder
|
282
293
|
request.url action
|
@@ -287,6 +298,10 @@ module DACPClient
|
|
287
298
|
parse_result result, model
|
288
299
|
end
|
289
300
|
|
301
|
+
def filter_param_keys(params)
|
302
|
+
Hash[ params.map { |k, v| [k.to_s.tr('_', '-'), v] }]
|
303
|
+
end
|
304
|
+
|
290
305
|
def parse_result(result, model)
|
291
306
|
if !result.success?
|
292
307
|
fail DACPForbiddenError, result
|
data/lib/dacpclient/model.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
module DACPClient
|
2
|
+
class Database < Model
|
3
|
+
dmap_tag :mlit
|
4
|
+
dmap_attribute :item_id, :miid
|
5
|
+
dmap_attribute :name, :minm
|
6
|
+
dmap_attribute :count, :mimc
|
7
|
+
dmap_attribute :container_count, :mctc
|
8
|
+
dmap_attribute :default_db, :mdbk
|
9
|
+
dmap_attribute :persistent_id, :mper
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module DACPClient
|
2
|
+
class Databases < Model
|
3
|
+
dmap_tag :avdb
|
4
|
+
dmap_attribute :status, :mstt
|
5
|
+
dmap_attribute :update_type, :myty
|
6
|
+
dmap_attribute :container_count, :mtco
|
7
|
+
dmap_attribute :returned_count, :mrco
|
8
|
+
dmap_container :items, :mlcl, DACPClient::Database
|
9
|
+
end
|
10
|
+
end
|
data/lib/dacpclient/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dacpclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jurriaan Pruis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.19.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: fuzzy_match
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.0.4
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.0.4
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: yard
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,6 +174,8 @@ files:
|
|
160
174
|
- lib/dacpclient/faraday/flatter_params_encoder.rb
|
161
175
|
- lib/dacpclient/faraday/gzip.rb
|
162
176
|
- lib/dacpclient/model.rb
|
177
|
+
- lib/dacpclient/models/database.rb
|
178
|
+
- lib/dacpclient/models/databases.rb
|
163
179
|
- lib/dacpclient/models/pair_info.rb
|
164
180
|
- lib/dacpclient/models/play_queue.rb
|
165
181
|
- lib/dacpclient/models/play_queue_item.rb
|