daapclient 0.1.0 → 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.
- data/CHANGELOG +36 -0
- data/EXAMPLES +79 -0
- data/LICENSE +340 -0
- data/NOTES +33 -0
- data/README +7 -31
- data/lib/net/daap.rb +34 -20
- data/lib/net/daap/album.rb +16 -0
- data/lib/net/daap/artist.rb +16 -0
- data/lib/net/daap/daap_version.rb +7 -0
- data/lib/net/daap/database.rb +54 -27
- data/lib/net/daap/dmap.rb +13 -24
- data/lib/net/daap/playlist.rb +4 -5
- data/lib/net/daap/song.rb +10 -8
- data/test/data/mt-daapd/02dd88de4b3a69c74bcc56c1acca9ae5.txt +0 -0
- data/test/data/mt-daapd/0de583b288d8ae30f89acb26d4c8535b.txt +0 -0
- data/test/data/mt-daapd/4146ec82a0f0a638db9293a0c2039e6b.txt +0 -0
- data/test/data/mt-daapd/51a2a6f2a53743bec7e79fe0d074dd28.txt +0 -0
- data/test/data/mt-daapd/6069971903eef3c8c71ec2c7b395bfeb.txt +0 -0
- data/test/data/mt-daapd/{e9a8e709c2116651157182f130207048.txt → 7102a16e834342b8264f1fb5226690e5.txt} +0 -0
- data/test/data/mt-daapd/9d29fb31969da7757fa2f4baa3a52fe9.txt +0 -0
- data/test/data/mt-daapd/a52dd33cc99471cc156528c06b22e709.txt +0 -0
- data/test/data/mt-daapd/a600829e59b3d719b32f25323a2719b0.txt +0 -0
- data/test/data/mt-daapd/e2552df8d742fe31d6cc6e1e41e496b3.txt +0 -0
- data/test/data/mt-daapd/fc631aa54b83344df9ccf1fbaa7684b0.txt +0 -0
- data/test/data/song_data.txt +0 -0
- data/test/data/song_structure.txt +209 -0
- data/test/mock_server.rb +56 -0
- data/test/server_saver.rb +31 -0
- data/test/tc_artists.rb +33 -0
- data/test/tc_client.rb +47 -116
- data/test/tc_download.rb +29 -0
- data/test/tc_playlist.rb +37 -0
- data/test/tc_protocol.rb +3 -0
- data/test/test_daap.rb +23 -0
- data/test/ts_daap.rb +7 -0
- metadata +41 -97
- data/doc/classes/Net.html +0 -127
- data/doc/classes/Net/DAAP.html +0 -168
- data/doc/classes/Net/DAAP/Client.html +0 -269
- data/doc/classes/Net/DAAP/Client.src/M000003.html +0 -20
- data/doc/classes/Net/DAAP/Client.src/M000004.html +0 -28
- data/doc/classes/Net/DAAP/Client.src/M000005.html +0 -33
- data/doc/classes/Net/DAAP/Client.src/M000006.html +0 -37
- data/doc/classes/Net/DAAP/Client.src/M000007.html +0 -20
- data/doc/classes/Net/DAAP/Client.src/M000008.html +0 -24
- data/doc/classes/Net/DAAP/Client.src/M000009.html +0 -18
- data/doc/classes/Net/DAAP/DAAPv2.html +0 -165
- data/doc/classes/Net/DAAP/DAAPv2.src/M000016.html +0 -30
- data/doc/classes/Net/DAAP/DAAPv2.src/M000017.html +0 -21
- data/doc/classes/Net/DAAP/DAAPv3.html +0 -178
- data/doc/classes/Net/DAAP/DAAPv3.src/M000018.html +0 -30
- data/doc/classes/Net/DAAP/DAAPv3.src/M000019.html +0 -23
- data/doc/classes/Net/DAAP/DMAP.html +0 -176
- data/doc/classes/Net/DAAP/DMAP.src/M000013.html +0 -20
- data/doc/classes/Net/DAAP/DMAP.src/M000014.html +0 -18
- data/doc/classes/Net/DAAP/DMAP.src/M000015.html +0 -24
- data/doc/classes/Net/DAAP/Database.html +0 -224
- data/doc/classes/Net/DAAP/Database.src/M000010.html +0 -25
- data/doc/classes/Net/DAAP/Database.src/M000011.html +0 -21
- data/doc/classes/Net/DAAP/Database.src/M000012.html +0 -35
- data/doc/classes/Net/DAAP/Playlist.html +0 -192
- data/doc/classes/Net/DAAP/Playlist.src/M000001.html +0 -24
- data/doc/classes/Net/DAAP/Playlist.src/M000002.html +0 -30
- data/doc/classes/Net/DAAP/Song.html +0 -208
- data/doc/classes/Net/DAAP/Song.src/M000020.html +0 -27
- data/doc/classes/Net/DAAP/Song.src/M000021.html +0 -19
- data/doc/created.rid +0 -1
- data/doc/files/CHANGELOG.html +0 -134
- data/doc/files/LICENSE.html +0 -531
- data/doc/files/README.html +0 -182
- data/doc/files/lib/net/daap/database_rb.html +0 -101
- data/doc/files/lib/net/daap/dmap_rb.html +0 -101
- data/doc/files/lib/net/daap/playlist_rb.html +0 -101
- data/doc/files/lib/net/daap/song_rb.html +0 -101
- data/doc/files/lib/net/daap_rb.html +0 -114
- data/doc/fr_class_index.html +0 -35
- data/doc/fr_file_index.html +0 -34
- data/doc/fr_method_index.html +0 -47
- data/doc/index.html +0 -24
- data/doc/rdoc-style.css +0 -208
- data/lib/CVS/Entries +0 -1
- data/lib/CVS/Repository +0 -1
- data/lib/CVS/Root +0 -1
- data/lib/net/CVS/Entries +0 -2
- data/lib/net/CVS/Repository +0 -1
- data/lib/net/CVS/Root +0 -1
- data/lib/net/daap/CVS/Entries +0 -5
- data/lib/net/daap/CVS/Repository +0 -1
- data/lib/net/daap/CVS/Root +0 -1
- data/test/CVS/Entries +0 -4
- data/test/CVS/Repository +0 -1
- data/test/CVS/Root +0 -1
- data/test/data/CVS/Entries +0 -1
- data/test/data/CVS/Repository +0 -1
- data/test/data/CVS/Root +0 -1
- data/test/data/mt-daapd/079aca35773150da9fd98db10c7fd0c0.txt +0 -0
- data/test/data/mt-daapd/2972f65088b42a06b5d3ca089d71791d.txt +0 -0
- data/test/data/mt-daapd/440c2217e6207c54c317c296f71f9769.txt +0 -0
- data/test/data/mt-daapd/4d1ce9f941cbd823ed06f1f1baa5a3b9.txt +0 -0
- data/test/data/mt-daapd/7bded8b540fd082f102d25e181b47bc4.txt +0 -0
- data/test/data/mt-daapd/CVS/Entries +0 -11
- data/test/data/mt-daapd/CVS/Repository +0 -1
- data/test/data/mt-daapd/CVS/Root +0 -1
- data/test/data/mt-daapd/b3e894b87111bdba88e4765967f4b45a.txt +0 -0
- data/test/data/mt-daapd/d56b699830e77ba53855679cb1d252da.txt +0 -0
- data/test/data/mt-daapd/e61ce3062cb76770658896b778ad06cd.txt +0 -0
- data/test/data/mt-daapd/f9073959a0afacebfab7e3bf19c2714a.txt +0 -0
data/NOTES
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
= Net::DAAP::Client Release Notes
|
|
2
|
+
|
|
3
|
+
== 0.2.0
|
|
4
|
+
|
|
5
|
+
Net::DAAP::Client has a newer, extended interface. In addition to the song
|
|
6
|
+
list that the database already contained, there is now a list of artists and
|
|
7
|
+
a list of albums that you can access from the database. The artists contain
|
|
8
|
+
all of the albums associated with that artists, and each album has all the songs
|
|
9
|
+
for that album. Each artist contains all songs by that artist as well.
|
|
10
|
+
|
|
11
|
+
For example, to access all songs by one artist, one could do this:
|
|
12
|
+
|
|
13
|
+
db.artists.find { |a| a.name == 'Radiohead' '}.songs.each { |s|
|
|
14
|
+
puts s.name
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Or, to access all of Radiohead's albums, one could do this:
|
|
18
|
+
|
|
19
|
+
db.artists.find { |a| a.name == 'Radiohead' '}.albums.each { |a|
|
|
20
|
+
puts a.name
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
An exhaustive example can be seen in the EXAMPLES file.
|
|
24
|
+
|
|
25
|
+
This version of Net::DAAP::Client relies on digest-m4p which can be obtained
|
|
26
|
+
from the project page here[http://rubyforge.org/frs/?group_id=1155].
|
|
27
|
+
Unfortunately I can't get digest-m4p to build on Windows (I don't have a
|
|
28
|
+
windows machine), so for now digest-m4p only works on Linux and OS X.
|
|
29
|
+
Hopefully someone can send me a patch (hint hint).
|
|
30
|
+
|
|
31
|
+
Also, because of a bug in RubyGems, digest-m4p cannot be released as a gem
|
|
32
|
+
until I find a workaround, or the new version of RubyGems gets released.
|
|
33
|
+
|
data/README
CHANGED
|
@@ -3,18 +3,14 @@
|
|
|
3
3
|
This library is used for browsing iTunes DAAP servers.
|
|
4
4
|
|
|
5
5
|
Most of this is based off the work in the perl version by Richard Clamp which
|
|
6
|
-
can be found here
|
|
7
|
-
|
|
8
|
-
http://search.cpan.org/~rclamp/
|
|
6
|
+
can be found here[http://search.cpan.org/~rclamp/].
|
|
9
7
|
|
|
10
8
|
Ruby version is by Aaron Patterson <aaronp@rubyforge.org>
|
|
11
9
|
|
|
12
10
|
== Installation
|
|
13
11
|
|
|
14
12
|
Make sure that Digest::M4P is installed before using this package. Digest::M4P
|
|
15
|
-
is available on the daap client ruby forge site
|
|
16
|
-
|
|
17
|
-
http://rubyforge.org/frs/?group_id=1155
|
|
13
|
+
is available on the daap client ruby forge site here[http://rubyforge.org/frs/?group_id=1155].
|
|
18
14
|
|
|
19
15
|
Digest::M4P has not been turned in to a Ruby gem as of this writing.
|
|
20
16
|
|
|
@@ -22,33 +18,13 @@ After that, just install the gem:
|
|
|
22
18
|
|
|
23
19
|
sudo gem install daapclient
|
|
24
20
|
|
|
25
|
-
Also, check out the project page
|
|
26
|
-
|
|
27
|
-
http://rubyforge.org/projects/daapclient
|
|
21
|
+
Also, check out the project page here[http://rubyforge.org/projects/daapclient].
|
|
28
22
|
|
|
29
23
|
== Example Usage
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
daap = Net::DAAP::Client.new('localhost')
|
|
35
|
-
|
|
36
|
-
daap.connect do |dsn|
|
|
37
|
-
daap.databases do |db|
|
|
38
|
-
puts "All songs in the database"
|
|
39
|
-
db.songs do |song|
|
|
40
|
-
filename = "#{song.artist} - #{song.name}.#{song.format}"
|
|
41
|
-
directory = "db/#{song.album}"
|
|
42
|
-
FileUtils::mkdir_p(directory)
|
|
43
|
-
|
|
44
|
-
File.open("#{directory}/#{filename}", "w") do |f|
|
|
45
|
-
song.get { |str| f.write str }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
== Acknowledgements
|
|
25
|
+
See the EXAMPLES[link://files/EXAMPLES.html] file
|
|
26
|
+
|
|
27
|
+
== Acknowledgments
|
|
52
28
|
|
|
53
29
|
The library is mostly a port of the Perl library, and owes most of its
|
|
54
30
|
communication logic to the original Perl version by Richard Clamp.
|
|
@@ -62,5 +38,5 @@ favorite language! ;-)
|
|
|
62
38
|
|
|
63
39
|
== License
|
|
64
40
|
|
|
65
|
-
This library is distributed under the GPL. Please see the LICENSE file.
|
|
41
|
+
This library is distributed under the GPL. Please see the LICENSE[link://files/LICENSE.html] file.
|
|
66
42
|
|
data/lib/net/daap.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
require 'net/http'
|
|
2
2
|
require 'digest/m4p'
|
|
3
3
|
require 'digest/md5'
|
|
4
|
+
require 'logger'
|
|
4
5
|
require 'net/daap/dmap'
|
|
6
|
+
require 'net/daap/artist'
|
|
7
|
+
require 'net/daap/album'
|
|
5
8
|
require 'net/daap/song'
|
|
6
9
|
require 'net/daap/playlist'
|
|
7
10
|
require 'net/daap/database'
|
|
11
|
+
require 'net/daap/daap_version'
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
module Net
|
|
@@ -46,22 +50,29 @@ module Net
|
|
|
46
50
|
# and each Database can have many Playlist, and many Song. See DAAP for a
|
|
47
51
|
# code example.
|
|
48
52
|
class Client
|
|
53
|
+
attr_accessor :log
|
|
49
54
|
attr_reader :dmap
|
|
50
55
|
|
|
51
56
|
# Create a new Client and pass in the host where the client will connect.
|
|
52
57
|
def initialize(server_host)
|
|
53
58
|
@server_host = server_host
|
|
54
59
|
@server_port = 3689
|
|
55
|
-
@
|
|
60
|
+
@validator = nil
|
|
61
|
+
@log = Logger.new(nil)
|
|
62
|
+
@session_id = nil
|
|
63
|
+
@request_id = nil
|
|
64
|
+
yield self if block_given?
|
|
56
65
|
end
|
|
57
66
|
|
|
58
67
|
# Connects to the iTunes server. This method should be called right after
|
|
59
68
|
# construction. See DAAP for an example.
|
|
60
69
|
def connect
|
|
70
|
+
@log.info("Connecting to #{@server_host}:#{@server_port}")
|
|
61
71
|
@http_client = Net::HTTP.start(@server_host, @server_port)
|
|
62
72
|
find_validator
|
|
63
73
|
@dmap = Net::DAAP::DMAP.new(:daap => self)
|
|
64
74
|
load_server_info
|
|
75
|
+
@log.info("Now connected")
|
|
65
76
|
@connected = 1
|
|
66
77
|
if block_given?
|
|
67
78
|
yield @dsn
|
|
@@ -73,15 +84,18 @@ module Net
|
|
|
73
84
|
|
|
74
85
|
# Returns the databases found on the iTunes server.
|
|
75
86
|
def databases
|
|
76
|
-
|
|
87
|
+
unless @connected
|
|
88
|
+
errstr = "Not connected, can't fetch databases"
|
|
89
|
+
@log.error(errstr)
|
|
90
|
+
raise errstr
|
|
91
|
+
end
|
|
77
92
|
|
|
78
93
|
listings = @dmap.find(do_get("databases"),
|
|
79
94
|
"daap.serverdatabases/dmap.listing")
|
|
80
95
|
# FIXME check the value of listing
|
|
81
96
|
@databases = []
|
|
82
97
|
unpack_listing(listings) do |value|
|
|
83
|
-
db = Database.new(
|
|
84
|
-
:daap => self )
|
|
98
|
+
db = Database.new( value.merge(:daap => self) )
|
|
85
99
|
if block_given?
|
|
86
100
|
yield db
|
|
87
101
|
else
|
|
@@ -92,19 +106,20 @@ module Net
|
|
|
92
106
|
end
|
|
93
107
|
|
|
94
108
|
def do_get(request, &block)
|
|
95
|
-
debug("do_get")
|
|
109
|
+
@log.debug("do_get called")
|
|
96
110
|
url = String.new('/' + request)
|
|
97
111
|
if @session_id
|
|
98
112
|
url += url =~ /\?/ ? "&" : "?"
|
|
99
113
|
url += "session-id=#{@session_id}"
|
|
100
114
|
end
|
|
101
115
|
|
|
102
|
-
if @revision && request != "logout"
|
|
103
|
-
|
|
104
|
-
end
|
|
105
|
-
debug(url)
|
|
116
|
+
#if @revision && request != "logout"
|
|
117
|
+
# url += "&revision-number=#{@revision}"
|
|
118
|
+
#end
|
|
119
|
+
@log.debug("Fetching url: #{url}")
|
|
106
120
|
|
|
107
121
|
res = @http_client.get(url, request_headers(url), nil, &block)
|
|
122
|
+
@log.debug("Done Fetching url: #{url}")
|
|
108
123
|
|
|
109
124
|
content_type = res.header['content-type']
|
|
110
125
|
if request !~ /(?:\/items\/\d+\.|logout)/ && content_type !~ /dmap/
|
|
@@ -115,8 +130,8 @@ module Net
|
|
|
115
130
|
end
|
|
116
131
|
|
|
117
132
|
def get_song(request, &block)
|
|
118
|
-
@
|
|
119
|
-
@request_id
|
|
133
|
+
@log.debug("Downloading a song")
|
|
134
|
+
@request_id = @request_id.nil? ? 2 : @request_id + 1
|
|
120
135
|
do_get(request, &block)
|
|
121
136
|
end
|
|
122
137
|
|
|
@@ -132,17 +147,19 @@ module Net
|
|
|
132
147
|
|
|
133
148
|
# Disconnects from the DAAP server
|
|
134
149
|
def disconnect
|
|
150
|
+
@log.info("Disconnecting")
|
|
135
151
|
do_get("logout")
|
|
136
152
|
end
|
|
153
|
+
|
|
137
154
|
private
|
|
138
155
|
def load_server_info
|
|
139
156
|
flat_list = @dmap.flat_list(do_get("server-info"))
|
|
140
157
|
@dsn = flat_list['/dmap.serverinforesponse/dmap.itemname']
|
|
141
158
|
|
|
142
|
-
debug("Connected to share '#{@dsn}'")
|
|
159
|
+
@log.debug("Connected to share '#{@dsn}'")
|
|
143
160
|
@session_id = @dmap.find(do_get("login"),
|
|
144
161
|
"dmap.loginresponse/dmap.sessionid")
|
|
145
|
-
debug("My id is #{@session_id}")
|
|
162
|
+
@log.debug("My id is #{@session_id}")
|
|
146
163
|
@dsn
|
|
147
164
|
end
|
|
148
165
|
|
|
@@ -157,23 +174,20 @@ module Net
|
|
|
157
174
|
headers
|
|
158
175
|
end
|
|
159
176
|
|
|
177
|
+
# Figure out what protocol version to use
|
|
160
178
|
def find_validator
|
|
179
|
+
@log.info("Determining DAAP version")
|
|
161
180
|
res = @http_client.get('/server-info')
|
|
162
181
|
server = res.header['daap-server']
|
|
163
182
|
|
|
164
183
|
if server =~ /^iTunes\/4.2/
|
|
165
184
|
@validator = DAAPv2.new
|
|
185
|
+
@log.info("Found DAAPv2")
|
|
166
186
|
end
|
|
167
187
|
|
|
168
188
|
if server =~ /^iTunes/
|
|
169
189
|
@validator = DAAPv3.new
|
|
170
|
-
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def debug(message)
|
|
174
|
-
if @debug == 1
|
|
175
|
-
print "DEBUG: "
|
|
176
|
-
p message
|
|
190
|
+
@log.info("Found DAAPv3")
|
|
177
191
|
end
|
|
178
192
|
end
|
|
179
193
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Net
|
|
2
|
+
module DAAP
|
|
3
|
+
# This class contains album information returned from the DAAP server.
|
|
4
|
+
class Album
|
|
5
|
+
attr_reader :name, :artist, :songs
|
|
6
|
+
|
|
7
|
+
alias :to_s :name
|
|
8
|
+
|
|
9
|
+
def initialize(args)
|
|
10
|
+
@name = args[:name] || args['daap.songalbum']
|
|
11
|
+
@artist = args[:artist]
|
|
12
|
+
@songs = []
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Net
|
|
2
|
+
module DAAP
|
|
3
|
+
# This class contains artist information returned from the DAAP server.
|
|
4
|
+
class Artist
|
|
5
|
+
attr_reader :name, :albums, :songs
|
|
6
|
+
|
|
7
|
+
alias :to_s :name
|
|
8
|
+
|
|
9
|
+
def initialize(args)
|
|
10
|
+
@name = args[:name] || args['daap.songartist']
|
|
11
|
+
@albums = []
|
|
12
|
+
@songs = []
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/net/daap/database.rb
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
def attr_blockreader(*syms)
|
|
3
|
+
syms.each do |sym|
|
|
4
|
+
class_eval %{ def #{sym.to_s}
|
|
5
|
+
if block_given?
|
|
6
|
+
@#{sym.to_s}.each \{ |s| yield s \}
|
|
7
|
+
end
|
|
8
|
+
@#{sym.to_s}
|
|
9
|
+
end
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
1
15
|
module Net
|
|
2
16
|
module DAAP
|
|
3
17
|
# This class contains a database found on an iTunes server.
|
|
4
18
|
class Database
|
|
5
19
|
attr_reader :persistentid, :name, :containercount, :id, :itemcount
|
|
6
|
-
|
|
20
|
+
attr_blockreader :songs, :artists, :albums
|
|
21
|
+
|
|
7
22
|
@@SONG_ATTRIBUTES = %w{ dmap.itemid dmap.itemname dmap.persistentid
|
|
8
23
|
daap.songalbum daap.songartist daap.songformat
|
|
9
24
|
daap.songsize }
|
|
10
25
|
|
|
11
26
|
def initialize(args)
|
|
12
|
-
|
|
13
|
-
@
|
|
14
|
-
@
|
|
15
|
-
@
|
|
16
|
-
@
|
|
17
|
-
@itemcount = info['dmap.itemcount']
|
|
27
|
+
@persistentid = args['dmap.persistentid']
|
|
28
|
+
@name = args['dmap.itemname']
|
|
29
|
+
@containercount = args['dmap.containercount']
|
|
30
|
+
@id = args['dmap.itemid']
|
|
31
|
+
@itemcount = args['dmap.itemcount']
|
|
18
32
|
@daap = args[:daap]
|
|
19
|
-
@songs =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def songs
|
|
24
|
-
if block_given?
|
|
25
|
-
@songs.each { |s| yield s }
|
|
26
|
-
end
|
|
27
|
-
@songs
|
|
33
|
+
@songs = []
|
|
34
|
+
@artists = []
|
|
35
|
+
@albums = []
|
|
36
|
+
load_songs
|
|
28
37
|
end
|
|
29
38
|
|
|
30
39
|
# Returns the playlists associated with this database
|
|
@@ -36,14 +45,13 @@ module Net
|
|
|
36
45
|
|
|
37
46
|
playlists = []
|
|
38
47
|
@daap.unpack_listing(listings) do |value|
|
|
48
|
+
playlist = Playlist.new( value.merge(
|
|
49
|
+
:daap => @daap,
|
|
50
|
+
:db => self ))
|
|
39
51
|
if block_given?
|
|
40
|
-
yield
|
|
41
|
-
:daap => @daap,
|
|
42
|
-
:db => self )
|
|
52
|
+
yield playlist
|
|
43
53
|
else
|
|
44
|
-
playlists <<
|
|
45
|
-
:daap => @daap,
|
|
46
|
-
:db => self )
|
|
54
|
+
playlists << playlist
|
|
47
55
|
end
|
|
48
56
|
end
|
|
49
57
|
playlists
|
|
@@ -56,13 +64,32 @@ module Net
|
|
|
56
64
|
|
|
57
65
|
listings = @daap.dmap.find(@daap.do_get(path),
|
|
58
66
|
"daap.databasesongs/dmap.listing")
|
|
59
|
-
|
|
67
|
+
artist_hash = {}
|
|
68
|
+
album_hash = {}
|
|
60
69
|
@daap.unpack_listing(listings) do |value|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
artist = artist_hash[value['daap.songartist']] ||= Artist.new(value)
|
|
71
|
+
album = album_hash[value['daap.songalbum']] ||= Album.new(
|
|
72
|
+
:name => value['daap.songalbum'],
|
|
73
|
+
:artist => artist )
|
|
74
|
+
|
|
75
|
+
song = Song.new( value.merge(
|
|
76
|
+
:daap => @daap,
|
|
77
|
+
:db => self,
|
|
78
|
+
:artist => artist,
|
|
79
|
+
:album => album))
|
|
80
|
+
|
|
81
|
+
album.songs << song
|
|
82
|
+
artist.songs << song
|
|
83
|
+
@songs << song
|
|
64
84
|
end
|
|
65
|
-
|
|
85
|
+
|
|
86
|
+
# Add each album to its artist
|
|
87
|
+
album_hash.each_value do |value|
|
|
88
|
+
value.artist.albums << value
|
|
89
|
+
@albums << value
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
artist_hash.each_value { |v| @artists << v }
|
|
66
93
|
end
|
|
67
94
|
end
|
|
68
95
|
end
|
data/lib/net/daap/dmap.rb
CHANGED
|
@@ -4,8 +4,9 @@ module Net
|
|
|
4
4
|
# structures.
|
|
5
5
|
class DMAP
|
|
6
6
|
def initialize(args)
|
|
7
|
-
@daap
|
|
8
|
-
|
|
7
|
+
@daap = args[:daap]
|
|
8
|
+
@big_endian = "Ruby".unpack("i")[0] != 2036495698 ? true : false
|
|
9
|
+
@type_to_unpack = find_type
|
|
9
10
|
update_content_codes
|
|
10
11
|
end
|
|
11
12
|
|
|
@@ -24,9 +25,9 @@ module Net
|
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
private
|
|
27
|
-
def
|
|
28
|
+
def find_type
|
|
28
29
|
types = nil
|
|
29
|
-
if big_endian
|
|
30
|
+
if @big_endian
|
|
30
31
|
types = {
|
|
31
32
|
1 => 'c',
|
|
32
33
|
3 => 'S',
|
|
@@ -52,11 +53,6 @@ module Net
|
|
|
52
53
|
types
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
def big_endian?
|
|
56
|
-
return @big_endian if @big_endian
|
|
57
|
-
@big_endian = "Ruby".unpack("i")[0] != 2036495698 ? true : false
|
|
58
|
-
end
|
|
59
|
-
|
|
60
56
|
def update_content_codes
|
|
61
57
|
content_codes = unpack(@daap.do_get("content-codes"))
|
|
62
58
|
mccr = seek(content_codes, "dmap.contentcodesresponse")
|
|
@@ -70,10 +66,8 @@ module Net
|
|
|
70
66
|
end
|
|
71
67
|
type = 9 if id == 'mcnm'
|
|
72
68
|
type = 42 if id == 'pfdt'
|
|
73
|
-
|
|
69
|
+
@@types[id] = { 'NAME' => name, 'ID' => id, 'TYPE' => type }
|
|
74
70
|
end
|
|
75
|
-
#@types = short
|
|
76
|
-
@types
|
|
77
71
|
end
|
|
78
72
|
|
|
79
73
|
def flat_list_traverse(struct, list = [], prefix = '')
|
|
@@ -94,12 +88,10 @@ module Net
|
|
|
94
88
|
def unpack(buffer = nil)
|
|
95
89
|
tags = []
|
|
96
90
|
|
|
97
|
-
buffer = @code unless buffer
|
|
98
|
-
|
|
99
91
|
while(buffer.length > 0)
|
|
100
92
|
tag, len = nil, nil
|
|
101
93
|
|
|
102
|
-
if big_endian
|
|
94
|
+
if @big_endian
|
|
103
95
|
tag, len = buffer.unpack("a4L")
|
|
104
96
|
else
|
|
105
97
|
tag, len = buffer.unpack("a4N")
|
|
@@ -109,22 +101,22 @@ module Net
|
|
|
109
101
|
|
|
110
102
|
buffer[0...8+len] = ''
|
|
111
103
|
|
|
112
|
-
type =
|
|
104
|
+
type = @@types[tag]['TYPE']
|
|
113
105
|
|
|
114
106
|
if type == 12
|
|
115
107
|
data = unpack(data)
|
|
116
108
|
elsif type == 7
|
|
117
|
-
n1, n2 = big_endian
|
|
109
|
+
n1, n2 = @big_endian ? data.unpack("L2") : data.unpack("N2")
|
|
118
110
|
data = n1 << 32
|
|
119
111
|
data += n2
|
|
120
112
|
else
|
|
121
|
-
data = data.unpack(type_to_unpack
|
|
113
|
+
data = data.unpack(@type_to_unpack[type])
|
|
122
114
|
end
|
|
123
115
|
|
|
124
116
|
if data.class == Array && data.length == 1 && data[0].class != Array || type == 11
|
|
125
|
-
tmp = [
|
|
117
|
+
tmp = [ @@types[tag]['NAME'], data[0]]
|
|
126
118
|
else
|
|
127
|
-
tmp = [
|
|
119
|
+
tmp = [ @@types[tag]['NAME'], data]
|
|
128
120
|
end
|
|
129
121
|
|
|
130
122
|
tags << tmp
|
|
@@ -148,9 +140,7 @@ module Net
|
|
|
148
140
|
return struct
|
|
149
141
|
end
|
|
150
142
|
|
|
151
|
-
|
|
152
|
-
def load_types
|
|
153
|
-
@types =
|
|
143
|
+
@@types =
|
|
154
144
|
{
|
|
155
145
|
'abal' => {
|
|
156
146
|
'ID' => 'abal',
|
|
@@ -598,7 +588,6 @@ module Net
|
|
|
598
588
|
'TYPE' => 11
|
|
599
589
|
}
|
|
600
590
|
}
|
|
601
|
-
end
|
|
602
591
|
end
|
|
603
592
|
end
|
|
604
593
|
end
|