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