xspf 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS CHANGED
@@ -1,7 +1,7 @@
1
1
  = Authors
2
2
 
3
3
  Pau Garcia i Quiles <pgquiles at elpauer dot org>
4
- * Developer & maintainer
4
+ * XSPF for Ruby developer & maintainer
5
5
 
6
6
  Lucas Gonze <lgonze at panix dot com>
7
7
  * XSLT templates
data/ChangeLog CHANGED
@@ -1,3 +1,18 @@
1
+ 0.4
2
+
3
+ * XSPF document generator (see examples of use)
4
+
5
+ * Renamed the methods which show the XML code for XSPF and XSPF::Playlist to XSPF#playlist_xml, XSPF::Playlist#tracklist_xml. These methods are now protected and should never be used. If you need to see the XML code, use to_xml
6
+
7
+ * Removed the 'xspf' parameter in to_m3u, to_smil, to_soundblox and to_html
8
+
9
+ * XSPF#playlist always returns a valid XSPF::Playlist object (both in parse and generation modes)
10
+
11
+ * XSPF::Playlist#tracklist always returns a valid XSPF::Tracklist object (both in parse and generation modes)
12
+
13
+ * It is able to eat its own dogfood (but keep in mind the limitations about <attribution>, <extension>, <link> and <meta>)
14
+
15
+
1
16
  0.3
2
17
 
3
18
  * Add methods to export the XSPF document to M3U, HTML, SMIL and SoundBlox
data/README CHANGED
@@ -1,16 +1,13 @@
1
1
  = README: XSPF for Ruby
2
- This library reads and parses a XSPF playlist file. This is release 0.2.
3
-
4
- At this early stage of development, it is not yet possible to write XSPF
5
- files.
2
+ This library parses and generates XSPF playlist documents. This is release 0.4.
6
3
 
7
4
  Current limitations:
8
- - Only read, not write, XSPF files
9
- - For "link" and "extension" elements, only the first one is found
10
- - The "attribution" element is not parsed (the XML content is returned)
11
- - The "extension" element is not parsed (the XML content is returned)
5
+ - For 'link', 'meta' and 'extension' elements, only the first one is parsed and only
6
+ one can be generated
7
+ - The content of the 'attribution' element is not parsed (the XML content is returned)
8
+ - The content of the 'extension' element is not parsed (the XML content is returned)
12
9
 
13
- Homepage:: http://www.elpauer.org/xspf/
10
+ Homepage:: http://xspf.rubyforge.org
14
11
 
15
12
  == Licensing
16
13
  XSPF for Ruby is available under the Ruby license and the GPLv2 license
data/USAGE ADDED
@@ -0,0 +1,350 @@
1
+ :title: USAGE
2
+
3
+ XSPF for Ruby implements a XML Shareable Playlist Format (XSPF[http://www.xspf.org]) v1 parser and generator in pure Ruby. It makes use of REXML to parse and generate the XML code, and Ruby-XSLT to export XSPF to different formats by means of XSLT transformations (XSPF for Ruby includes the XSLT templates by Lucas Gonze in its distribution).
4
+
5
+ The API is quite straightforward if you know the XSPF specification. It is possible to combine parse and generation modes: you may load (parse) a file, then modify some of its attributes or contents and save it to XSPF again.
6
+
7
+ The important thing to remember while using XSPF for Ruby is in generation mode you create objects by passing a hash or nil, and in parse mode you create objects by passing its 'parent' in the XSPF hierarchy.
8
+
9
+ If a XSPF attribute or element is not set, the corresponding method will return _nil_.
10
+
11
+ === Examples
12
+ ==== Parse from file
13
+
14
+ require 'xspf'
15
+
16
+ f = File.new("playlist.xspf")
17
+ x = XSPF.new(f)
18
+ f.close
19
+ pl = XSPF::Playlist.new(x)
20
+ tl = XSPF::Tracklist.new(pl)
21
+
22
+ puts "XML version: #{x.version}"
23
+ puts "XML encoding: #{ x.encoding}"
24
+ puts "XSPF version: #{pl.version}"
25
+ puts "Namespace: #{pl.xmlns}"
26
+ puts "Playlist title: #{pl.title}"
27
+ puts "Playlist creator: #{pl.creator}"
28
+ puts "Playlist annotation: #{pl.annotation}"
29
+ puts "Playlist info: #{pl.info}"
30
+ puts "Playlist identifier: #{pl.identifier}"
31
+ puts "Playlist attribution: #{pl.attribution}"
32
+ puts "Tracklist: #{pl.tracklist}"
33
+ tl.tracks.each do |t|
34
+ puts "Track identifier: #{t.identifier}"
35
+ puts "Track title: #{t.title}"
36
+ puts "Track creator: #{t.creator}"
37
+ puts "Track duration: #{t.duration}"
38
+ puts "Track metainformation: link=#{t.meta_rel} content=#{t.meta_content}"
39
+ end
40
+
41
+ # Convert the XSPF document to SMIL
42
+ x.to_smil
43
+
44
+ # Convert the XSPF document to HTML
45
+ x.to_html
46
+
47
+ # Convert the XSPF document in a M3U playlist
48
+ x.to_m3u
49
+
50
+ ==== Parse from string
51
+
52
+ require 'xspf'
53
+
54
+ playlist_document = <<-END_OF_PLAYLIST
55
+ <?xml version="1.0" encoding="UTF-8"?>
56
+ <playlist version="0" xmlns="http://xspf.org/ns/0/">
57
+ <title>XSPlF it up!</title>
58
+ <creator>Mayhem &amp; Chaos Coordinator</creator>
59
+ <annotation>Just a few songs to enjoy while you XSPlF it up!</annotation>
60
+ <info>http://mayhem-chaos.net/xspf/xspf_it_up.html</info>
61
+ <identifier>http://mayhem-chaos.net/xspf/xspf_it_up/1.0</identifier>
62
+ <attribution>
63
+ <location>ihttp://mayhem-chaos.net/xspf/xspf_it_up.html</location>
64
+ </attribution>
65
+ <trackList>
66
+ <track>
67
+ <identifier>http://musicbrainz.org/track/bdab6db0-2fd6-4166-a5fa-fbf2ff213793</identifier>
68
+ <title>I Wanna Get High</title>
69
+ <creator>Cypress Hill</creator>
70
+ <duration>174613</duration>
71
+ <meta rel="http://musicbrainz.org/track">http://musicbrainz.org/mm-2.1/track/bdab6db0-2fd6-4166-a5fa-fbf2ff213793</meta>
72
+ </track>
73
+ <track>
74
+ <identifier>bdc846e7-6c26-4193-82a6-8d1b5a4d3429</identifier>
75
+ <title>Smoke Two Joints</title>
76
+ <creator>Sublime</creator>
77
+ <duration>175466</duration>
78
+ <meta rel="http://musicbrainz.org/track">http://musicbrainz.org/mm-2.1/track/bdc846e7-6c26-4193-82a6-8d1b5a4d3429</meta>
79
+ </track>
80
+ <track>
81
+ <identifier>http://musicbrainz.org/track/7d9776f7-d428-40dc-a425-3c6e3dce4d58</identifier>
82
+ <title>Hash Pipe</title>
83
+ <creator>Weezer</creator>
84
+ <duration>186533</duration>
85
+ <meta rel="http://musicbrainz.org/track">http://musicbrainz.org/mm-2.1/track/7d9776f7-d428-40dc-a425-3c6e3dce4d58</meta>
86
+ </track>
87
+ </trackList>
88
+ </playlist>
89
+ END_OF_PLAYLIST
90
+
91
+ x = XSPF.new(playlist_document)
92
+ pl = XSPF::Playlist.new(x)
93
+ tl = XSPF::Tracklist.new(pl)
94
+
95
+ puts "XML version: #{x.version}"
96
+ puts "XML encoding: #{ x.encoding}"
97
+ puts "XSPF version: #{pl.version}"
98
+ puts "Namespace: #{pl.xmlns}"
99
+ puts "Playlist title: #{pl.title}"
100
+ puts "Playlist creator: #{pl.creator}"
101
+ puts "Playlist annotation: #{pl.annotation}"
102
+ puts "Playlist info: #{pl.info}"
103
+ puts "Playlist identifier: #{pl.identifier}"
104
+ puts "Playlist attribution: #{pl.attribution}"
105
+ puts "Tracklist: #{pl.tracklist}"
106
+ tl.tracks.each do |t|
107
+ puts "Track identifier: #{t.identifier}"
108
+ puts "Track title: #{t.title}"
109
+ puts "Track creator: #{t.creator}"
110
+ puts "Track duration: #{t.duration}"
111
+ puts "Track metainformation: link=#{t.meta_rel} content=#{t.meta_content}"
112
+ end
113
+
114
+ # Convert the XSPF document to SMIL
115
+ x.to_smil
116
+
117
+ # Convert the XSPF document to HTML
118
+ x.to_html
119
+
120
+ # Convert the XSPF document in a M3U playlist
121
+ x.to_m3u
122
+
123
+ ==== Generate
124
+
125
+ require 'xspf'
126
+
127
+ track1 = XSPF::Track.new( {
128
+ :location => 'http://some.nifty.locati.on/file1.ogg',
129
+ :identifier => 'http://musicbrainz.org/track/9f342af1-982d-4c26-9f61-3ac258957a83', :title => 'Plus au sud',
130
+ :creator => 'Yann Tiersen',
131
+ :tracknum => '1',
132
+ :album => 'Tout est calme',
133
+ :meta_rel => 'http://www.example.org/key',
134
+ :meta_content => 'value'
135
+ } )
136
+
137
+ track2 = XSPF::Track.new( {
138
+ :location => 'http://some.nifty.locati.on/file2.ogg',
139
+ :identifier => 'http://musicbrainz.org/track/eba1a9a9-1810-41f1-8cc9-2a00dda0a68c',
140
+ :title => 'Les Grandes Marées',
141
+ :creator => 'Yann Tiersen',
142
+ :tracknum => '2',
143
+ :album => 'Tout est calme',
144
+ :meta_rel => 'http://www.example.org/key',
145
+ :meta_content => 'value'
146
+ } )
147
+
148
+ track3 = XSPF::Track.new( {
149
+ :location => 'http://some.nifty.locati.on/file3.ogg',
150
+ :identifier => 'http://musicbrainz.org/track/0c18ef8c-04fa-47d5-b078-66ab6a819a83',
151
+ :title => 'La Crise',
152
+ :creator => 'Yann Tiersen',
153
+ :tracknum => '3',
154
+ :album => 'Tout est calme',
155
+ :meta_rel => 'http://www.example.org/key',
156
+ :meta_content => 'value'
157
+ } )
158
+
159
+ track4 = XSPF::Track.new( {
160
+ :location => 'http://some.nifty.locati.on/file4.ogg',
161
+ :identifier => 'http://musicbrainz.org/track/0f66dd52-bda0-4526-979d-af95ac637cc4',
162
+ :title => 'Tout est calme',
163
+ :creator => 'Yann Tiersen',
164
+ :tracknum => '4',
165
+ :album => 'Tout est calme',
166
+ :meta_rel => 'http://www.example.org/key',
167
+ :meta_content => 'value'
168
+ } )
169
+
170
+ track5 = XSPF::Track.new( {
171
+ :location => 'http://some.nifty.locati.on/file5.ogg',
172
+ :identifier => 'http://musicbrainz.org/track/a06ef58e-019e-409a-bf72-9bd080012ac3',
173
+ :title => 'La Rupture',
174
+ :creator => 'Yann Tiersen',
175
+ :tracknum => '5',
176
+ :album => 'Tout est calme',
177
+ :meta_rel => 'http://www.example.org/key',
178
+ :meta_content => 'value'
179
+ } )
180
+
181
+ track6 = XSPF::Track.new( {
182
+ :location => 'http://some.nifty.locati.on/file6.ogg',
183
+ :identifier => 'http://musicbrainz.org/track/f82c0a06-d4a8-41a5-9238-029e38fa9d7c',
184
+ :title => 'La Relève',
185
+ :creator => 'Yann Tiersen',
186
+ :tracknum => '6',
187
+ :album => 'Tout est calme',
188
+ :meta_rel => 'http://www.example.org/key',
189
+ :meta_content => 'value'
190
+ } )
191
+
192
+ track7 = XSPF::Track.new( {
193
+ :location => 'http://some.nifty.locati.on/file7.ogg',
194
+ :identifier => 'http://musicbrainz.org/track/97591e2b-967e-47eb-b2b3-9a450cd33352',
195
+ :title => 'La Pharmacie',
196
+ :creator => 'Yann Tiersen',
197
+ :tracknum => '7',
198
+ :album => 'Tout est calme',
199
+ :meta_rel => 'http://www.example.org/key',
200
+ :meta_content => 'value'
201
+ } )
202
+
203
+ track8 = XSPF::Track.new( {
204
+ :location => 'http://some.nifty.locati.on/file8.ogg',
205
+ :identifier => 'http://musicbrainz.org/track/ae7f8502-778d-4f5e-9dba-6fc5d553ad0e',
206
+ :title => 'La Terrasse',
207
+ :creator => 'Yann Tiersen',
208
+ :tracknum => '8',
209
+ :album => 'Tout est calme',
210
+ :meta_rel => 'http://www.example.org/key',
211
+ :meta_content => 'value'
212
+ } )
213
+
214
+ track9 = XSPF::Track.new( {
215
+ :location => 'http://some.nifty.locati.on/file9.ogg',
216
+ :identifier => 'http://musicbrainz.org/track/6e937503-9d01-428c-84b5-1200bab9d1c6',
217
+ :title => "L''Étal",
218
+ :creator => 'Yann Tiersen',
219
+ :tracknum => '9',
220
+ :album => 'Tout est calme',
221
+ :meta_rel => 'http://www.example.org/key',
222
+ :meta_content => 'value'
223
+ } )
224
+
225
+ track10 = XSPF::Track.new( {
226
+ :location => 'http://some.nifty.locati.on/file10.ogg',
227
+ :identifier => 'http://musicbrainz.org/track/2c4c845c-907a-4d96-940a-bbe8b2d0f126',
228
+ :title => 'La Découverte',
229
+ :creator => 'Yann Tiersen',
230
+ :tracknum => '10',
231
+ :album => 'Tout est calme',
232
+ :meta_rel => 'http://www.example.org/key',
233
+ :meta_content => 'value'
234
+ } )
235
+
236
+ tracklist = XSPF::Tracklist.new
237
+
238
+ tracklist << track1
239
+ tracklist << track2
240
+ tracklist << track3
241
+ tracklist << track4
242
+ tracklist << track5
243
+ tracklist << track6
244
+ tracklist << track7
245
+ tracklist << track8
246
+ tracklist << track9
247
+ tracklist << track10
248
+
249
+ playlist = XSPF::Playlist.new( {
250
+ :xmlns => 'http://xspf.org/ns/0/',
251
+ :title => 'Tout est calme',
252
+ :creator => 'Yann Tiersen',
253
+ :license => 'Redistribution or sharing not allowed',
254
+ :info => 'http://www.yanntiersen.com/',
255
+ :tracklist => tracklist,
256
+ :meta_rel => 'http://www.example.org/key',
257
+ :meta_content => 'value'
258
+ } )
259
+
260
+ xspf = XSPF.new( { :playlist => playlist } )
261
+
262
+ f = File.open('playlist.xspf', 'w')
263
+ f.write(xspf.to_xml)
264
+ f.close
265
+
266
+ ==== Parse and generate
267
+
268
+ Say you want to modify an existing XSPF document. What would you do?
269
+
270
+ There are two ways to do it: the right way and the wrong way. The best way to do it is:
271
+
272
+ require 'xspf'
273
+
274
+ f = File.new("playlist.xspf")
275
+ x = XSPF.new(f)
276
+ pl = x.playlist
277
+ tl = pl.tracklist
278
+
279
+ some_other_track = XSPF::Track.new( {
280
+ :location => 'http://some.nifty.locati.on/file1.ogg',
281
+ :identifier => 'http://musicbrainz.org/track/9f342af1-982d-4c26-9f61-3ac258957a83',
282
+ :title => 'Plus au sud',
283
+ :creator => 'Yann Tiersen',
284
+ :tracknum => '1',
285
+ :album => 'Tout est calme',
286
+ :meta_rel => 'http://www.example.org/key',
287
+ :meta_content => 'value'
288
+ } )
289
+
290
+ tl << some_other_track
291
+ pl.title = 'My modified playlist'
292
+ f = File.open('playlist.xspf', 'w')
293
+ f.write(x.to_xml)
294
+ f.close
295
+
296
+ Of course this would also work, but it means more work:
297
+
298
+ require 'xspf'
299
+
300
+ f = File.new("playlist.xspf")
301
+ x = XSPF.new(f)
302
+ pl = XSPF::Playlist.new(x)
303
+ tl = XSPF::Tracklist.new(pl)
304
+
305
+ some_other_track = XSPF::Track.new( {
306
+ :location => 'http://some.nifty.locati.on/file1.ogg',
307
+ :identifier => 'http://musicbrainz.org/track/9f342af1-982d-4c26-9f61-3ac258957a83',
308
+ :title => 'Plus au sud',
309
+ :creator => 'Yann Tiersen',
310
+ :tracknum => '1',
311
+ :album => 'Tout est calme',
312
+ :meta_rel => 'http://www.example.org/key',
313
+ :meta_content => 'value'
314
+ } )
315
+
316
+ tl << some_other_track
317
+ pl.title = 'My modified playlist'
318
+ pl.tracklist = tl
319
+ x.playlist = pl
320
+ f = File.open('playlist.xspf', 'w')
321
+ f.write(x.to_xml)
322
+ f.close
323
+
324
+ This way, which may seem intuitive, is wrong:
325
+
326
+ require 'xspf'
327
+
328
+ f = File.new("playlist.xspf")
329
+ x = XSPF.new(f)
330
+ pl = XSPF::Playlist.new(x)
331
+ tl = XSPF::Tracklist.new(pl)
332
+
333
+ some_other_track = XSPF::Track.new( {
334
+ :location => 'http://some.nifty.locati.on/file1.ogg',
335
+ :identifier => 'http://musicbrainz.org/track/9f342af1-982d-4c26-9f61-3ac258957a83',
336
+ :title => 'Plus au sud',
337
+ :creator => 'Yann Tiersen',
338
+ :tracknum => '1',
339
+ :album => 'Tout est calme',
340
+ :meta_rel => 'http://www.example.org/key',
341
+ :meta_content => 'value'
342
+ } )
343
+
344
+ tl << some_other_track
345
+ pl.title = 'My modified playlist'
346
+ f = File.open('playlist.xspf', 'w')
347
+ f.write(x.to_xml)
348
+ f.close
349
+
350
+ That will not work because 'pl' is a new object, unrelated to 'x'; and 'tl' is a new object, unrelated to 'pl'.
@@ -149,7 +149,7 @@ table.report tr.dark {
149
149
  </head>
150
150
  <body>
151
151
  <h3>C0 code coverage information</h3>
152
- <p>Generated on Fri Oct 20 17:20:35 CEST 2006 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.7.0</a>
152
+ <p>Generated on Mon Oct 30 22:55:21 CET 2006 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.7.0</a>
153
153
  </p>
154
154
  <hr /> <table class='report'>
155
155
  <thead>
@@ -165,21 +165,21 @@ table.report tr.dark {
165
165
  <tr class='light'>
166
166
  <td>TOTAL</td>
167
167
  <td class='value'>
168
- <tt>319</tt>
168
+ <tt>480</tt>
169
169
  </td>
170
170
  <td class='value'>
171
- <tt>126</tt>
171
+ <tt>321</tt>
172
172
  </td>
173
173
  <td>
174
174
  <table cellspacing='0' cellpadding='0' align='right'>
175
175
  <tr>
176
176
  <td>
177
- <tt>95.6%</tt>&nbsp;</td>
177
+ <tt>100.0%</tt>&nbsp;</td>
178
178
  <td>
179
179
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
180
180
  <tr>
181
- <td class='covered' width='96' />
182
- <td class='uncovered' width='4' />
181
+ <td class='covered' width='100' />
182
+ <td class='uncovered' width='0' />
183
183
  </tr>
184
184
  </table>
185
185
  </td>
@@ -190,12 +190,12 @@ table.report tr.dark {
190
190
  <table cellspacing='0' cellpadding='0' align='right'>
191
191
  <tr>
192
192
  <td>
193
- <tt>91.3%</tt>&nbsp;</td>
193
+ <tt>100.0%</tt>&nbsp;</td>
194
194
  <td>
195
195
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
196
196
  <tr>
197
- <td class='covered' width='91' />
198
- <td class='uncovered' width='9' />
197
+ <td class='covered' width='100' />
198
+ <td class='uncovered' width='0' />
199
199
  </tr>
200
200
  </table>
201
201
  </td>
@@ -208,21 +208,21 @@ table.report tr.dark {
208
208
  <a href='lib-xspf_rb.html'>lib/xspf.rb</a>
209
209
  </td>
210
210
  <td class='value'>
211
- <tt>319</tt>
211
+ <tt>480</tt>
212
212
  </td>
213
213
  <td class='value'>
214
- <tt>126</tt>
214
+ <tt>321</tt>
215
215
  </td>
216
216
  <td>
217
217
  <table cellspacing='0' cellpadding='0' align='right'>
218
218
  <tr>
219
219
  <td>
220
- <tt>95.6%</tt>&nbsp;</td>
220
+ <tt>100.0%</tt>&nbsp;</td>
221
221
  <td>
222
222
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
223
223
  <tr>
224
- <td class='covered' width='96' />
225
- <td class='uncovered' width='4' />
224
+ <td class='covered' width='100' />
225
+ <td class='uncovered' width='0' />
226
226
  </tr>
227
227
  </table>
228
228
  </td>
@@ -233,12 +233,12 @@ table.report tr.dark {
233
233
  <table cellspacing='0' cellpadding='0' align='right'>
234
234
  <tr>
235
235
  <td>
236
- <tt>91.3%</tt>&nbsp;</td>
236
+ <tt>100.0%</tt>&nbsp;</td>
237
237
  <td>
238
238
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
239
239
  <tr>
240
- <td class='covered' width='91' />
241
- <td class='uncovered' width='9' />
240
+ <td class='covered' width='100' />
241
+ <td class='uncovered' width='0' />
242
242
  </tr>
243
243
  </table>
244
244
  </td>