dacpclient 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a91f6ef4321ce83e0cabc85493552ebf7961756
4
- data.tar.gz: c032e8102b42801e7fa220861ecefb5b306f0550
3
+ metadata.gz: ef5304a1a170b2d08364485ca254ff1f2607fba3
4
+ data.tar.gz: f7369e5cc191eae00af1a9b02e4e276069385496
5
5
  SHA512:
6
- metadata.gz: 352cf3561c859d1bf52deb7a3fb33d036245282e6610e72871f11863055afebd3fb41ff630fdb887c3f52573bf3ead3fbcf9fc7163ca0b6882391d9addf65ec6
7
- data.tar.gz: e78e5bad668a556c7d583702c23798a75b2df288bfb8358c9e750047685963bfbbc3380f9c2df6c12fb9236a3b5c2bb65f9b8bd5ebc6950a9c3801754cac72f6
6
+ metadata.gz: 6c8b74aac51cfa281f8201e52b49044ec1009bfca8fed4252c5d2da9dc9abeaba0bf3e755605900f30f1f521885d54c9e4614741fcaee4dffdcbc73b4165331e
7
+ data.tar.gz: e4204cd25fd0223c49b59dddfc032f91714827478ba3c6ca6692037b0ba83e15c771ea03aea0d96546704f34889230a44ef583b244d727f49d1426ba7d4094be
data/.rubocop.yml CHANGED
@@ -3,5 +3,7 @@ MethodLength:
3
3
  Enabled: false
4
4
  Documentation:
5
5
  Enabled: false
6
- ConstantName:
6
+ ClassVars:
7
+ Enabled: false
8
+ ClassLength:
7
9
  Enabled: false
data/Gemfile CHANGED
@@ -2,12 +2,3 @@
2
2
  gemspec
3
3
 
4
4
  source 'https://rubygems.org'
5
-
6
- group :test do
7
- gem 'pry'
8
- gem 'minitest', '~> 5.0.6'
9
- # gem 'coveralls', require: false
10
- gem 'rake'
11
- gem 'rubocop', '~> 0.11.1'
12
- gem 'simplecov', :require => false
13
- end
data/README.md CHANGED
@@ -5,6 +5,8 @@
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, or with Home Sharing. DACPClient supports both methods.
9
+
8
10
  Look at the [bin/dacpclient](https://github.com/jurriaan/ruby-dacpclient/blob/master/bin/dacpclient) file for an example client.
9
11
 
10
12
  ## Installation
@@ -25,8 +27,30 @@ Or install it yourself using:
25
27
 
26
28
  See [bin/dacpclient](https://github.com/jurriaan/ruby-dacpclient/blob/master/bin/dacpclient)
27
29
 
30
+ Usage: dacpclient [command]
31
+ (c) 2013 Jurriaan Pruis <email@jurriaanpruis.nl>
32
+
33
+ Where command is one of the following:
34
+ status
35
+ status_ticker
36
+ home_sharing
37
+ play
38
+ pause
39
+ playpause
40
+ next
41
+ prev
42
+ databases
43
+ playqueue
44
+ upnext
45
+ stop
46
+ debug
47
+ usage
48
+ previous
49
+ help
50
+
28
51
  ## Todo
29
52
 
53
+ - Use bonjour
30
54
  - Add tests
31
55
  - Add more tagdefinitions
32
56
  - Documentation
data/Rakefile CHANGED
@@ -19,4 +19,4 @@ task :rubocop do
19
19
  fail unless cli.run(args) == 0
20
20
  end
21
21
 
22
- task default: :test
22
+ task default: :test
data/bin/dacpclient CHANGED
@@ -1,13 +1,25 @@
1
1
  #!/usr/bin/env ruby
2
-
3
2
  require 'dacpclient'
4
- require 'english'
3
+ require 'English'
5
4
  require 'socket'
5
+ require 'yaml'
6
+ require 'yaml/dbm'
7
+ require 'fileutils'
8
+ require 'io/console'
6
9
 
7
10
  # This is the CLI DACP Client. Normally installed as `dacpclient`
8
11
  class CLIClient
9
12
  def initialize
10
- @client = DACPClient::Client.new("CLIClient (#{Socket.gethostname})", 'localhost', 3689)
13
+ @config = {}
14
+ @config['client_name'] ||= "DACPClient (#{Socket.gethostname})"
15
+ load_config
16
+
17
+ @client = DACPClient::Client.new(@config['client_name'], 'localhost', 3689)
18
+ if @config['guid'].nil? || @config['guid'] !~ /^[a-f0-9]{16}$/
19
+ @config['guid'] = @client.get_guid
20
+ save_config
21
+ end
22
+ @client.guid = @config['guid']
11
23
  @login = false
12
24
  end
13
25
 
@@ -64,6 +76,23 @@ class CLIClient
64
76
  end
65
77
  end
66
78
 
79
+ def home_sharing
80
+ puts "Setting up Home Sharing. Saving Home Sharing GUID to ~/.dacpclient/config.yml"
81
+ puts "\nPlease enter your Apple ID credentials:"
82
+ print "Apple ID (e-mail address): "
83
+ email = $stdin.gets.strip
84
+ print "Password: "
85
+ password = $stdin.noecho(&:gets).chomp
86
+ guid = @client.setup_home_sharing(email, password)
87
+ password = nil
88
+ @config['appleid'] = email
89
+ @config['hsgid'] = guid
90
+ save_config
91
+ puts "\n\n"
92
+ puts "Got your Home Sharing GUID (#{guid}). Logging in.."
93
+ login
94
+ end
95
+
67
96
  def play
68
97
  login
69
98
  @client.play
@@ -101,7 +130,7 @@ class CLIClient
101
130
 
102
131
  def upnext
103
132
  login
104
- items = @client.list_queue.mlcl.select { |item| item.type.tag == 'mlit' }
133
+ items = @client.list_queue.mlcl.to_a.select {|i| i.type.tag == 'mlit' }
105
134
  puts 'Up next:'
106
135
  puts '--------'
107
136
  puts
@@ -140,7 +169,13 @@ class CLIClient
140
169
  private
141
170
 
142
171
  def login
143
- @client.login unless @login
172
+ return if @login
173
+ @client.hsgid = @config['hsgid']
174
+ if @client.hsgid.nil?
175
+ @client.pair_and_login
176
+ else
177
+ @client.login
178
+ end
144
179
  @login = true
145
180
  end
146
181
 
@@ -165,7 +200,27 @@ class CLIClient
165
200
  end
166
201
  end
167
202
  end
203
+
204
+ def config_dir
205
+ File.join(ENV['HOME'], '.dacpclient')
206
+ end
207
+
208
+ def load_config
209
+ FileUtils.mkdir_p(config_dir)
210
+ config_file = File.join(config_dir,'config.yml')
211
+ if File.exists? config_file
212
+ @config.merge! YAML.load_file(config_file)
213
+ else
214
+ save_config
215
+ end
216
+ end
217
+
218
+ def save_config
219
+ File.open(File.join(config_dir,'config.yml'), 'w') do |out|
220
+ YAML.dump(@config, out)
221
+ end
222
+ end
168
223
  end
169
224
 
170
225
  cli = CLIClient.new
171
- cli.parse_arguments(Array(ARGV))
226
+ cli.parse_arguments(Array(ARGV))
data/dacpclient.gemspec CHANGED
@@ -20,10 +20,15 @@ Gem::Specification.new do |spec|
20
20
  spec.extra_rdoc_files = ['README.md', 'LICENSE']
21
21
 
22
22
  spec.add_runtime_dependency 'dnssd', '~> 2.0'
23
+ spec.add_runtime_dependency 'faraday', '~> 0.8.8'
24
+ spec.add_runtime_dependency 'plist', '~> 3.1.0'
23
25
 
24
26
  spec.add_development_dependency 'yard'
25
27
  spec.add_development_dependency 'redcarpet'
26
28
  spec.add_development_dependency 'github-markup'
29
+ spec.add_development_dependency 'minitest', '~> 5.2.0'
30
+ spec.add_development_dependency 'rubocop', '~> 0.15.0'
31
+ spec.add_development_dependency 'rake'
27
32
 
28
- spec.required_ruby_version = '>= 1.9.3'
33
+ spec.required_ruby_version = '>= 2.0.0'
29
34
  end
@@ -0,0 +1,43 @@
1
+ module DACPClient
2
+ # The Client class handles communication with the server
3
+ class Bonjour
4
+ SERVICE_NAME = '_daap._tcp'.freeze
5
+ DOMAIN = 'local'.freeze
6
+
7
+ def browse
8
+ servers = []
9
+
10
+ begin
11
+ timeout(3) do
12
+ DNSSD.browse!(SERVICE_NAME, DOMAIN) do |node|
13
+ ip, port = nil
14
+
15
+ resolver = DNSSD::Service.new
16
+ resolver.resolve(node) do |resolved|
17
+ ip = get_ip(resolved.target)
18
+ port = resolved.port
19
+
20
+ break unless resolved.flags.more_coming?
21
+ end
22
+
23
+ servers << { name: node.name, ip: ip, port: port, node: node }
24
+
25
+ break unless node.flags.more_coming?
26
+ end
27
+ end
28
+
29
+ rescue Timeout::Error
30
+ return []
31
+ end
32
+
33
+ servers
34
+ end
35
+
36
+ private
37
+
38
+ def get_ip(target)
39
+ info = Socket.getaddrinfo(target, nil, Socket::AF_INET)
40
+ info[0][2]
41
+ end
42
+ end
43
+ end
@@ -1,51 +1,89 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- Bundler.setup(:default)
1
+ require 'faraday'
4
2
  require 'digest'
5
3
  require 'net/http'
4
+ require 'uri'
5
+ require 'cgi'
6
+ require 'plist'
6
7
  require 'dacpclient/pairingserver'
7
8
  require 'dacpclient/dmapparser'
8
9
  require 'dacpclient/dmapbuilder'
9
- require 'uri'
10
- require 'cgi'
10
+ require 'dacpclient/bonjour'
11
11
 
12
12
  module DACPClient
13
13
  # The Client class handles communication with the server
14
14
  class Client
15
+ attr_accessor :guid, :hsgid
16
+ attr_reader :name, :host, :port, :session_id
17
+
18
+ HOME_SHARING_HOST = 'https://homesharing.itunes.apple.com'
19
+ HOME_SHARING_PATH = '/WebObjects/MZHomeSharing.woa/wa/getShareIdentifiers'
20
+
21
+ DEFAULT_HEADERS = {
22
+ 'Viewer-Only-Client' => '1',
23
+ # 'Accept-Encoding' => 'gzip',
24
+ 'Connection' => 'keep-alive',
25
+ 'User-Agent' => 'Remote/2.0'
26
+ }.freeze
15
27
 
16
28
  def initialize(name, host = 'localhost', port = 3689)
17
29
  @client = Net::HTTP.new(host, port)
18
30
  @name = name
19
31
  @host = host
20
32
  @port = port
21
- @service = nil
33
+
22
34
  @session_id = nil
35
+ @hsgid = nil
23
36
  @mediarevision = 1
37
+ @uri = URI::HTTP.build(host: @host, port: @port)
38
+ @client = Faraday.new(url: @uri.to_s)
39
+ end
40
+
41
+ def setup_home_sharing(user, password)
42
+ hs_client = Faraday.new(url: HOME_SHARING_HOST)
43
+ result = hs_client.post do |request|
44
+ request.url HOME_SHARING_PATH
45
+ request.headers['Content-Type'] = 'text/xml'
46
+ request.headers.merge!(DEFAULT_HEADERS)
47
+ request.body = { 'appleId' => user, 'guid' => 'empty',
48
+ 'password' => password }.to_plist
49
+ end
50
+ response = Plist.parse_xml(result.body)
51
+ @hsgid = response['sgid']
52
+ end
53
+
54
+ def get_guid
55
+ return @guid unless @guid.nil?
56
+ d = Digest::SHA2.hexdigest(@name)
57
+ d[0..15]
24
58
  end
25
59
 
26
60
  def pair(pin)
27
- pairingserver = PairingServer.new(@name, '0.0.0.0', 1024)
61
+ pairingserver = PairingServer.new(self, '0.0.0.0', 1024)
28
62
  pairingserver.pin = pin
29
63
  pairingserver.start
30
64
  end
31
65
 
32
- def self.get_guid(name)
33
- d = Digest::SHA2.hexdigest(name)
34
- d[0..15]
35
- end
36
-
37
66
  def serverinfo
38
- do_action('server-info')
67
+ do_action('server-info', {}, true)
39
68
  end
40
69
 
41
- def login(pin = nil)
42
- pairing_guid = '0x' + Client.get_guid(@name)
43
- response = do_action(:login, { 'pairing-guid' => pairing_guid })
70
+ def login
71
+ response = nil
72
+ if @hsgid.nil?
73
+ pairing_guid = '0x' + get_guid
74
+ response = do_action(:login, 'pairing-guid' => pairing_guid)
75
+ else
76
+ response = do_action(:login, 'hasFP' => '1')
77
+ end
44
78
  @session_id = response[:mlid]
45
79
  response
80
+ end
81
+
82
+ def pair_and_login(pin = nil)
83
+ login
46
84
  rescue DACPForbiddenError => e
47
85
  pin = 4.times.map { Random.rand(10) } if pin.nil?
48
- warn "#{e.result.message} error: Cannot login, starting pairing process"
86
+ warn "#{e.result.status} error: Cannot login, starting pairing process"
49
87
  warn "Pincode: #{pin}"
50
88
  pair(pin)
51
89
  retry
@@ -71,16 +109,29 @@ module DACPClient
71
109
  do_action(:pause)
72
110
  end
73
111
 
112
+ def track_length
113
+ response = do_action(:getproperty, properties: 'dacp.playingtime')
114
+ response['cast']
115
+ end
116
+
74
117
  def seek(ms)
75
118
  do_action(:setproperty, 'dacp.playingtime' => ms)
76
119
  end
77
120
 
121
+ def get_position
122
+ response = do_action(:getproperty, properties: 'dacp.playingtime')
123
+ response['cast'] - response['cant']
124
+ end
125
+
126
+ alias_method :position, :get_position
127
+ alias_method :position=, :seek
128
+
78
129
  def status(wait = false)
79
130
  revision = wait ? @mediarevision : 1
80
131
  result = do_action(:playstatusupdate, 'revision-number' => revision)
81
132
  @mediarevision = result[:cmsr]
82
133
  result
83
- rescue Net::ReadTimeout => e
134
+ rescue Faraday::Error::TimeoutError => e
84
135
  if wait
85
136
  retry
86
137
  else
@@ -96,6 +147,8 @@ module DACPClient
96
147
  do_action(:previtem)
97
148
  end
98
149
 
150
+ alias_method :previous, :prev
151
+
99
152
  def get_volume
100
153
  response = do_action(:getproperty, properties: 'dmcp.volume')
101
154
  response[:cmvo]
@@ -105,6 +158,9 @@ module DACPClient
105
158
  do_action(:setproperty, 'dmcp.volume' => volume)
106
159
  end
107
160
 
161
+ alias_method :volume, :get_volume
162
+ alias_method :volume=, :set_volume
163
+
108
164
  def get_repeat
109
165
  response = do_action(:getproperty, properties: 'dacp.repeatstate')
110
166
  response[:carp]
@@ -123,25 +179,31 @@ module DACPClient
123
179
  do_action(:setproperty, 'dmcp.volume' => volume)
124
180
  end
125
181
 
182
+ def getspeakers
183
+ do_action(:getspeakers)
184
+ end
185
+
126
186
  def ctrl_int
127
- do_action('ctrl-int', {}, false)
187
+ do_action('ctrl-int', {}, true)
128
188
  end
129
189
 
130
190
  def logout
131
- do_action(:logout, {}, false)
191
+ do_action(:logout)
192
+ @mediarevision = 1
193
+ @session_id = nil
132
194
  end
133
195
 
134
196
  def queue(id)
135
- do_action('playqueue-edit', { command: 'add',
136
- query: "\'dmap.itemid:#{id}\'" })
197
+ do_action('playqueue-edit', command: 'add',
198
+ query: "\'dmap.itemid:#{id}\'")
137
199
  end
138
200
 
139
201
  def clear_queue
140
- do_action('playqueue-edit', { command: 'clear' })
202
+ do_action('playqueue-edit', command: 'clear')
141
203
  end
142
204
 
143
205
  def list_queue
144
- do_action('playqueue-contents', {})
206
+ do_action('playqueue-contents')
145
207
  end
146
208
 
147
209
  def databases
@@ -153,7 +215,7 @@ module DACPClient
153
215
  end
154
216
 
155
217
  def default_db
156
- databases[:mlcl].to_a.find {|item| item.mdbk == 1}
218
+ databases[:mlcl].to_a.find { |item| item.mdbk == 1 }
157
219
  end
158
220
 
159
221
  def default_playlist(db)
@@ -166,7 +228,7 @@ module DACPClient
166
228
  end
167
229
 
168
230
  def now_playing_artwork(width = 320, height = 320)
169
- do_action(:nowplayingartwork, { mw: width, mh: height })
231
+ do_action(:nowplayingartwork, mw: width, mh: height)
170
232
  end
171
233
 
172
234
  def search(db, container, search, type = nil)
@@ -180,17 +242,19 @@ module DACPClient
180
242
  }
181
243
  queries = []
182
244
  type = types.keys if type.nil?
183
- Array(type).each do |t|
245
+ Array(type).each do |t|
184
246
  queries << "'#{types[t]}:#{search}'"
185
247
  end
186
- # @http.get("/databases/1/containers/1/items?query='daap.songartist:#{escaped_pattern}','daap.songalbum:#{escaped_pattern}','dmap.itemname:#{escaped_pattern}','daap.songgenre:#{escaped_pattern}','daap.songcomposer:#{escaped_pattern}'").body
187
- #queries.push(words.map { |v| "\'dmap.itemname:*#{v}*\'" }.join('+'))
188
- # queries.push(words.map{|v| "\'daap.songartist:*#{v}*\'"}.join('+'))
248
+
189
249
  q = queries.join(',')
190
- meta = 'dmap.itemname,dmap.itemid,daap.songartist,daap.songalbumartist,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'
250
+ meta = %w(dmap.itemname dmap.itemid daap.songartist daap.songalbumartist
251
+ daap.songalbum com.apple.itunes.cloud-id dmap.containeritemid
252
+ com.apple.itunes.has-video com.apple.itunes.itms-songid
253
+ com.apple.itunes.extended-media-kind dmap.downloadstatus
254
+ daap.songdisabled).join(',')
191
255
 
192
256
  url = "databases/#{db}/containers/#{container}/items"
193
- do_action(url, { type: 'music', sort: 'album', query: q, meta: meta},
257
+ do_action(url, { type: 'music', sort: 'album', query: q, meta: meta },
194
258
  true)
195
259
  end
196
260
 
@@ -202,28 +266,23 @@ module DACPClient
202
266
  params['session-id'] = @session_id
203
267
  action = '/ctrl-int/1' + action unless cleanurl
204
268
  end
205
- params = params.map { |k,v| "#{k}=#{v}" }.join('&')
206
- uri = URI::HTTP.build({ host: @host, port: @port, path: action,
207
- query: params })
208
- req = Net::HTTP::Get.new(uri.request_uri)
209
- req.add_field('Viewer-Only-Client', '1')
210
- res = Net::HTTP.new(uri.host, uri.port).start do |http|
211
- http.read_timeout = 1000
212
- http.request(req)
213
- end
214
- if res.kind_of?(Net::HTTPServiceUnavailable) ||
215
- res.kind_of?(Net::HTTPForbidden)
216
- raise DACPForbiddenError.new(res)
217
- elsif !res.kind_of?(Net::HTTPSuccess)
218
- warn 'No succes!'
219
- warn res
220
- return nil
269
+ params['hsgid'] = @hsgid unless @hsgid.nil?
270
+ result = @client.get do |request|
271
+ request.url action
272
+ request.params = params
273
+ request.headers.merge!(DEFAULT_HEADERS)
221
274
  end
222
275
 
223
- if res['Content-Type'] == 'application/x-dmap-tagged'
224
- DMAPParser::Parser.parse(res.body)
276
+ parse_result result
277
+ end
278
+
279
+ def parse_result(result)
280
+ if !result.success?
281
+ fail DACPForbiddenError, result
282
+ elsif result.headers['Content-Type'] == 'application/x-dmap-tagged'
283
+ DMAPParser.parse(result.body)
225
284
  else
226
- res.body
285
+ result.body
227
286
  end
228
287
  end
229
288
  end
@@ -232,8 +291,8 @@ module DACPClient
232
291
  # service unavailable
233
292
  class DACPForbiddenError < StandardError
234
293
  attr_reader :result
235
- def initialize(res)
236
- @result = res
294
+ def initialize(result)
295
+ @result = result
237
296
  end
238
297
  end
239
298
  end
@@ -11,31 +11,33 @@ module DACPClient
11
11
  new.send(method, *args, &block)
12
12
  end
13
13
 
14
- def method_missing(method, *args, &block)
15
- if method.to_s.length != 4 ||
16
- (tag = DMAPParser::Types.find { |a| a.tag.to_s == method.to_s }).nil?
17
- return super
14
+ def build_container(tag , &block)
15
+ unless tag.type == :container
16
+ fail "Tag #{method} is not a container type"
17
+ end
18
+ @dmap_stack << TagContainer.new(tag)
19
+ instance_eval(&block)
20
+ if @dmap_stack.length > 1
21
+ @dmap_stack.last.value << @dmap_stack.pop
22
+ else
23
+ return @result = @dmap_stack.pop
18
24
  end
25
+ end
26
+
27
+ def method_missing(method, *args, &block)
28
+ tag = TagDefinition[method]
29
+ return super if tag.nil?
30
+
19
31
  if block_given?
20
- if tag.type == :container
21
- @dmap_stack << DMAPParser::TagContainer.new(tag)
22
- instance_eval(&block)
23
- if @dmap_stack.length > 1
24
- @dmap_stack.last.value << @dmap_stack.pop
25
- else
26
- return @result = @dmap_stack.pop
27
- end
28
- else
29
- raise "Tag #{method} is not a container type"
30
- end
32
+ build_container(tag, &block)
31
33
  else
32
34
  if @dmap_stack.length > 0
33
35
  args = args.size > 1 ? args : args.first
34
- @dmap_stack.last.value << DMAPParser::Tag.new(tag, args)
36
+ @dmap_stack.last.value << Tag.new(tag, args)
35
37
  else
36
- raise 'Cannot build DMAP without a valid container'
38
+ fail 'Cannot build DMAP without a valid container'
37
39
  end
38
40
  end
39
41
  end
40
42
  end
41
- end
43
+ end
@@ -2,6 +2,10 @@ module DACPClient
2
2
  # The DMAPConverter class converts between binary and ruby formats
3
3
  class DMAPConverter
4
4
  class << self
5
+ def date_to_bin(data)
6
+ int_to_bin(value.to_i)
7
+ end
8
+
5
9
  def bin_to_byte(data)
6
10
  data.unpack('C').first
7
11
  end
@@ -27,15 +31,15 @@ module DACPClient
27
31
  end
28
32
 
29
33
  def bin_to_hex(data)
30
- data.bytes.reduce('') { |a, e| a += sprintf('%02X', e) }
34
+ data.bytes.reduce('') { |a, e| a + sprintf('%02X', e) }
35
+ end
36
+
37
+ def bin_to_date(data)
38
+ Time.at(bin_to_int(data))
31
39
  end
32
40
 
33
41
  def bool_to_bin(data)
34
- if data.true?
35
- "\x01"
36
- else
37
- "\x00"
38
- end
42
+ (data ? 1 : 0).chr
39
43
  end
40
44
 
41
45
  def int_to_bin(data)
@@ -61,6 +65,55 @@ module DACPClient
61
65
  def hex_to_bin(data)
62
66
  [data].pack 'H*'
63
67
  end
68
+
69
+ def decode_unknown(data)
70
+ if data =~ /[^\x20-\x7e]/ # non-readable characters
71
+ if data.bytesize == 1
72
+ return DMAPConverter.bin_to_byte(data)
73
+ elsif data.bytesize == 2
74
+ return DMAPConverter.bin_to_short(data)
75
+ elsif data.bytesize == 4
76
+ return DMAPConverter.bin_to_int(data)
77
+ elsif data.bytesize == 8
78
+ return DMAPConverter.bin_to_long(data)
79
+ end
80
+ end
81
+ data
82
+ end
83
+
84
+ def bin_to_string(data)
85
+ data
86
+ end
87
+ alias_method :string_to_bin, :bin_to_string
88
+
89
+ alias_method :uint16_to_bin, :short_to_bin
90
+ alias_method :uint32_to_bin, :int_to_bin
91
+ alias_method :uint64_to_bin, :long_to_bin
92
+
93
+ alias_method :bin_to_uint16, :bin_to_short
94
+ alias_method :bin_to_uint32, :bin_to_int
95
+ alias_method :bin_to_uint64, :bin_to_long
96
+ alias_method :bin_to_unknown, :decode_unknown
97
+
98
+ def decode(type, data)
99
+ decode_method = ('bin_to_' + type.to_s).to_sym
100
+ if respond_to? decode_method
101
+ send(decode_method, data)
102
+ else
103
+ warn "Decoder: Unknown type #{type}"
104
+ decode_unknown(data)
105
+ end
106
+ end
107
+
108
+ def encode(type, data)
109
+ encode_method = (type.to_s + '_to_bin').to_sym
110
+ if respond_to? encode_method
111
+ send(encode_method, data)
112
+ else
113
+ warn "Encoder: Unknown type #{type}"
114
+ data
115
+ end
116
+ end
64
117
  end
65
118
  end
66
- end
119
+ end