Implement playlist saving for XSPF.

This commit is contained in:
John Maguire 2010-05-23 16:26:32 +00:00
parent a59f5a3887
commit 1b76ead951
3 changed files with 78 additions and 0 deletions

View File

@ -16,8 +16,10 @@
#include "xspfparser.h"
#include <QDomDocument>
#include <QFile>
#include <QIODevice>
#include <QRegExp>
#include <QUrl>
#include <QXmlStreamReader>
@ -137,5 +139,52 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
}
void XSPFParser::Save(const SongList &songs, QIODevice *device, const QDir &dir) const {
QDomDocument doc;
QDomElement root = doc.createElement("playlist");
doc.appendChild(root);
QDomElement track_list = doc.createElement("trackList");
root.appendChild(track_list);
foreach (const Song& song, songs) {
QString url;
if (song.filetype() == Song::Type_Stream) {
url = song.filename();
} else {
url = QUrl::fromLocalFile(MakeRelativeTo(song.filename(), dir)).toString();
}
if (url.isEmpty()) {
continue; // Skip empty items like Last.fm streams.
}
QDomElement track = doc.createElement("track");
track_list.appendChild(track);
MaybeAppendElementWithText("location", url, &doc, &track);
MaybeAppendElementWithText("creator", song.artist(), &doc, &track);
MaybeAppendElementWithText("album", song.album(), &doc, &track);
MaybeAppendElementWithText("title", song.title(), &doc, &track);
if (song.length() != -1) {
MaybeAppendElementWithText("duration", QString::number(song.length() * 1000), &doc, &track);
}
QString art = song.art_manual().isEmpty() ? song.art_automatic() : song.art_manual();
// Ignore images that are in our resource bundle.
if (!art.startsWith(":") && !art.isEmpty()) {
// Convert local files to URLs.
if (!art.contains(QRegExp("^\\w+://"))) {
art = QUrl::fromLocalFile(MakeRelativeTo(art, dir)).toString();
}
MaybeAppendElementWithText("image", art, &doc, &track);
}
}
device->write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
device->write(doc.toByteArray(2));
}
void XSPFParser::MaybeAppendElementWithText(
const QString& element_name, const QString& text, QDomDocument* doc, QDomNode* parent) const {
if (text.isEmpty()) {
return;
}
QDomElement element = doc->createElement(element_name);
QDomText t = doc->createTextNode(text);
element.appendChild(t);
parent->appendChild(element);
}

View File

@ -21,6 +21,9 @@
#include <QXmlStreamReader>
class QDomDocument;
class QDomNode;
class XSPFParser : public ParserBase {
Q_OBJECT
@ -37,6 +40,8 @@ class XSPFParser : public ParserBase {
bool ParseUntilElement(QXmlStreamReader* reader, const QString& element) const;
void IgnoreElement(QXmlStreamReader* reader) const;
Song ParseTrack(QXmlStreamReader* reader) const;
void MaybeAppendElementWithText(
const QString& element, const QString& text, QDomDocument* doc, QDomNode* parent) const;
};
#endif

View File

@ -15,12 +15,15 @@
*/
#include "test_utils.h"
#include "gmock/gmock-matchers.h"
#include "gtest/gtest.h"
#include "playlistparsers/xspfparser.h"
#include <QBuffer>
using ::testing::HasSubstr;
class XSPFParserTest : public ::testing::Test {
};
@ -89,3 +92,24 @@ TEST_F(XSPFParserTest, IgnoresInvalidLength) {
ASSERT_EQ(1, songs.length());
EXPECT_EQ(-1, songs[0].length());
}
TEST_F(XSPFParserTest, SavesSong) {
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
XSPFParser parser;
Song one;
one.set_filename("http://www.example.com/foo.mp3");
one.set_filetype(Song::Type_Stream);
one.set_title("foo");
one.set_length(123);
one.set_artist("bar");
SongList songs;
songs << one;
parser.Save(songs, &buffer);
EXPECT_THAT(data.constData(), HasSubstr("<location>http://www.example.com/foo.mp3</location>"));
EXPECT_THAT(data.constData(), HasSubstr("<duration>123000</duration>"));
EXPECT_THAT(data.constData(), HasSubstr("<title>foo</title>"));
EXPECT_THAT(data.constData(), HasSubstr("<creator>bar</creator>"));
}