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