SVN commit 637191 by metz: - clean up handling of relative paths and urls, m3u files with relative paths seem to be working again - No "Stream from foo.bar.com" naming anymore, we cannot reliably determine if a file is streamable just by looking at its url M +1 -1 noatun/playlistsaver.h M +127 -139 playlistsaver.cpp --- trunk/KDE/kdemultimedia/noatun/library/noatun/playlistsaver.h #637190:637191 @@ -118,7 +118,7 @@ bool loadXML(const QString &file); bool loadASX(const QString &file, const KUrl &originalUrl); bool loadM3U(const QString &file, const KUrl &originalUrl); - bool loadPLS(const QString &file); + bool loadPLS(const QString &file, const KUrl &originalUrl); bool saveXML(QTextStream &stream); bool saveM3U(QTextStream &stream); --- trunk/KDE/kdemultimedia/noatun/library/playlistsaver.cpp #637190:637191 @@ -165,7 +165,7 @@ if (mt == "audio/mpegurl" || mt == "audio/x-mpegurl" || mt == "application/m3u") res = loadM3U(localFile, url); else if (mt == "audio/x-scpls") - res = loadPLS(localFile); + res = loadPLS(localFile, url); else if (mt == "audio/x-ms-asx") res = loadASX(localFile, url); else if (mt == "text/xml") @@ -178,17 +178,11 @@ return res; } - const QString &PlaylistSaver::lastMimeType() const { return mLastMimeType; } - - - - - bool PlaylistSaver::save(QFile &file, const QString &mt) // private { QTextStream stream(&file); @@ -203,42 +197,8 @@ } -bool PlaylistSaver::saveXML(QTextStream &stream) -{ - const PlaylistItem &i = PlaylistItem(); - QDomDocument doc("playlist"); - doc.setContent(QString("")); - QDomElement docElem = doc.documentElement(); - reset(); - while ((i = writeItem())) - { - // write all properties - const QStringList &props = i.properties(); - QDomElement elem = doc.createElement("item"); - - foreach(const QString &propertyName, props) - { - QString propertyValue = i.property(propertyName); - elem.setAttribute(propertyName, propertyValue); - - /*if (propertyName == "url") - { - KUrl u(val); - if (u.isLocalFile()) - elem.setAttribute("local", u.path()); - }*/ - } - docElem.appendChild(elem); - } - - stream.setCodec(QTextCodec::codecForName("UTF-8")); - stream << doc.toString(); - return true; -} - - class NoatunXMLStructure : public QXmlDefaultHandler { public: @@ -450,7 +410,6 @@ }; - bool PlaylistSaver::loadASX(const QString &file, const KUrl &originalUrl) { kDebug(66666) << k_funcinfo << "url:" << originalUrl << endl; @@ -463,7 +422,7 @@ QXmlInputSource source(&f); QXmlSimpleReader reader; - MSASXStructure ASXparser(this, originalUrl.path()); // path() argument? TODO KDE4 + MSASXStructure ASXparser(this, originalUrl.path()); reader.setContentHandler(&ASXparser); reader.parse(source); return !ASXparser.fresh; @@ -490,6 +449,7 @@ bool PlaylistSaver::loadM3U(const QString &file, const KUrl &originalUrl) { + kDebug(66666) << k_funcinfo << "originalUrl: " << originalUrl << endl; QFile f(file); if (!f.open(QIODevice::ReadOnly)) return false; @@ -499,28 +459,29 @@ bool isExt = false; // flag telling if we load an EXTM3U file QString filename; QString extinf; - Noatun::PropertyMap prop; reset(); while (!t.atEnd()) { + Noatun::PropertyMap prop; + if (isExt) { - extinf = t.readLine(); + extinf = t.readLine().trimmed(); if (!extinf.startsWith("#EXTINF:")) { filename = extinf; - extinf=""; + extinf.clear(); } else { - filename = t.readLine(); // read in second line containing the filename + filename = t.readLine().trimmed(); // read in second line containing the filename } } else // old style m3u { - filename = t.readLine(); + filename = t.readLine().trimmed(); } if (filename == "#EXTM3U") // on first line @@ -532,44 +493,33 @@ if (filename.isEmpty()) continue; - if (filename.contains(QRegExp("^[a-zA-Z][a-zA-Z0-9]*:/"))) - { - //kDebug(66666) << k_funcinfo << "url filename = " << filename << endl; + kDebug(66666) << k_funcinfo << "filename: '" << filename << "'" << endl; - KUrl protourl(filename); - KMimeType::Ptr mimetype = KMimeType::findByUrl(protourl); - - if (mimetype->name() != "application/octet-stream") - { - prop["url"] = filename; - } - else - { - //prop["playObject"]="SplayPlayObject"; - // Default title, might be overwritten by #EXTINF later - prop["title"] = i18n("Stream from %1",protourl.host()); - - if (!protourl.hasPath()) - protourl.setPath("/"); - - prop["url"] = protourl.url(); - prop["stream_"] = prop["url"]; - } + if (filename.contains(QRegExp("^[a-zA-Z0-9]*:/"))) + { + // filename is url-style (i.e. "proto:/foo" format) + KUrl fileUrl(QUrl::toPercentEncoding(filename)); + /*if (KMimeType::findByUrl(fileUrl)->name() == "application/octet-stream") + prop["title"] = i18n("Stream from %1", fileUrl.host());*/ + prop["url"] = fileUrl.url(); } - else // filename that is not of URL style (i.e. NOT "proto:/path/somefile") + else { - KUrl u1; - // we have to deal with a relative path - if (filename.contains('/')) + // filename that is not in url-style (i.e. plain path without a protocol) + + KUrl localUrl; + if (KUrl::isRelativeUrl(filename)) { - u1.setPath(originalUrl.path()); - u1.setFileName(filename); + // prepend path from playlist file + localUrl.setPath(originalUrl.path()); + // append filename + localUrl.setFileName(filename); } else { - u1.setPath(filename); + localUrl = KUrl::fromPath(filename); } - prop["url"] = u1.url(); + prop["url"] = localUrl.url(); } // parse line of the following format: @@ -599,14 +549,94 @@ } // END !displayTitle.isEmpty() } // END if(isExt) + // pass properties list to playlist + kDebug(66666) << k_funcinfo << "prop:" << prop << endl; readItem(prop); - prop.clear(); } // END while() return true; } +static QString findNoCase(const Noatun::PropertyMap &map, const QString &key) +{ + Noatun::PropertyMap::ConstIterator it(map.begin()); + Noatun::PropertyMap::ConstIterator end(map.end()); + const QString lowerKey = key.toLower(); + for ( ; it != end; ++it) + { + if (it.key().toLower() == lowerKey) + return it.value(); + } + return QString(); +} +bool PlaylistSaver::loadPLS(const QString &file, const KUrl &originalUrl) +{ + kDebug(66666) << k_funcinfo << endl; + QFile checkFile(file); + if (!checkFile.open(QIODevice::ReadOnly)) + return false; + QTextStream t(&checkFile); + QString firstLine = t.readLine().trimmed().toLower(); + if (firstLine != "[playlist]") + { + kWarning(66666) << "PLS file '" << file << + "' did not start with '[playlist]', aborting loading" << endl; + return false; + } + checkFile.close(); + + KConfig list(file, KConfig::OnlyLocal); + // some windows users like to be case insensitive, oh my + QStringList groups = list.groupList().filter(QRegExp("^playlist$", Qt::CaseInsensitive)); + QMap group = list.entryMap(groups[0]); + + QString numOfEntries = findNoCase(group, "numberofentries"); + if(numOfEntries.isEmpty()) + return false; + + reset(); + + unsigned int nEntries = numOfEntries.toUInt(); + for(unsigned int entry = 1; entry <= nEntries; ++entry ) + { + Noatun::PropertyMap prop; + + QString filename = findNoCase(group, "file"+QString::number(entry)); + QString title = findNoCase(group, "title"+QString::number(entry)); + + kDebug(66666) << k_funcinfo << "filename:" << filename << endl; + + KUrl fileUrl; + if (filename.contains(QRegExp("^[a-zA-Z0-9]*:/"))) + { + fileUrl = KUrl(QUrl::toPercentEncoding(filename)); + } + else + { + if (KUrl::isRelativeUrl(filename)) + { + // prepend path from playlist file + fileUrl.setPath(originalUrl.path()); + // append filename + fileUrl.setFileName(filename); + } + else + { + fileUrl = KUrl::fromPath(filename); + } + } + + prop["url"] = fileUrl.url(); + if (!title.isEmpty()) + prop["title"] = title; + + kDebug(66666) << k_funcinfo << "prop:" << prop << endl; + readItem(prop); + } + return true; +} + bool PlaylistSaver::saveM3U(QTextStream &stream) { reset(); @@ -649,73 +679,31 @@ return true; } - -static QString findNoCase(const Noatun::PropertyMap &map, const QString &key) +bool PlaylistSaver::saveXML(QTextStream &stream) { - Noatun::PropertyMap::ConstIterator it(map.begin()); - Noatun::PropertyMap::ConstIterator end(map.end()); - const QString lowerKey = key.toLower(); - for ( ; it != end; ++it) - { - if (it.key().toLower() == lowerKey) - return it.value(); - } - return QString(); -} + const PlaylistItem &i = PlaylistItem(); + QDomDocument doc("playlist"); + doc.setContent(QString("")); + QDomElement docElem = doc.documentElement(); - -bool PlaylistSaver::loadPLS(const QString &file) -{ - QFile checkFile(file); - if (!checkFile.open(QIODevice::ReadOnly)) - return false; - QTextStream t(&checkFile); - QString firstLine = t.readLine(); - if(firstLine.toLower() != "[playlist]") - { - kWarning(66666) << - "PLS file '" << file << - "' did not start with '[playlist]', aborting loading" << endl; - return false; - } - checkFile.close(); - - - KConfig list(file, KConfig::OnlyLocal); - // some windows users like to be case insensitive, oh my - QStringList groups = list.groupList().filter(QRegExp("^playlist$", Qt::CaseInsensitive)); - QMap group = list.entryMap(groups[0]); - - QString numOfEntries = findNoCase(group, "numberofentries"); - if(numOfEntries.isEmpty()) - return false; - reset(); - unsigned int nEntries = numOfEntries.toUInt(); - for(unsigned int entry = 1; entry <= nEntries; ++entry ) + while ((i = writeItem())) { - Noatun::PropertyMap map; - QString str; - str.sprintf("file%d", entry); - QString cast = findNoCase(group, str.toUtf8()); - str.sprintf("title%d", entry); - QString title = findNoCase(group, str.toUtf8()); + // write all properties + const QStringList &props = i.properties(); + QDomElement elem = doc.createElement("item"); - // TODO: This assumes that everything in a pls is a streamable file - KUrl url(cast); - if (!url.hasPath()) - url.setPath("/"); - - if (title.isEmpty()) - map["title"] = i18n("Stream from %1 (port: %2)",url.host(), QString::number(url.port())); - else - map["title"] = i18n("Stream from %1, (ip: %2, port: %3)",title, url.host(), QString::number(url.port())); - - map["url"] = map["stream_"] = url.url(); - - readItem(map); + foreach(const QString &propertyName, props) + { + const QString propertyValue = i.property(propertyName); + elem.setAttribute(propertyName, propertyValue); + } + docElem.appendChild(elem); } + + stream.setCodec(QTextCodec::codecForName("UTF-8")); + stream << doc.toString(); return true; }