Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/library/parserm3u.cpp

Go to the documentation of this file.
00001 //
00002 // C++ Implementation: parserm3u
00003 //
00004 // Description: module to parse m3u(plaintext) formated playlists
00005 //
00006 //
00007 // Author: Ingo Kossyk <kossyki@cs.tu-berlin.de>, (C) 2004
00008 // Author: Tobias Rafreider trafreider@mixxx.org, (C) 2011
00009 //
00010 // Copyright: See COPYING file that comes with this distribution
00011 //
00012 //
00013 #include <QTextStream>
00014 #include <QDebug>
00015 #include <QDir>
00016 #include <QMessageBox>
00017 #include "parserm3u.h"
00018 #include <QUrl>
00019 #include <QTextCodec>
00020 
00040 ParserM3u::ParserM3u() : Parser()
00041 {
00042 }
00043 
00044 ParserM3u::~ParserM3u()
00045 {
00046 
00047 }
00048 
00049 
00050 QList<QString> ParserM3u::parse(QString sFilename)
00051 {
00052     QFile file(sFilename);
00053     QString basepath = sFilename.section('/', 0, -2);
00054 
00055     clearLocations();
00056     //qDebug() << "ParserM3u: Starting to parse.";
00057     if (file.open(QIODevice::ReadOnly) && !isBinary(sFilename)) {
00058         /* Unfortunately, QT 4.7 does not handle <CR> (=\r or asci value 13) line breaks.
00059          * This is important on OS X where iTunes, e.g., exports M3U playlists using <CR>
00060          * rather that <LF>
00061          *
00062          * Using QFile::readAll() we obtain the complete content of the playlist as a ByteArray.
00063          * We replace any '\r' with '\n' if applicaple
00064          * This ensures that playlists from iTunes on OS X can be parsed
00065          */
00066         QByteArray ba = file.readAll();
00067         //detect encoding
00068         bool isCRLF_encoded = ba.contains("\r\n");
00069         bool isCR_encoded = ba.contains("\r");
00070         if(isCR_encoded && !isCRLF_encoded)
00071             ba.replace('\r','\n');
00072         QTextStream textstream(ba.data());
00073 
00074         if (isUtf8(ba.data())) {
00075             textstream.setCodec("UTF-8");
00076         } else {
00077             textstream.setCodec("windows-1252");
00078         }
00079 
00080         while(!textstream.atEnd()) {
00081             QString sLine = getFilepath(&textstream, basepath);
00082             if(sLine.isEmpty())
00083                 break;
00084 
00085             //qDebug() << "ParserM3u: parsed: " << (sLine);
00086             m_sLocations.append(sLine);
00087         }
00088 
00089         file.close();
00090 
00091         if(m_sLocations.count() != 0)
00092             return m_sLocations;
00093         else
00094             return QList<QString>(); // NULL pointer returned when no locations were found
00095 
00096     }
00097 
00098     file.close();
00099     return QList<QString>(); //if we get here something went wrong
00100 }
00101 
00102 
00103 QString ParserM3u::getFilepath(QTextStream *stream, QString basepath)
00104 {
00105     QString textline,filename = "";
00106 
00107     textline = stream->readLine();
00108 
00109     while(!textline.isEmpty()){
00110         //qDebug() << "Untransofrmed text: " << textline;
00111         if(textline.isNull())
00112             break;
00113 
00114         if(!textline.contains("#")){
00115             filename = textline;
00116             filename.remove("file://");
00117             QByteArray strlocbytes = filename.toUtf8();
00118             //qDebug() << "QByteArray UTF-8: " << strlocbytes;
00119             QUrl location = QUrl::fromEncoded(strlocbytes);
00120             //qDebug() << "QURL UTF-8: " << location;
00121             QString trackLocation = location.toString();
00122             //qDebug() << "UTF8 TrackLocation:" << trackLocation;
00123             if(isFilepath(trackLocation)) {
00124                 return trackLocation;
00125             } else {
00126                 // Try relative to m3u dir
00127                 QString rel = basepath + "/" + trackLocation;
00128                 if (isFilepath(rel)) {
00129                     return rel;
00130                 }
00131                 // We couldn't match this to a real file so ignore it
00132             }
00133         }
00134         textline = stream->readLine();
00135     }
00136 
00137     // Signal we reached the end
00138     return 0;
00139 
00140 }
00141 
00142 bool ParserM3u::writeM3UFile(const QString &file_str, QList<QString> &items, bool useRelativePath) {
00143     return writeM3UFile(file_str, items, useRelativePath, false);
00144 }
00145 
00146 bool ParserM3u::writeM3U8File(const QString &file_str, QList<QString> &items, bool useRelativePath) {
00147     return writeM3UFile(file_str, items, useRelativePath, true);
00148 }
00149 
00150 bool ParserM3u::writeM3UFile(const QString &file_str, QList<QString> &items, bool useRelativePath, bool useUtf8)
00151 {
00152     // Important note:
00153     // On Windows \n will produce a <CR><CL> (=\r\n)
00154     // On Linux and OS X \n is <CR> (which remains \n)
00155 
00156     QTextCodec* codec;
00157     if (useUtf8) {
00158         codec = QTextCodec::codecForName("UTF-8");
00159     } else {
00160         // according to http://en.wikipedia.org/wiki/M3U the default encoding of m3u is Windows-1252
00161         // see also http://tools.ietf.org/html/draft-pantos-http-live-streaming-07
00162         // check if the all items can be properly encoded to Latin1.
00163         codec = QTextCodec::codecForName("windows-1252");
00164         for (int i = 0; i < items.size(); ++i) {
00165             if (!codec->canEncode(items.at(i))) {
00166                 // filepath contains incompatible character
00167                 QMessageBox::warning(NULL,tr("Playlist Export Failed"),
00168                                      tr("File path contains characters, not allowed in m3u playlists.\n") +
00169                                      tr("Export a m3u8 playlist instead!\n") +
00170                                      items.at(i));
00171                 return false;
00172             }
00173         }
00174     }
00175 
00176     QFile file(file_str);
00177     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
00178         QMessageBox::warning(NULL,tr("Playlist Export Failed"),
00179                              tr("Could not create file") + " " + file_str);
00180         return false;
00181     }
00182 
00183     // Base folder of file
00184     QString base = file_str.section('/', 0, -2);
00185     QDir base_dir(base);
00186 
00187     qDebug() << "Basepath: " << base;
00188     QTextStream out(&file);
00189     out.setCodec(codec);
00190     out << "#EXTM3U\n";
00191     for (int i = 0; i < items.size(); ++i) {
00192         out << "#EXTINF\n";
00193         // Write relative path if possible
00194         if (useRelativePath) {
00195             //QDir::relativePath() will return the absolutePath if it cannot compute the
00196             //relative Path
00197             out << base_dir.relativeFilePath(items.at(i)) << "\n";
00198         } else {
00199             out << items.at(i) << "\n";
00200         }
00201     }
00202     return true;
00203 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines