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