98ac21a45cdaf82cc6dfb97a31c4d68a4403e8f1
[tomamp] / tomamp / playlistmanager.cpp
1 #include "playlistmanager.h"
2 #include <QDir>
3 #include <QUrl>
4 #include <QMap>
5
6 QStringList allowedExtensions;
7
8
9 PlaylistManager::PlaylistManager(QWidget* parent)
10     : parentWidget (parent), lastMetaRead (-1)
11 {
12     allowedExtensions << "mp3" << "ogg" << "wav" << "wmv" << "wma" << "flac";
13 //    qDebug () << Phonon::BackendCapabilities::availableMimeTypes();
14     metaInformationResolver = new Phonon::MediaObject(parent);
15     connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
16         this, SLOT(metaStateChanged(Phonon::State,Phonon::State)));
17 }
18
19 int PlaylistManager::indexOf(const Phonon::MediaSource &s) const
20 {
21     for (int i = 0; i < items.size(); ++i)
22     {
23         if (items[i].source == s)
24             return i;
25     }
26     return -1;
27 }
28
29 void PlaylistManager::parseAndAddFolder(const QString &dir, bool recursive)
30 {
31     QStringList filters;
32 //    filters << "*.mp3";
33
34     QStringList files = QDir (dir).entryList(filters);
35
36     if (files.isEmpty())
37         return;
38
39     qDebug () << "Parsing folder " << dir;
40
41     //settings.setValue("LastFolder", dir);
42     int index = items.size();
43     foreach (QString string, files)
44     {
45         if (string == "."  || string == "..")
46             continue;
47         QString fname = dir + "/" + string;
48         QFileInfo fi (fname);
49         if (fi.isDir())
50         {
51             if (recursive)
52                 parseAndAddFolder(fname, true);
53             continue;
54         }
55         if (fileSupported(fname))
56         {
57             qDebug () << "Adding: " << fname;
58             items.append(PlaylistItem (PlaylistItem (fname)));
59         }
60     }
61 //    if (!items.isEmpty())
62     if (items.size () > index)
63     {
64         metaInformationResolver->setCurrentSource(items.at(index).source);
65         lastMetaRead = index;
66     }
67     qDebug () << " SIZE: " << items.size ();
68     emit playlistChanged (index);
69 }
70
71 void PlaylistManager::addStringList(const QStringList& list)
72 {
73     int index = items.size();
74     foreach (QString string, list)
75     {
76         if (fileSupported(string) || string.toLower().startsWith("http"))
77         {
78             qDebug () << "Adding " << string;
79             items.append(PlaylistItem (string));
80         }
81     }
82 //    if (!items.isEmpty())
83     if (items.size () > index)
84     {
85         metaInformationResolver->setCurrentSource(items.at(index).source);
86         lastMetaRead = index;
87     }
88     emit playlistChanged(index);
89 }
90
91 void PlaylistManager::metaStateChanged(Phonon::State newState, Phonon::State oldState)
92 {
93     qDebug () << "Meta state now " << newState << " old state " << oldState;
94     // This is an ugly hack, since the metaInformationResolver doesn't properly load the assigned source when it's in the error state
95     // In order to properly read the next file we have to set it as current source again when the resolver entered the stopped state after the error
96     static bool wasError = false;
97     if (wasError && newState == Phonon::StoppedState)
98     {
99         metaInformationResolver->setCurrentSource(items[lastMetaRead].source);
100         wasError = false;
101         return;
102     }
103     if (newState == Phonon::ErrorState)
104     {
105         wasError = true;
106     }
107
108     if (newState != Phonon::StoppedState && newState != Phonon::ErrorState)
109     {
110         return;
111     }
112
113     int index = lastMetaRead;
114     qDebug () << "Reading meta info of " << metaInformationResolver->currentSource().fileName() << " => " << index;
115
116     QMap<QString, QString> metaData = metaInformationResolver->metaData();
117
118
119     if (index >= 0 && newState != Phonon::ErrorState && index < items.size ())
120     {
121         items[index].artist = metaData.value("ARTIST");
122         items[index].title = metaData.value("TITLE");
123         items[index].album = metaData.value("ALBUM");
124 /*        items[index].year = metaData.value("DATE");
125         items[index].genre = metaData.value("GENRE");
126         qDebug () << "Meta " << metaData;
127         qDebug () << "Info is: " << items[index].year << " - " << items[index].genre;*/
128         if (metaData.isEmpty())
129             qDebug () << "Detected to be empty: " << items[index].uri;
130         else
131             items[index].playable = true;
132         emit itemUpdated (index);
133     }
134     if (index >= 0 && items.size () > index + 1)
135     {
136         metaInformationResolver->setCurrentSource(items[index + 1].source);
137         lastMetaRead = index + 1;
138     }
139 }
140
141 void PlaylistManager::savePlaylist(const QString& filenam)
142 {
143     QString filename = filenam;
144     if (filename.isEmpty())
145         return;
146     bool writepls = false;
147     if (filename.length() < 4 || (filename.right(4).toLower() != ".m3u" && filename.right(4).toLower() != ".pls"))
148     {
149         filename += ".pls";
150         writepls = true;
151     }
152     else if (filename.right(4).toLower() == ".pls")
153         writepls = true;
154     QFile f (filename);
155     try
156     {
157         f.open(QFile::WriteOnly);
158         if (writepls)
159         {
160             f.write ("[playlist]\n");
161             f.write (QString ("NumberOfEntries=%1\n").arg (items.size ()).toAscii());
162         }
163         for (int i = 0; i < items.size(); ++i)
164         {
165             if (writepls)
166             {
167                 f.write (QString ("File%1=%2\n").arg (i + 1).arg (items[i].uri).toAscii());
168                 f.write (QString ("Title%1=%2 - %3 - %4\n").arg (i + 1).arg (items[i].artist).arg (items[i].title).arg (items[i].album).toAscii());
169             }
170             else
171             {
172                 f.write (items[i].uri.toAscii());
173                 f.write ("\n");
174             }
175         }
176         if (writepls)
177             f.write ("Version=2\n");
178         f.close ();
179     }
180     catch (...)
181     {
182 //        QMessageBox::critical(this, "Write error", "Could not write playlist file", QMessageBox::Ok);
183     }
184 }
185
186 void PlaylistManager::loadPlaylist(const QString& filename)
187 {
188     clearPlaylist();
189     if (filename.right(4).toLower() == ".m3u")
190         appendPlaylist(filename);
191     else if (filename.right(4).toLower() == ".pls")
192         appendPlaylistPLS(filename);
193     if (!items.isEmpty())
194     {
195         metaInformationResolver->setCurrentSource(items.at(0).source);
196         lastMetaRead = 0;
197     }
198     emit playlistChanged (0);
199 }
200
201 void PlaylistManager::addPlaylist(const QString& filename)
202 {
203     int index = items.size();
204     if (filename.right(4).toLower() == ".m3u")
205         appendPlaylist(filename);
206     else if (filename.right(4).toLower() == ".pls")
207         appendPlaylistPLS(filename);
208     if (items.size () > index)
209 //    if (!items.isEmpty())
210     {
211         metaInformationResolver->setCurrentSource(items.at(index).source);
212         lastMetaRead = index;
213         emit playlistChanged (index);
214     }
215 }
216
217 void PlaylistManager::appendPlaylist(const QString& filename)
218 {
219     qDebug () << "Attempting to load playlist: " << filename;
220     QFile f(filename);
221     if (!f.open (QFile::ReadOnly))
222         return;
223     QString tmp = f.readAll();
224     f.close ();
225     QStringList lines = tmp.split("\n");
226     foreach (QString l, lines)
227     {
228         if (l.isEmpty() || (!QFileInfo (l).exists() && (l.indexOf("http") != 0)))
229         {
230             continue;
231         }
232         qDebug () << "Load " << l;
233         items.append(PlaylistItem (l));
234     }
235 }
236
237 void PlaylistManager::appendPlaylistPLS(const QString& filename)
238 {
239     qDebug () << "Attempting to load playlist: " << filename;
240     QFile f(filename);
241     if (!f.open (QFile::ReadOnly))
242         return;
243     QString tmp = f.readAll();
244     f.close ();
245     QStringList lines = tmp.split("\n");
246     QMap<int, int> filemap;
247
248     foreach (QString l, lines)
249     {
250         if (l.isEmpty() || l.trimmed().toLower() == "[playlist]" || l.trimmed().toLower() == "version=2")
251         {
252             continue;
253         }
254         qDebug () << "PLS " << l;
255         if (l.trimmed().toLower().left(4) == "file")
256         {
257             QStringList tokens = l.split('=');
258             if (tokens.size () < 2)
259                 continue;
260             tokens[0] = tokens[0].mid (4);
261             filemap.insert(tokens[0].toInt (), items.size ());
262             qDebug () << tokens;
263             items.append(PlaylistItem (tokens[1]));
264         }
265         else if (l.trimmed().toLower().left(5) == "title")
266         {
267             QStringList tokens = l.split('=');
268             if (tokens.size () < 2)
269                 continue;
270             tokens[0] = tokens[0].mid (5);
271             int toupdate = filemap[tokens[0].toInt()];
272             qDebug () << "Need to update " << toupdate << " for " << l;
273             QStringList metatok = tokens[1].split (" - ");
274             qDebug () << metatok;
275             if (metatok.size() > 2 && toupdate >= 0 && toupdate < items.size ())
276             {
277                 items[toupdate].artist = metatok[0];
278                 items[toupdate].title = metatok[1];
279                 metatok = metatok.mid (2);
280                 items[toupdate].album = metatok.join (" - ");
281             }
282             else
283             {
284                 items[toupdate].title = metatok.join (" - ");
285             }
286         }
287     }
288 }
289
290
291 void PlaylistManager::clearPlaylist()
292 {
293     items.clear();
294     emit playlistChanged(0);
295 /*    while (musicTable->rowCount())
296         musicTable->removeRow(0);
297     mediaObject->clear();*/
298 }
299
300 QStringList PlaylistManager::playlistStrings() const
301 {
302     QStringList ret;
303     for (int i = 0; i < items.size (); ++i)
304         ret << items[i].uri;
305     qDebug () << "Returning playlist " << ret << " SIZE: " << items.size ();
306     return ret;
307 }
308
309 void PlaylistManager::removeItem(int i)
310 {
311     items.removeAt (i);
312     emit itemRemoved(i);
313 }
314
315
316 bool PlaylistManager::fileSupported (const QString& fname) const
317 {
318     if (fname.lastIndexOf('.') < 0)
319         return false;
320     QString ext = fname.right(fname.size() - fname.lastIndexOf('.') - 1).toLower();
321     foreach (QString e, allowedExtensions)
322     {
323         if (ext == e)
324             return true;
325     }
326
327     return false;
328 }
329
330 bool PlaylistManager::moveItemUp (int i)
331 {
332     if (i)
333     {
334         PlaylistItem tmp = items[i - 1];
335         items[i - 1] = items[i];
336         items[i] = tmp;
337         return true;
338 //        emit playlistChanged(i - 1);
339     }
340     return false;
341 }
342
343 bool PlaylistManager::moveItemDown (int i)
344 {
345     if (i < items.size () - 1)
346     {
347         PlaylistItem tmp = items[i + 1];
348         items[i + 1] = items[i];
349         items[i] = tmp;
350         return true;
351 //        emit playlistChanged(i - 1);
352     }
353     return false;
354 }