1 /***************************************************************************
2 * copyright : (C) 2006 Mattias Fliesberg <mattias.fliesberg@gmail.com> *
3 * (C) 2007 Ian Monroe <ian@monroe.nu> *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License or (at your option) version 3 or any later version
9 * accepted by the membership of KDE e.V. (or its successor approved
10 * by the membership of KDE e.V.), which shall act as a proxy
11 * defined in Section 14 of version 3 of the license.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 **************************************************************************/
24 #include "xspfplaylist.h"
26 #include "atomicstring.h"
32 XSPFPlaylist::XSPFPlaylist( )
34 QDomElement root
= createElement( "playlist" );
36 root
.setAttribute( "version", 1 );
37 root
.setAttribute( "xmlns", "http://xspf.org/ns/1/" );
39 root
.appendChild( createElement( "trackList" ) );
44 XSPFPlaylist::XSPFPlaylist( QTextStream
&stream
)
50 XSPFPlaylist::loadXSPF( QTextStream
&stream
)
53 int errorLine
, errorColumn
;
54 stream
.setCodec( "UTF8" );
55 if (!setContent(stream
.readAll(), &errorMsg
, &errorLine
, &errorColumn
))
57 debug() << "[XSPFPlaylist]: Error loading xml file: " "(" << errorMsg
<< ")"
58 << " at line " << errorLine
<< ", column " << errorColumn
;
68 return documentElement().namedItem( "title" ).firstChild().nodeValue();
72 XSPFPlaylist::creator()
74 return documentElement().namedItem( "creator" ).firstChild().nodeValue();
78 XSPFPlaylist::annotation()
80 return documentElement().namedItem( "annotation" ).firstChild().nodeValue();
86 return KUrl( documentElement().namedItem( "info" ).firstChild().nodeValue() );
90 XSPFPlaylist::location()
92 return KUrl( documentElement().namedItem( "location" ).firstChild().nodeValue() );
96 XSPFPlaylist::identifier()
98 return documentElement().namedItem( "identifier" ).firstChild().nodeValue();
102 XSPFPlaylist::image()
104 return KUrl( documentElement().namedItem( "image" ).firstChild().nodeValue() );
110 return QDateTime::fromString( documentElement().namedItem( "date" ).firstChild().nodeValue(), Qt::ISODate
);
114 XSPFPlaylist::license()
116 return KUrl( documentElement().namedItem( "license" ).firstChild().nodeValue() );
120 XSPFPlaylist::attribution()
122 QDomNode node
= documentElement().namedItem( "attribution" );
125 while ( !node
.isNull() )
127 if ( !node
.namedItem( "location" ).firstChild().nodeValue().isNull() )
128 list
.append( node
.namedItem( "location" ).firstChild().nodeValue() );
129 else if ( !node
.namedItem( "identifier" ).firstChild().nodeValue().isNull() )
130 list
.append( node
.namedItem( "identifier" ).firstChild().nodeValue() );
132 node
= node
.nextSibling();
141 return KUrl( documentElement().namedItem( "link" ).firstChild().nodeValue() );
145 XSPFPlaylist::setTitle( QString title
)
147 if ( documentElement().namedItem( "title" ).isNull() )
149 QDomNode node
= createElement( "title" );
150 QDomNode subNode
= createTextNode( title
);
151 node
.appendChild( subNode
);
152 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
155 documentElement().namedItem( "title" ).replaceChild( createTextNode( title
), documentElement().namedItem( "title" ).firstChild() );
159 XSPFPlaylist::setCreator( QString creator
)
161 if ( documentElement().namedItem( "creator" ).isNull() )
163 QDomNode node
= createElement( "creator" );
164 QDomNode subNode
= createTextNode( creator
);
165 node
.appendChild( subNode
);
166 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
169 documentElement().namedItem( "creator" ).replaceChild( createTextNode( creator
), documentElement().namedItem( "creator" ).firstChild() );
173 XSPFPlaylist::setAnnotation( QString annotation
)
175 if ( documentElement().namedItem( "annotation" ).isNull() )
177 QDomNode node
= createElement( "annotation" );
178 QDomNode subNode
= createTextNode( annotation
);
179 node
.appendChild( subNode
);
180 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
183 documentElement().namedItem( "annotation" ).replaceChild( createTextNode( annotation
), documentElement().namedItem( "annotation" ).firstChild() );
187 XSPFPlaylist::setInfo( KUrl info
)
189 if ( documentElement().namedItem( "info" ).isNull() )
191 QDomNode node
= createElement( "info" );
192 QDomNode subNode
= createTextNode( info
.url() );
193 node
.appendChild( subNode
);
194 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
197 documentElement().namedItem( "info" ).replaceChild( createTextNode( info
.url() ), documentElement().namedItem( "info" ).firstChild() );
201 XSPFPlaylist::setLocation( KUrl location
)
203 if ( documentElement().namedItem( "location" ).isNull() )
205 QDomNode node
= createElement( "location" );
206 QDomNode subNode
= createTextNode( location
.url() );
207 node
.appendChild( subNode
);
208 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
211 documentElement().namedItem( "location" ).replaceChild( createTextNode( location
.url() ), documentElement().namedItem( "location" ).firstChild() );
215 XSPFPlaylist::setIdentifier( QString identifier
)
217 if ( documentElement().namedItem( "identifier" ).isNull() )
219 QDomNode node
= createElement( "identifier" );
220 QDomNode subNode
= createTextNode( identifier
);
221 node
.appendChild( subNode
);
222 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
225 documentElement().namedItem( "identifier" ).replaceChild( createTextNode( identifier
), documentElement().namedItem( "identifier" ).firstChild() );
229 XSPFPlaylist::setImage( KUrl image
)
231 if ( documentElement().namedItem( "image" ).isNull() )
233 QDomNode node
= createElement( "image" );
234 QDomNode subNode
= createTextNode( image
.url() );
235 node
.appendChild( subNode
);
236 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
239 documentElement().namedItem( "image" ).replaceChild( createTextNode( image
.url() ), documentElement().namedItem( "image" ).firstChild() );
243 XSPFPlaylist::setDate( QDateTime date
)
245 /* date needs timezone info to be compliant with the standard
246 (ex. 2005-01-08T17:10:47-05:00 ) */
248 if ( documentElement().namedItem( "date" ).isNull() )
250 QDomNode node
= createElement( "date" );
251 QDomNode subNode
= createTextNode( date
.toString( "yyyy-MM-ddThh:mm:ss" ) );
252 node
.appendChild( subNode
);
253 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
256 documentElement().namedItem( "date" ).replaceChild( createTextNode( date
.toString( "yyyy-MM-ddThh:mm:ss" ) ), documentElement().namedItem( "date" ).firstChild() );
260 XSPFPlaylist::setLicense( KUrl license
)
262 if ( documentElement().namedItem( "license" ).isNull() )
264 QDomNode node
= createElement( "license" );
265 QDomNode subNode
= createTextNode( license
.url() );
266 node
.appendChild( subNode
);
267 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
270 documentElement().namedItem( "license" ).replaceChild( createTextNode( license
.url() ), documentElement().namedItem( "license" ).firstChild() );
274 XSPFPlaylist::setAttribution( KUrl attribution
, bool append
)
276 if ( documentElement().namedItem( "attribution" ).isNull() )
277 documentElement().insertBefore( createElement( "attribution" ), documentElement().namedItem( "trackList" ) );
281 QDomNode subNode
= createElement( "location" );
282 QDomNode subSubNode
= createTextNode( attribution
.url() );
283 subNode
.appendChild( subSubNode
);
284 documentElement().namedItem( "attribution" ).insertBefore( subNode
, documentElement().namedItem( "attribution" ).firstChild() );
288 QDomNode node
= createElement( "attribution" );
289 QDomNode subNode
= createElement( "location" );
290 QDomNode subSubNode
= createTextNode( attribution
.url() );
291 subNode
.appendChild( subSubNode
);
292 node
.appendChild( subNode
);
293 documentElement().replaceChild( node
, documentElement().namedItem( "attribution" ) );
298 XSPFPlaylist::setLink( KUrl link
)
300 if ( documentElement().namedItem( "link" ).isNull() )
302 QDomNode node
= createElement( "link" );
303 QDomNode subNode
= createTextNode( link
.url() );
304 node
.appendChild( subNode
);
305 documentElement().insertBefore( node
, documentElement().namedItem( "trackList" ) );
308 documentElement().namedItem( "link" ).replaceChild( createTextNode( link
.url() ), documentElement().namedItem( "link" ).firstChild() );
311 XSPFPlaylist::trackList()
315 QDomNode trackList
= documentElement().namedItem( "trackList" );
316 QDomNode subNode
= trackList
.firstChild();
319 while ( !subNode
.isNull() )
322 subSubNode
= subNode
.firstChild();
323 if ( subNode
.nodeName() == "track" )
325 while ( !subSubNode
.isNull() )
327 if ( subSubNode
.nodeName() == "location" )
328 track
.location
= subSubNode
.firstChild().nodeValue();
329 else if ( subSubNode
.nodeName() == "title" )
330 track
.title
= subSubNode
.firstChild().nodeValue();
331 else if ( subSubNode
.nodeName() == "creator" )
332 track
.creator
= subSubNode
.firstChild().nodeValue();
333 else if ( subSubNode
.nodeName() == "duration" )
334 track
.duration
= subSubNode
.firstChild().nodeValue().toInt();
335 else if ( subSubNode
.nodeName() == "annotation" )
336 track
.annotation
= subSubNode
.firstChild().nodeValue();
337 else if ( subSubNode
.nodeName() == "album" )
338 track
.album
= subSubNode
.firstChild().nodeValue();
339 else if ( subSubNode
.nodeName() == "trackNum" )
340 track
.trackNum
= (uint
)subSubNode
.firstChild().nodeValue().toInt();
341 else if ( subSubNode
.nodeName() == "identifier" )
342 track
.identifier
= subSubNode
.firstChild().nodeValue();
343 else if ( subSubNode
.nodeName() == "info" )
344 track
.info
= subSubNode
.firstChild().nodeValue();
345 else if ( subSubNode
.nodeName() == "image" )
346 track
.image
= subSubNode
.firstChild().nodeValue();
347 else if ( subSubNode
.nodeName() == "link" )
348 track
.link
= subSubNode
.firstChild().nodeValue();
350 subSubNode
= subSubNode
.nextSibling();
353 list
.append( track
);
354 subNode
= subNode
.nextSibling();
361 //documentation of attributes from http://www.xspf.org/xspf-v1.html
363 XSPFPlaylist::setTrackList( Meta::TrackList trackList
, bool append
)
365 if ( documentElement().namedItem( "trackList" ).isNull() )
366 documentElement().appendChild( createElement( "trackList" ) );
368 QDomNode node
= createElement( "trackList" );
370 XSPFtrackList::iterator it
;
372 Meta::TrackPtr track
;
373 foreach( track
, trackList
)
375 QDomNode subNode
= createElement( "track" );
377 //URI of resource to be rendered.
378 QDomNode location
= createElement( "location" );
379 //Human-readable name of the track that authored the resource
380 QDomNode title
= createElement( "title" );
381 //Human-readable name of the entity that authored the resource.
382 QDomNode creator
= createElement( "creator" );
383 //A human-readable comment on the track.
384 QDomNode annotation
= createElement( "annotation" );
385 //Human-readable name of the collection from which the resource comes
386 QDomNode album
= createElement( "album" );
387 //Integer > 0 giving the ordinal position of the media in the album.
388 QDomNode trackNum
= createElement( "trackNum" );
389 //The time to render a resource, in milliseconds. It MUST be a nonNegativeInteger.
390 QDomNode duration
= createElement( "duration" );
392 //identifier - Canonical ID for this resource. Likely to be a hash or other
393 // location-independent name, such as a MusicBrainz identifier. MUST be a legal URI.
394 // QDomNode identifier = createElement( "identifier" );
395 //info - URI of a place where this resource can be bought or more info can be found.
396 // QDomNode info = createElement( "info" );
397 //image - URI of an image to display for the duration of the track.
398 // QDomNode image = createElement( "image" );
399 // link - element allows XSPF to be extended without the use of XML namespaces.
400 // QDomNode link = createElement( "link" );
402 // QDomNode extension
404 #define APPENDNODE( X, Y ) \
406 X.appendChild( createTextNode( Y ) ); \
407 subNode.appendChild( X ); \
410 if ( !track
->playableUrl().isEmpty() )
411 APPENDNODE(location
, track
->playableUrl().url() )
412 if ( !track
->name().isEmpty() )
413 APPENDNODE(title
, track
->name() )
414 if ( track
->artist() && !track
->artist()->name().isEmpty() )
415 APPENDNODE(creator
, track
->artist()->name() );
416 if ( !track
->comment().isEmpty() )
417 APPENDNODE(annotation
, track
->comment() );
418 if ( track
->album() && !track
->album()->name().isEmpty() )
419 APPENDNODE( album
, track
->album()->name() );
420 if ( track
->trackNumber() > 0 )
421 APPENDNODE( trackNum
, QString::number( track
->trackNumber() ) );
422 if ( track
->length() > 0 )
423 APPENDNODE( duration
, QString::number( track
->length() * 1000 ) );
425 node
.appendChild( subNode
);
430 while ( !node
.isNull() )
432 documentElement().namedItem( "trackList" ).appendChild( node
.firstChild() );
433 node
= node
.nextSibling();
437 documentElement().replaceChild( node
, documentElement().namedItem( "trackList" ) );