dacpclient 0.1.1 → 0.2.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.
@@ -1,86 +1,40 @@
1
- require 'dacpclient/tagdefinitions'
1
+ require 'dacpclient/tag_definitions'
2
2
  require 'dacpclient/dmapconverter'
3
3
 
4
4
  require 'stringio'
5
5
  module DACPClient
6
- module DMAPParser
7
- # The DMAPParser class parses DMAP responses
8
- class Parser
9
-
10
- def self.parse(response)
11
- return nil if response.nil? || response.length < 8
12
- response = StringIO.new(response)
13
- ret = TagContainer.new
14
- key = response.read(4)
15
- ret.type = Types.find { |a| a.tag == key }
16
- response.read(4) # ignore length for now
17
- ret.value = parse_container(response)
18
- ret
19
- end
20
-
21
- private
6
+ # The DMAPParser class parses DMAP responses
7
+ class DMAPParser
8
+ def self.parse(response)
9
+ return nil if response.nil? || response.length < 8
10
+ response = StringIO.new(response)
11
+ ret = TagContainer.new
12
+ key = response.read(4)
13
+ ret.type = TagDefinition[key]
14
+ response.read(4) # ignore length for now
15
+ ret.value = parse_container(response)
16
+ ret
17
+ end
22
18
 
23
- def self.parse_container(response)
24
- values = []
19
+ private
25
20
 
26
- until response.eof?
27
- key = response.read(4)
28
- length = DMAPConverter.bin_to_int(response.read(4))
29
- data = response.read(length)
30
- tag = Types.find { |a| a.tag.to_s == key }
31
- # puts "#{key} (#{length}): #{data.inspect}"
32
- p data if !tag.nil? && tag.tag.to_s == 'msas'
33
- values << if !tag.nil?
34
- case tag.type
35
- when :container
36
- data = StringIO.new(data)
37
- TagContainer.new(tag, parse_container(data))
38
- when :byte
39
- Tag.new(tag, DMAPConverter.bin_to_byte(data))
40
- when :uint16, :short
41
- Tag.new(tag, DMAPConverter.bin_to_short(data))
42
- when :uint32
43
- Tag.new(tag, DMAPConverter.bin_to_int(data))
44
- when :uint64
45
- Tag.new(tag, DMAPConverter.bin_to_long(data))
46
- when :bool
47
- Tag.new(tag, DMAPConverter.bin_to_bool(data))
48
- when :hex
49
- Tag.new(tag, DMAPConverter.bin_to_hex(data))
50
- when :string
51
- Tag.new(tag, data)
52
- when :date
53
- Tag.new tag, Time.at(DMAPConverter.bin_to_int(data))
54
- when :version
55
- Tag.new tag, DMAPConverter.bin_to_version(data)
56
- else
57
- warn "Unknown type #{tag.type}"
58
- Tag.new(tag, parseunknown(data))
59
- end
60
- else
61
- # puts "Unknown key #{key}"
62
- tag = TagDefinition.new(key, :unknown,
63
- "unknown (#{data.bytesize})")
64
- Tag.new(tag, parseunknown(data))
65
- end
66
- end
67
- values
68
- end
21
+ def self.parse_container(response)
22
+ values = []
69
23
 
70
- def self.parseunknown(data)
71
- if data =~ /[^\x20-\x7e]/ # non-readable characters
72
- if data.bytesize == 1
73
- return DMAPConverter.bin_to_byte(data)
74
- elsif data.bytesize == 2
75
- return DMAPConverter.bin_to_short(data)
76
- elsif data.bytesize == 4
77
- return DMAPConverter.bin_to_int(data)
78
- elsif data.bytesize == 8
79
- return DMAPConverter.bin_to_long(data)
80
- end
24
+ until response.eof?
25
+ key = response.read(4)
26
+ length = DMAPConverter.bin_to_int(response.read(4))
27
+ data = response.read(length)
28
+ tag = TagDefinition[key] ||
29
+ TagDefinition.new(key, :unknown, "unknown (#{data.bytesize})")
30
+ if tag.type == :container
31
+ data = StringIO.new(data)
32
+ values << TagContainer.new(tag, parse_container(data))
33
+ else
34
+ values << Tag.new(tag, DMAPConverter.decode(tag.type, data))
81
35
  end
82
- data
83
36
  end
37
+ values
84
38
  end
85
39
  end
86
- end
40
+ end
@@ -1,50 +1,35 @@
1
1
  require 'socket'
2
2
  require 'dnssd'
3
3
  require 'digest'
4
+ require 'gserver'
4
5
  module DACPClient
5
6
  # The pairingserver handles pairing with iTunes
6
- class PairingServer
7
+ class PairingServer < GServer
7
8
  attr_accessor :pin, :device_type
8
- def initialize(name, host, port = 1024)
9
- @name = name
9
+
10
+ MDNS_TYPE = '_touch-remote._tcp'.freeze
11
+
12
+ def initialize(client, host, port = 1024)
13
+ @name = client.name
10
14
  @port = port
11
15
  @host = host
12
- @pair = Client.get_guid(@name)
16
+ @pair = client.get_guid
13
17
  @pin = [0, 0, 0, 0]
14
18
  @device_type = 'iPod'
19
+ super port, host
15
20
  end
16
21
 
17
22
  def start
18
- # puts "Pairing started (pincode=#{@pin.join})"
19
-
20
- pairing_string = generate_pairing_string(@pair, @name, @device_type)
21
-
22
- expected = PairingServer.generate_pin_challenge(@pair, @pin)
23
- server = TCPServer.open(@host, @port)
24
- type = '_touch-remote._tcp'
25
- @service = DNSSD.register!(@name, type, 'local', @port, text_record)
23
+ @pairing_string = generate_pairing_string(@pair, @name, @device_type)
24
+ @expected = PairingServer.generate_pin_challenge(@pair, @pin)
25
+ @service = DNSSD.register!(@name, MDNS_TYPE, 'local', @port, text_record)
26
26
 
27
- while (client = server.accept)
28
- get = client.gets
29
- code = get.match(/pairingcode=([^&]*)/)[1]
27
+ super
28
+ join
30
29
 
31
- if code == expected
32
- client.print "HTTP/1.1 200 OK\r\n"
33
- client.print "Content-Length: #{pairing_string.length}\r\n\r\n"
34
- client.print pairing_string
35
- # puts 'Pairing succeeded :)'
36
- client.close
37
- @service.stop
38
- break
39
- else
40
- # puts 'Wrong pincode entered'
41
- client.print "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"
42
- end
43
- client.close
44
- end
45
- server.close
30
+ @service.stop
46
31
 
47
- sleep 1 # sleep so iTunes accepts our login
32
+ sleep 0.5 # sleep so iTunes accepts our login
48
33
  end
49
34
 
50
35
  def self.generate_pin_challenge(pair, pin)
@@ -52,17 +37,31 @@ module DACPClient
52
37
  Digest::MD5.hexdigest(pair + pin_string).upcase
53
38
  end
54
39
 
40
+ def serve(client)
41
+ code = client.gets.match(/pairingcode=([^&]*)/)[1]
42
+ correct = code == @expected
43
+ if correct
44
+ client.print "HTTP/1.1 200 OK\r\n" +
45
+ "Content-Length: #{@pairing_string.length}\r\n\r\n"
46
+ client.print @pairing_string
47
+ else
48
+ client.print "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"
49
+ end
50
+ client.close
51
+ stop if correct
52
+ end
53
+
55
54
  private
56
55
 
57
56
  def text_record
58
- DNSSD::TextRecord.new({
57
+ DNSSD::TextRecord.new(
59
58
  'DvNm' => @name,
60
59
  'Revm' => '10000',
61
60
  'DvTy' => @device_type,
62
61
  'RemN' => 'Remote',
63
62
  'txtvers' => '1',
64
63
  'Pair' => @pair
65
- })
64
+ )
66
65
  end
67
66
 
68
67
  def generate_pairing_string(pair, name, device_type)
@@ -73,4 +72,4 @@ module DACPClient
73
72
  end.to_dmap
74
73
  end
75
74
  end
76
- end
75
+ end
@@ -0,0 +1,21 @@
1
+ module DACPClient
2
+ Tag = Struct.new(:type, :value) do
3
+ def to_s
4
+ "#<#{self.class.name} #{type}>"
5
+ end
6
+
7
+ def inspect(level = 0)
8
+ "#{' ' * level}#{type}: #{value}"
9
+ end
10
+
11
+ def to_dmap
12
+ value = self.value
13
+ if type.type == :container
14
+ value = value.reduce('') { |a, e| a + e.to_dmap }
15
+ else
16
+ value = DMAPConverter.encode(type.type, value)
17
+ end
18
+ type.tag.to_s + [value.length].pack('N') + value
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module DACPClient
2
+ # The TagContainer class is a Tag which contains other Tags
3
+ class TagContainer < Tag
4
+ def initialize(type = nil, value = [])
5
+ super type, value
6
+ end
7
+
8
+ def inspect(level = 0)
9
+ "#{' ' * level}#{type}:\n" + value.reduce('') do |a, e|
10
+ a + e.inspect(level + 1).chomp + "\n"
11
+ end
12
+ end
13
+
14
+ def get_value(key)
15
+ return value[key] if key.is_a? Fixnum
16
+
17
+ key = key.to_s
18
+ val = value.find { |e| e.type.tag == key }
19
+ val = value.find { |e| e.type.name == key } if val.nil?
20
+
21
+ if val.type.type == :container
22
+ val
23
+ elsif !val.nil?
24
+ val.value
25
+ end
26
+ end
27
+
28
+ alias_method :[], :get_value
29
+
30
+ def has?(key)
31
+ key = key.to_s
32
+ val = value.find { |e| e.type.tag == key }
33
+ val = value.find { |e| e.type.name == key } if val.nil?
34
+ !val.nil?
35
+ end
36
+
37
+ def method_missing(method, *arguments, &block)
38
+ if has?(method)
39
+ get_value(method)
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ def to_a
46
+ value
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ require 'dacpclient/tag'
2
+ require 'dacpclient/tag_container'
3
+
4
+ module DACPClient
5
+ # The TagDefinition class describes the tags
6
+ TagDefinition = Struct.new(:tag, :type, :name) do
7
+ def inspect
8
+ "#{tag} (#{name}: #{type})"
9
+ end
10
+
11
+ def to_s
12
+ "#{tag} (#{name}: #{type})"
13
+ end
14
+
15
+ class << self
16
+ def find(key)
17
+ @@tags[key.to_s]
18
+ end
19
+
20
+ def tag(*args, &block)
21
+ @@tags ||= Hash.new(nil)
22
+ definition = new(*args, &block).freeze
23
+ @@tags[definition.tag.to_s] = definition
24
+ end
25
+
26
+ alias_method :[], :find
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,167 @@
1
+ require 'dacpclient/tag_definition'
2
+ module DACPClient
3
+ # Sources:
4
+ # https://github.com/chendo/dmap-ng/blob/master/lib/dmap/tag_definitions.rb
5
+ # https://code.google.com/p/ytrack/wiki/DMAP
6
+ # https://code.google.com/p/tunesremote-se/wiki/ContentCodes
7
+ # https://raw.github.com/mattstevens/dmap-parser/master/dmap_parser.c
8
+ # /content-codes
9
+ class TagDefinition
10
+ tag 'mcon', :container, 'dmap.container'
11
+ tag 'msrv', :container, 'dmap.serverinforesponse'
12
+ tag 'msml', :container, 'dmap.msml'
13
+ tag 'mccr', :container, 'dmap.contentcodesresponse'
14
+ tag 'mdcl', :container, 'dmap.dictionary'
15
+ tag 'mlog', :container, 'dmap.loginresponse'
16
+ tag 'mupd', :container, 'dmap.updateresponse'
17
+ tag 'avdb', :container, 'daap.serverdatabases'
18
+ tag 'mlcl', :container, 'dmap.listing'
19
+ tag 'mlit', :container, 'dmap.listingitem'
20
+ tag 'mbcl', :container, 'dmap.bag'
21
+ tag 'adbs', :container, 'daap.returndatabasesongs'
22
+ tag 'aply', :container, 'daap.databaseplaylists'
23
+ tag 'apso', :container, 'daap.playlistsongs'
24
+ tag 'mudl', :container, 'dmap.deletedidlisting'
25
+ tag 'abro', :container, 'daap.databasebrowse'
26
+ tag 'abal', :container, 'daap.browsealbumlisting'
27
+ tag 'abar', :container, 'daap.browseartistlisting'
28
+ tag 'abcp', :container, 'daap.browsecomposerlisting'
29
+ tag 'abgn', :container, 'daap.browsegenrelisting'
30
+ tag 'prsv', :container, 'daap.resolve'
31
+ tag 'arif', :container, 'daap.resolveinfo'
32
+ tag 'casp', :container, 'dacp.speakers'
33
+ tag 'caci', :container, 'dacp.controlint'
34
+ tag 'cmpa', :container, 'dacp.pairinganswer'
35
+ tag 'cacr', :container, 'dacp.cacr'
36
+ tag 'cmcp', :container, 'dmcp.controlprompt'
37
+ tag 'cmgt', :container, 'dmcp.getpropertyresponse'
38
+ tag 'cmst', :container, 'dmcp.status'
39
+ tag 'agal', :container, 'daap.albumgrouping'
40
+ tag 'minm', :string, 'dmap.itemname'
41
+ tag 'msts', :string, 'dmap.statusstring'
42
+ tag 'mcna', :string, 'dmap.contentcodesname'
43
+ tag 'asal', :string, 'daap.songalbum'
44
+ tag 'asaa', :string, 'daap.songalbumartist'
45
+ tag 'asar', :string, 'daap.songartist'
46
+ tag 'ascm', :string, 'daap.songcomment'
47
+ tag 'asfm', :string, 'daap.songformat'
48
+ tag 'aseq', :string, 'daap.songeqpreset'
49
+ tag 'asgn', :string, 'daap.songgenre'
50
+ tag 'asdt', :string, 'daap.songdescription'
51
+ tag 'asul', :string, 'daap.songdataurl'
52
+ tag 'ceWM', :string, 'com.apple.itunes.welcome-message'
53
+ tag 'ascp', :string, 'daap.songcomposer'
54
+ tag 'assu', :string, 'daap.sortartist'
55
+ tag 'assa', :string, 'daap.sortalbum'
56
+ tag 'agrp', :string, 'daap.songgrouping'
57
+ tag 'cann', :string, 'daap.nowplayingtrack'
58
+ tag 'cana', :string, 'daap.nowplayingartist'
59
+ tag 'canl', :string, 'daap.nowplayingalbum'
60
+ tag 'cang', :string, 'daap.nowplayinggenre'
61
+ tag 'cmnm', :string, 'dacp.devicename'
62
+ tag 'cmty', :string, 'dacp.devicetype'
63
+ tag 'cmpg', :hex, 'dacp.pairingguid' # hex string
64
+ tag 'mper', :uint64, 'dmap.persistentid'
65
+ tag 'canp', :uint64, 'dacp.nowplaying'
66
+ tag 'cmpy', :uint64, 'dacp.passguid'
67
+ tag 'mstt', :uint32, 'dmap.status' # http status??
68
+ tag 'mcnm', :uint32, 'dmap.contentcodesnumber'
69
+ tag 'miid', :uint32, 'dmap.itemid'
70
+ tag 'mcti', :uint32, 'dmap.containeritemid'
71
+ tag 'mpco', :uint32, 'dmap.parentcontainerid'
72
+ tag 'mimc', :uint32, 'dmap.itemcount'
73
+ tag 'mrco', :uint32, 'dmap.returnedcount'
74
+ tag 'mtco', :uint32, 'dmap.containercount'
75
+ tag 'mstm', :uint32, 'dmap.timeoutinterval'
76
+ tag 'msdc', :uint32, 'dmap.databasescount'
77
+ tag 'msma', :uint32, 'dmap.speakermachineaddress'
78
+ tag 'mlid', :uint32, 'dmap.sessionid'
79
+ tag 'assr', :uint32, 'daap.songsamplerate'
80
+ tag 'assz', :uint32, 'daap.songsize'
81
+ tag 'asst', :uint32, 'daap.songstarttime'
82
+ tag 'assp', :uint32, 'daap.songstoptime'
83
+ tag 'astm', :uint32, 'daap.songtime'
84
+ tag 'msto', :uint32, 'dmap.utcoffset'
85
+ tag 'cmsr', :uint32, 'dmcp.mediarevision'
86
+ tag 'caas', :uint32, 'dacp.albumshuffle'
87
+ tag 'caar', :uint32, 'dacp.albumrepeat'
88
+ tag 'cant', :uint32, 'dacp.remainingtime'
89
+ tag 'cmmk', :uint32, 'dmcp.mediakind'
90
+ tag 'cast', :uint32, 'dacp.tracklength'
91
+ tag 'asai', :uint32, 'daap.songalbumid'
92
+ tag 'aeNV', :uint32, 'com.apple.itunes.norm-volume'
93
+ tag 'cmvo', :uint32, 'dmcp.volume'
94
+ tag 'mcty', :uint16, 'dmap.contentcodestype'
95
+ tag 'asbt', :uint16, 'daap.songsbeatsperminute'
96
+ tag 'asbr', :uint16, 'daap.songbitrate'
97
+ tag 'asdc', :uint16, 'daap.songdisccount'
98
+ tag 'asdn', :uint16, 'daap.songdiscnumber'
99
+ tag 'astc', :uint16, 'daap.songtrackcount'
100
+ tag 'astn', :uint16, 'daap.songtracknumber'
101
+ tag 'asyr', :uint16, 'daap.songyear'
102
+ tag 'ated', :uint16, 'daap.supportsextradata'
103
+ tag 'asgr', :uint16, 'daap.supportsgroups'
104
+ tag 'mikd', :byte, 'dmap.itemkind'
105
+ tag 'casu', :byte, 'dacp.su'
106
+ tag 'msau', :byte, 'dmap.authenticationmethod'
107
+ tag 'mstu', :byte, 'dmap.updatetype'
108
+ tag 'asrv', :byte, 'daap.songrelativevolume'
109
+ tag 'asur', :byte, 'daap.songuserrating'
110
+ tag 'asdk', :byte, 'daap.songdatakind'
111
+ tag 'caps', :byte, 'dacp.playstatus'
112
+ tag 'cash', :byte, 'dacp.shufflestate'
113
+ tag 'carp', :byte, 'dacp.repeatstate'
114
+ tag 'muty', :byte, 'dmap.updatetype'
115
+ tag "f\215ch", :byte, 'dmap.haschildcontainers'
116
+ tag 'msas', :byte, 'dmap.authenticationschemes'
117
+ tag 'cavs', :bool, 'dacp.visualizer'
118
+ tag 'cafs', :bool, 'dacp.fullscreen'
119
+ tag 'ceGS', :bool, 'com.apple.itunes.genius-selectable'
120
+ tag 'mslr', :bool, 'dmap.loginrequired'
121
+ tag 'msal', :bool, 'dmap.supportsautologout'
122
+ tag 'msup', :bool, 'dmap.supportsupdate'
123
+ tag 'mspi', :bool, 'dmap.supportspersistenids'
124
+ tag 'msex', :bool, 'dmap.supportsextensions'
125
+ tag 'msbr', :bool, 'dmap.supportsbrowse'
126
+ tag 'msqy', :bool, 'dmap.supportsquery'
127
+ tag 'msix', :bool, 'dmap.supportsindex'
128
+ tag 'msrs', :bool, 'dmap.supportsresolve'
129
+ tag 'asco', :bool, 'daap.songcompliation'
130
+ tag 'asdb', :bool, 'daap.songdisabled'
131
+ tag 'abpl', :bool, 'daap.baseplaylist'
132
+ tag 'aeSP', :bool, 'com.apple.itunes.smart-playlist'
133
+ tag 'aePP', :bool, 'com.apple.itunes.is-podcast-playlist'
134
+ tag 'aePS', :bool, 'com.apple.itunes.special-playlist'
135
+ tag 'aeSG', :bool, 'com.apple.itunes.saved-genius'
136
+ tag 'aeFP', :bool, 'com.apple.itunes.req-fplay'
137
+ tag 'aeHV', :bool, 'com.apple.itunes.has-video'
138
+ tag 'caia', :bool, 'dacp.isavailiable'
139
+ tag 'caip', :bool, 'dacp.isplaying'
140
+ tag 'ceVO', :bool, 'com.apple.itunes.voting-enabled'
141
+ tag 'aeSV', :version, 'com.apple.itunes.music-sharing-version'
142
+ tag 'mpro', :version, 'dmap.protocolversion'
143
+ tag 'apro', :version, 'daap.protocolversion'
144
+ tag 'musr', :version, 'dmap.serverrevision'
145
+ tag 'mstc', :date, 'dmap.utc-time'
146
+ tag 'asda', :date, 'daap.songdateadded'
147
+ tag 'asdm', :date, 'daap.songdatemodified'
148
+ tag 'ceJC', :bool, 'com.apple.itunes.jukebox-client-vote'
149
+ tag 'ceJI', :bool, 'com.apple.itunes.jukebox-current'
150
+ tag 'ceJS', :uint16, 'com.apple.itunes.jukebox-score'
151
+ tag 'ceJV', :bool, 'com.apple.itunes.jukebox-vote'
152
+ tag 'ceQR', :container, 'com.apple.itunes.playqueue-contents-response'
153
+ tag 'ceQS', :container, 'com.apple.itunes.playqueue-contents-???'
154
+ tag 'ceQs', :uint64, 'com.apple.itunes.playqueue-id'
155
+ tag 'ceQa', :string, 'com.apple.itunes.playqueue-album'
156
+ tag 'ceQg', :string, 'com.apple.itunes.playqueue-genre'
157
+ tag 'ceQn', :string, 'com.apple.itunes.playqueue-name'
158
+ tag 'ceQr', :string, 'com.apple.itunes.playqueue-artist'
159
+ tag 'msml', :container, 'msml'
160
+ tag 'aeGs', :bool, 'com.apple.itunes.can-be-genius-seed'
161
+ tag 'aprm', :short, 'daap.playlistrepeatmode'
162
+ tag 'apsm', :short, 'daap.playlistshufflemode'
163
+ tag 'cmpr', :version, 'dmcp.protocolversion'
164
+ tag 'capr', :version, 'dacp.protocolversion'
165
+ tag 'ppro', :version, 'unknown.version'
166
+ end
167
+ end
@@ -1,4 +1,4 @@
1
1
  # The DACPClient module
2
2
  module DACPClient
3
- VERSION = '0.1.1'
4
- end
3
+ VERSION = '0.2.0'
4
+ end
data/lib/dacpclient.rb CHANGED
@@ -1 +1 @@
1
- require 'dacpclient/client'
1
+ require 'dacpclient/client'
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.1.1
4
+ version: 0.2.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: 2013-08-13 00:00:00.000000000 Z
11
+ date: 2013-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dnssd
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.8
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.8.8
41
+ - !ruby/object:Gem::Dependency
42
+ name: plist
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 3.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.1.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: yard
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +94,48 @@ dependencies:
66
94
  - - '>='
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 5.2.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 5.2.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.15.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 0.15.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
69
139
  description: A DACP (iTunes Remote protocol) client
70
140
  email:
71
141
  - email@jurriaanpruis.nl
@@ -85,12 +155,16 @@ files:
85
155
  - bin/dacpclient
86
156
  - dacpclient.gemspec
87
157
  - lib/dacpclient.rb
158
+ - lib/dacpclient/bonjour.rb
88
159
  - lib/dacpclient/client.rb
89
160
  - lib/dacpclient/dmapbuilder.rb
90
161
  - lib/dacpclient/dmapconverter.rb
91
162
  - lib/dacpclient/dmapparser.rb
92
163
  - lib/dacpclient/pairingserver.rb
93
- - lib/dacpclient/tagdefinitions.rb
164
+ - lib/dacpclient/tag.rb
165
+ - lib/dacpclient/tag_container.rb
166
+ - lib/dacpclient/tag_definition.rb
167
+ - lib/dacpclient/tag_definitions.rb
94
168
  - lib/dacpclient/version.rb
95
169
  homepage: https://github.com/jurriaan/ruby-dacpclient
96
170
  licenses:
@@ -104,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
178
  requirements:
105
179
  - - '>='
106
180
  - !ruby/object:Gem::Version
107
- version: 1.9.3
181
+ version: 2.0.0
108
182
  required_rubygems_version: !ruby/object:Gem::Requirement
109
183
  requirements:
110
184
  - - '>='
@@ -112,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
186
  version: '0'
113
187
  requirements: []
114
188
  rubyforge_project:
115
- rubygems_version: 2.0.5
189
+ rubygems_version: 2.1.11
116
190
  signing_key:
117
191
  specification_version: 4
118
192
  summary: A DACP (iTunes Remote protocol) client