OSDN Git Service

Implemented coalescing of progress updates, in order to reduce the number of signals...
[lamexp/LameXP.git] / src / PlaylistImporter.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "PlaylistImporter.h"
23
24 #include <QString>
25 #include <QStringList>
26 #include <QDir>
27 #include <QFileInfo>
28 #include <QProcess>
29 #include <QDate>
30 #include <QTime>
31 #include <QDebug>
32
33 //Un-escape XML characters
34 static const struct
35 {
36         char *escape;
37         char *output;
38 }
39 g_xmlEscapeSequence[] =
40 {
41         {"&amp;", "&"},
42         {"&lt;", "<"},
43         {"&gt;", ">"},
44         {"&apos;", "'"},
45         {"&nbsp;", " "},
46         {"&quot;", "\""},
47         {NULL, NULL}
48 };
49
50 const char *PlaylistImporter::supportedExtensions = "*.m3u *.m3u8 *.pls *.asx *.wpl";
51
52
53 ////////////////////////////////////////////////////////////
54 // Public Functions
55 ////////////////////////////////////////////////////////////
56
57 bool PlaylistImporter::importPlaylist(QStringList &fileList, const QString &playlistFile)
58 {
59         QFileInfo file(playlistFile);
60         QDir baseDir(file.canonicalPath());
61
62         QDir rootDir(baseDir);
63         while(rootDir.cdUp());
64
65         //Sanity check
66         if(file.size() < 3 || file.size() > 512000)
67         {
68                 return false;
69         }
70         
71         //Detect playlist type
72         playlist_t playlistType = isPlaylist(file.canonicalFilePath());
73
74         //Exit if not a playlist
75         if(playlistType == notPlaylist)
76         {
77                 return false;
78         }
79         
80         QFile data(playlistFile);
81
82         //Open file for reading
83         if(!data.open(QIODevice::ReadOnly))
84         {
85                 return false;
86         }
87
88         //Parse playlist depending on type
89         switch(playlistType)
90         {
91         case m3uPlaylist:
92                 return parsePlaylist_m3u(data, fileList, baseDir, rootDir);
93                 break;
94         case plsPlaylist:
95                 return parsePlaylist_pls(data, fileList, baseDir, rootDir);
96                 break;
97         case wplPlaylist:
98                 return parsePlaylist_wpl(data, fileList, baseDir, rootDir);
99                 break;
100         default:
101                 return false;
102                 break;
103         }
104 }
105
106 ////////////////////////////////////////////////////////////
107 // Private Functions
108 ////////////////////////////////////////////////////////////
109
110 PlaylistImporter::playlist_t PlaylistImporter::isPlaylist(const QString &fileName)
111 {
112         QFileInfo file (fileName);
113         
114         if(file.suffix().compare("m3u", Qt::CaseInsensitive) == 0 || file.suffix().compare("m3u8", Qt::CaseInsensitive) == 0)
115         {
116                 return m3uPlaylist;
117         }
118         else if(file.suffix().compare("pls", Qt::CaseInsensitive) == 0)
119         {
120                 return  plsPlaylist;
121         }
122         else if(file.suffix().compare("asx", Qt::CaseInsensitive) == 0 || file.suffix().compare("wpl", Qt::CaseInsensitive) == 0)
123         {
124                 return  wplPlaylist;
125         }
126         else
127         {
128                 return notPlaylist;
129         }
130 }
131
132 bool PlaylistImporter::parsePlaylist_m3u(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir)
133 {
134         QByteArray line = data.readLine();
135         
136         while(line.size() > 0)
137         {
138                 QFileInfo filename1(QDir::fromNativeSeparators(QString::fromUtf8(line.constData(), line.size()).trimmed()));
139                 QFileInfo filename2(QDir::fromNativeSeparators(QString::fromLatin1(line.constData(), line.size()).trimmed()));
140
141                 filename1.setCaching(false);
142                 filename2.setCaching(false);
143
144                 if(!(filename1.filePath().startsWith("#") || filename2.filePath().startsWith("#")))
145                 {
146                         fixFilePath(filename1, baseDir, rootDir);
147                         fixFilePath(filename2, baseDir, rootDir);
148
149                         if(filename1.exists())
150                         {
151                                 if(isPlaylist(filename1.canonicalFilePath()) == notPlaylist)
152                                 {
153                                         fileList << filename1.canonicalFilePath();
154                                 }
155                         }
156                         else if(filename2.exists())
157                         {
158                                 if(isPlaylist(filename2.canonicalFilePath()) == notPlaylist)
159                                 {
160                                         fileList << filename2.canonicalFilePath();
161                                 }
162                         }
163                 }
164
165                 line = data.readLine();
166         }
167
168         return true;
169 }
170
171 bool PlaylistImporter::parsePlaylist_pls(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir)
172 {
173         QRegExp plsEntry("File(\\d+)=(.+)", Qt::CaseInsensitive);
174         QByteArray line = data.readLine();
175         
176         while(line.size() > 0)
177         {
178                 bool flag = false;
179                 
180                 QString temp1(QDir::fromNativeSeparators(QString::fromUtf8(line.constData(), line.size()).trimmed()));
181                 QString temp2(QDir::fromNativeSeparators(QString::fromLatin1(line.constData(), line.size()).trimmed()));
182
183                 if(!flag && plsEntry.indexIn(temp1) >= 0)
184                 {
185                         QFileInfo filename(QDir::fromNativeSeparators(plsEntry.cap(2)).trimmed());
186                         filename.setCaching(false);
187                         fixFilePath(filename, baseDir, rootDir);
188
189                         if(filename.exists())
190                         {
191                                 if(isPlaylist(filename.canonicalFilePath()) == notPlaylist)
192                                 {
193                                         fileList << filename.canonicalFilePath();
194                                 }
195                                 flag = true;
196                         }
197                 }
198                 
199                 if(!flag && plsEntry.indexIn(temp2) >= 0)
200                 {
201                         QFileInfo filename(QDir::fromNativeSeparators(plsEntry.cap(2)).trimmed());
202                         filename.setCaching(false);
203                         fixFilePath(filename, baseDir, rootDir);
204
205                         if(filename.exists())
206                         {
207                                 if(isPlaylist(filename.canonicalFilePath()) == notPlaylist)
208                                 {
209                                         fileList << filename.canonicalFilePath();
210                                 }
211                                 flag = true;
212                         }
213                 }
214
215                 line = data.readLine();
216         }
217
218         return true;
219 }
220
221 bool PlaylistImporter::parsePlaylist_wpl(QFile &data, QStringList &fileList, const QDir &baseDir, const QDir &rootDir)
222 {
223         QRegExp skipData("<!--(.+)-->", Qt::CaseInsensitive);
224         QRegExp wplEntry("<(media|ref)[^<>]*(src|href)=\"([^\"]+)\"[^<>]*>", Qt::CaseInsensitive);
225         
226         skipData.setMinimal(true);
227
228         QByteArray buffer = data.readAll();
229         QString line = QString::fromUtf8(buffer.constData(), buffer.size()).simplified();
230         buffer.clear();
231
232         int index = 0;
233
234         while((index = skipData.indexIn(line)) >= 0)
235         {
236                 line.remove(index, skipData.matchedLength());
237         }
238
239         int offset = 0;
240
241         while((offset = wplEntry.indexIn(line, offset) + 1) > 0)
242         {
243                 QFileInfo filename(QDir::fromNativeSeparators(unescapeXml(wplEntry.cap(3)).trimmed()));
244                 filename.setCaching(false);
245                 fixFilePath(filename, baseDir, rootDir);
246
247                 if(filename.exists())
248                 {
249                         if(isPlaylist(filename.canonicalFilePath()) == notPlaylist)
250                         {
251                                 fileList << filename.canonicalFilePath();
252                         }
253                 }
254         }
255
256         return true;
257 }
258
259 void PlaylistImporter::fixFilePath(QFileInfo &filename, const QDir &baseDir, const QDir &rootDir)
260 {
261         if(filename.filePath().startsWith("/"))
262         {
263                 while(filename.filePath().startsWith("/"))
264                 {
265                         filename.setFile(filename.filePath().mid(1));
266                 }
267                 filename.setFile(rootDir.filePath(filename.filePath()));
268         }
269         
270         if(!filename.isAbsolute())
271         {
272                 filename.setFile(baseDir.filePath(filename.filePath()));
273         }
274 }
275
276 QString &PlaylistImporter::unescapeXml(QString &str)
277 {
278         for(int i = 0; (g_xmlEscapeSequence[i].escape && g_xmlEscapeSequence[i].output); i++)
279         {
280                 str.replace(g_xmlEscapeSequence[i].escape, g_xmlEscapeSequence[i].output);
281         }
282         
283         return str;
284 }