summaryrefslogtreecommitdiffstats
path: root/src/library/parserpls.cpp
blob: 95c2295429cbc61b215bd07453f98a816b0aa7cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//
// C++ Implementation: parserpls
//
// Description: module to parse pls formatted playlists
//
//
// Author: Ingo Kossyk <kossyki@cs.tu-berlin.de>, (C) 2004
// Author: Tobias Rafreider trafreider@mixxx.org, (C) 2011
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "library/parserpls.h"

#include <QtDebug>
#include <QMessageBox>
#include <QDir>
#include <QFile>
#include <QUrl>

/**
   @author Ingo Kossyk (kossyki@cs.tu-berlin.de)
 **/

/**
   ToDo:
    - parse ALL information from the pls file if available ,
          not only the filepath;
 **/

ParserPls::ParserPls() : Parser() {
}

ParserPls::~ParserPls() {
}

QList<QString> ParserPls::parse(QString sFilename) {
    //long numEntries =0;
    QFile file(sFilename);
    QString basepath = sFilename.section('/', 0, -2);

    clearLocations();

    if (file.open(QIODevice::ReadOnly) && !isBinary(sFilename)) {

        /* Unfortunately, QT 4.7 does not handle <CR> (=\r or asci value 13) line breaks.
         * This is important on OS X where iTunes, e.g., exports M3U playlists using <CR>
         * rather that <LF>
         *
         * Using QFile::readAll() we obtain the complete content of the playlist as a ByteArray.
         * We replace any '\r' with '\n' if applicaple
         * This ensures that playlists from iTunes on OS X can be parsed
         */
        QByteArray ba = file.readAll();
        //detect encoding
        bool isCRLF_encoded = ba.contains("\r\n");
        bool isCR_encoded = ba.contains("\r");
        if(isCR_encoded && !isCRLF_encoded)
            ba.replace('\r','\n');
        QTextStream textstream(ba.constData());

        while(!textstream.atEnd()) {
            QString psLine = getFilepath(&textstream, basepath);
            if(psLine.isNull()) {
                break;
            } else {
                m_sLocations.append(psLine);
            }

        }

        file.close();

        if(m_sLocations.count() != 0)
            return m_sLocations;
        else
            return QList<QString>(); // NULL pointer returned when no locations were found
    }

    file.close();
    return QList<QString>(); //if we get here something went wrong :D
}

long ParserPls::getNumEntries(QTextStream *stream) {
    QString textline;
    textline = stream->readLine();

    if (textline.contains("[playlist]")) {
        while (!textline.contains("NumberOfEntries")) {
            textline = stream->readLine();
        }

        QString temp = textline.section("=",-1,-1);

        return temp.toLong();

    } else{
        qDebug() << "ParserPls: pls file is not a playlist! \n";
        return 0;
    }

}


QString ParserPls::getFilepath(QTextStream *stream, QString basepath) {
    QString textline = stream->readLine();
    while (!textline.isEmpty()) {
        if (textline.isNull()) {
            break;
        }

        if(textline.contains("File")) {
            int iPos = textline.indexOf("=", 0);
            ++iPos;

            QString filename = textline.right(textline.length() - iPos);
            TrackFile trackFile = playlistEntryToTrackFile(filename);

            if(trackFile.checkFileExists()) {
                return trackFile.location();
            } else {
                // Try relative to pls dir
                QString rel = QDir(basepath).filePath(trackFile.location());
                if (QFile::exists(rel)) {
                    return rel;
                }
                // We couldn't match this to a real file so ignore it
                qWarning() << trackFile.location() << "not found";
            }
        }
        textline = stream->readLine();
    }

    // Signal we reached the end
    return 0;
}

bool ParserPls::writePLSFile(const QString &file_str, QList<QString> &items, bool useRelativePath)
{
    QFile file(file_str);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::warning(NULL,tr("Playlist Export Failed"),
                             tr("Could not create file")+" "+file_str);
        return false;
    }
    //Base folder of file
    QString base = file_str.section('/', 0, -2);
    QDir base_dir(base);

    QTextStream out(&file);
    out << "[playlist]\n";
    out << "NumberOfEntries=" << items.size() << "\n";
    for (int i = 0; i < items.size(); ++i) {
        //Write relative path if possible
        if (useRelativePath) {
            //QDir::relativePath() will return the absolutePath if it cannot compute the
            //relative Path
            out << "File" << i << "=" << base_dir.relativeFilePath(items.at(i)) << "\n";
        } else {
            out << "File" << i << "=" << items.at(i) << "\n";
        }
    }

    return true;
}