dacpclient 0.2.11 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|