aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2017-06-14 20:24:58 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2017-06-14 20:24:58 +0000
commitb2576ddc181d3758e3a57d9cac871ee7d7e2ef06 (patch)
tree1dfd6331a91f153d4a693a0aa32a774e2e53e2ea
parent9e3bcc8653f5e0500e9d0e4ee0c953e8bbf4ea4c (diff)
downloadqmmp-b2576ddc181d3758e3a57d9cac871ee7d7e2ef06.tar.gz
qmmp-b2576ddc181d3758e3a57d9cac871ee7d7e2ef06.tar.bz2
qmmp-b2576ddc181d3758e3a57d9cac871ee7d7e2ef06.zip
improved playlist formats support
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@7237 90c681e8-e032-0410-971d-27865f9a5e38
-rw-r--r--src/app/builtincommandlineoption.cpp6
-rw-r--r--src/plugins/PlayListFormats/m3u/m3uplaylistformat.cpp49
-rw-r--r--src/plugins/PlayListFormats/m3u/m3uplaylistformat.h4
-rw-r--r--src/plugins/PlayListFormats/pls/plsplaylistformat.cpp113
-rw-r--r--src/plugins/PlayListFormats/pls/plsplaylistformat.h4
-rw-r--r--src/plugins/PlayListFormats/xspf/xspfplaylistformat.cpp67
-rw-r--r--src/plugins/PlayListFormats/xspf/xspfplaylistformat.h4
-rw-r--r--src/qmmpui/addurldialog.cpp36
-rw-r--r--src/qmmpui/addurldialog_p.h5
-rw-r--r--src/qmmpui/fileloader.cpp109
-rw-r--r--src/qmmpui/fileloader_p.h8
-rw-r--r--src/qmmpui/playlistdownloader.cpp21
-rw-r--r--src/qmmpui/playlistdownloader.h23
-rw-r--r--src/qmmpui/playlistformat.h8
-rw-r--r--src/qmmpui/playlistmodel.cpp32
-rw-r--r--src/qmmpui/playlistmodel.h2
-rw-r--r--src/qmmpui/playlistparser.cpp73
-rw-r--r--src/qmmpui/playlistparser.h15
-rw-r--r--src/qmmpui/playlisttrack.cpp22
-rw-r--r--src/qmmpui/playlisttrack.h5
20 files changed, 424 insertions, 182 deletions
diff --git a/src/app/builtincommandlineoption.cpp b/src/app/builtincommandlineoption.cpp
index 30bad21a1..1cc93df44 100644
--- a/src/app/builtincommandlineoption.cpp
+++ b/src/app/builtincommandlineoption.cpp
@@ -147,10 +147,8 @@ QString BuiltinCommandLineOption::executeCommand(const QString &option_string,
if(!remote_pls_list.isEmpty())
{
PlayListDownloader *downloader = new PlayListDownloader(this);
- connect(downloader, SIGNAL(done(QStringList)), m_model, SLOT(add(QStringList)));
- connect(downloader, SIGNAL(done(QStringList)), downloader, SLOT(deleteLater()));
- connect(downloader, SIGNAL(error(QString)), downloader, SLOT(deleteLater()));
- downloader->start(remote_pls_list.at(0));
+ connect(downloader, SIGNAL(finished(bool,QString)), downloader, SLOT(deleteLater()));
+ downloader->start(remote_pls_list.at(0), m_model);
}
}
else if (option_string == "--play" || option_string == "-p")
diff --git a/src/plugins/PlayListFormats/m3u/m3uplaylistformat.cpp b/src/plugins/PlayListFormats/m3u/m3uplaylistformat.cpp
index 87bd2eaf8..783f3c518 100644
--- a/src/plugins/PlayListFormats/m3u/m3uplaylistformat.cpp
+++ b/src/plugins/PlayListFormats/m3u/m3uplaylistformat.cpp
@@ -32,34 +32,57 @@ const PlayListFormatProperties M3UPlaylistFormat::properties() const
return p;
}
-QStringList M3UPlaylistFormat::decode(const QString & contents)
+QList<PlayListTrack *> M3UPlaylistFormat::decode(const QByteArray &contents)
{
- QStringList out;
- QStringList splitted = contents.split("\n");
+ QList<PlayListTrack*> out;
+ QStringList splitted = QString::fromUtf8(contents).split("\n");
if(splitted.isEmpty())
- return QStringList();
+ return out;
+
+ QRegExp extInfRegExp("#EXTINF:(-{0,1}\\d+),(.*) - (.*)");
+ int length = 0;
+ QString artist, title;
+ bool hasExtInf = false;
foreach(QString str, splitted)
{
- str = str.trimmed ();
- if (str.startsWith("#EXTM3U") || str.startsWith("#EXTINF:") || str.isEmpty())
- continue;//TODO: Let's skip it for now..
- else if (str.startsWith("#") || str.isEmpty())
+ str = str.trimmed();
+ if(str.startsWith("#EXTM3U") || str.isEmpty())
continue;
- else
- out << str;
+
+ if(extInfRegExp.indexIn(str) > -1)
+ {
+ length = extInfRegExp.cap(1).toInt();
+ artist = extInfRegExp.cap(2);
+ title = extInfRegExp.cap(3);
+ hasExtInf = true;
+ }
+
+ if(str.startsWith("#"))
+ continue;
+
+ out << new PlayListTrack();
+ out.last()->insert(Qmmp::URL, str);
+
+ if(hasExtInf)
+ {
+ out.last()->setLength(length);
+ out.last()->insert(Qmmp::ARTIST, artist);
+ out.last()->insert(Qmmp::TITLE, title);
+ hasExtInf = false;
+ }
}
return out;
}
-QString M3UPlaylistFormat::encode(const QList<PlayListTrack*> & contents, const QString &path)
+QByteArray M3UPlaylistFormat::encode(const QList<PlayListTrack*> &contents, const QString &path)
{
QStringList out;
out << QString("#EXTM3U");
MetaDataFormatter formatter("%if(%p,%p - %t,%t)%if(%p|%t,,%f)");
QString m3uDir = QFileInfo(path).canonicalPath();
- foreach(PlayListTrack* f,contents)
+ foreach(PlayListTrack* f, contents)
{
QString info = "#EXTINF:" + QString::number(f->length()) + "," + formatter.format(f);
out.append(info);
@@ -75,7 +98,7 @@ QString M3UPlaylistFormat::encode(const QList<PlayListTrack*> & contents, const
else
out.append(f->url());
}
- return out.join("\n");
+ return out.join("\n").toUtf8();
}
Q_EXPORT_PLUGIN2(m3uplaylistformat,M3UPlaylistFormat)
diff --git a/src/plugins/PlayListFormats/m3u/m3uplaylistformat.h b/src/plugins/PlayListFormats/m3u/m3uplaylistformat.h
index 379ae063e..dd859c807 100644
--- a/src/plugins/PlayListFormats/m3u/m3uplaylistformat.h
+++ b/src/plugins/PlayListFormats/m3u/m3uplaylistformat.h
@@ -36,8 +36,8 @@ class M3UPlaylistFormat : public QObject, public PlayListFormat
Q_INTERFACES(PlayListFormat)
public:
const PlayListFormatProperties properties() const;
- QStringList decode(const QString& contents);
- QString encode(const QList<PlayListTrack*>& contents, const QString &path);
+ QList<PlayListTrack*> decode(const QByteArray &contents);
+ QByteArray encode(const QList<PlayListTrack*>& contents, const QString &path);
};
diff --git a/src/plugins/PlayListFormats/pls/plsplaylistformat.cpp b/src/plugins/PlayListFormats/pls/plsplaylistformat.cpp
index ac4954567..a4822c423 100644
--- a/src/plugins/PlayListFormats/pls/plsplaylistformat.cpp
+++ b/src/plugins/PlayListFormats/pls/plsplaylistformat.cpp
@@ -18,8 +18,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#include <QFileInfo>
#include <QtPlugin>
+#include <QRegExp>
+#include <qmmpui/metadataformatter.h>
#include "plsplaylistformat.h"
const PlayListFormatProperties PLSPlaylistFormat::properties() const
@@ -31,57 +32,111 @@ const PlayListFormatProperties PLSPlaylistFormat::properties() const
return p;
}
-QStringList PLSPlaylistFormat::decode(const QString & contents)
+QList<PlayListTrack *> PLSPlaylistFormat::decode(const QByteArray &contents)
{
- QStringList out;
- QStringList splitted = contents.split("\n");
- if (!splitted.isEmpty())
+ QList<PlayListTrack *> out;
+ QStringList splitted = QString::fromUtf8(contents).split("\n");
+
+ if(splitted.isEmpty())
{
- if (splitted.takeAt(0).toLower().contains("[playlist]"))
+ qWarning("PLSPlaylistFormat: error parsing PLS format");
+ return out;
+ }
+
+ if(!splitted.takeFirst().toLower().startsWith("[playlist]"))
+ {
+ qWarning("PLSPlaylistFormat: unknown playlist format");
+ return out;
+ }
+
+ QRegExp fileRegExp("^File(\\d+)=(.+)");
+ QRegExp fullTitleRegExp("^Title(\\d+)=(.+) - (.+)");
+ QRegExp titleRegExp("^Title(\\d+)=(.+)");
+ QRegExp lengthRegExp("^Length(\\d+)=(-{0,1}\\d+)");
+
+ int number = 0;
+ bool error = false;
+
+ foreach (QString line, splitted)
+ {
+ if(fileRegExp.indexIn(line) > -1)
{
- foreach(QString str, splitted)
+ if((number = fileRegExp.cap(1).toInt()) > 0)
{
- if (str.startsWith("File"))
- {
- QString unverified = str.remove(0,str.indexOf(QChar('=')) + 1);
- unverified = unverified.trimmed();
- if (unverified.startsWith("http://"))
- {
- out << unverified;
- }
- else /*if (QFileInfo(unverified).exists())*/
- out << QFileInfo(unverified).absoluteFilePath();
- /*else
- qWarning("File %s does not exist", qPrintable(unverified));*/
- }
+ while(number > out.count())
+ out << new PlayListTrack();
+ out[number - 1]->insert(Qmmp::URL, fileRegExp.cap(2));
}
- return out;
+ else
+ error = true;
+ }
+ else if(fullTitleRegExp.indexIn(line) > -1)
+ {
+ if((number = fullTitleRegExp.cap(1).toInt()) > 0)
+ {
+ while(number > out.count())
+ out << new PlayListTrack();
+ out[number - 1]->insert(Qmmp::ARTIST, fullTitleRegExp.cap(2));
+ out[number - 1]->insert(Qmmp::TITLE, fullTitleRegExp.cap(3));
+ }
+ else
+ error = true;
+ }
+ else if(titleRegExp.indexIn(line) > -1)
+ {
+ if((number = titleRegExp.cap(1).toInt()) > 0)
+ {
+ while(number > out.count())
+ out << new PlayListTrack();
+ out[number - 1]->insert(Qmmp::TITLE, titleRegExp.cap(2));
+ }
+ else
+ error = true;
+ }
+ else if(lengthRegExp.indexIn(line) > -1)
+ {
+ if((number = lengthRegExp.cap(1).toInt()) > 0)
+ {
+ while(number > out.count())
+ out << new PlayListTrack();
+ out[number - 1]->setLength(lengthRegExp.cap(2).toInt());
+ }
+ else
+ error = true;
+ }
+
+ if(error)
+ {
+ qWarning("PLSPlaylistFormat: error while parsing line: '%s'", qPrintable(line));
+ qDeleteAll(out);
+ out.clear();
+ break;
}
}
- else
- qWarning("Error parsing PLS format");
- return QStringList();
+ return out;
}
-QString PLSPlaylistFormat::encode(const QList<PlayListTrack *> & contents, const QString &path)
+QByteArray PLSPlaylistFormat::encode(const QList<PlayListTrack *> &contents, const QString &path)
{
Q_UNUSED(path);
+ MetaDataFormatter formatter("%if(%p,%p - %t,%t)%if(%p|%t,,%f)");
QStringList out;
out << QString("[playlist]");
int counter = 1;
- foreach(PlayListTrack* f,contents)
+ foreach(PlayListTrack *f, contents)
{
QString begin = "File" + QString::number(counter) + "=";
out.append(begin + f->url());
begin = "Title" + QString::number(counter) + "=";
- out.append(begin + f->value(Qmmp::TITLE));
+ out.append(begin + formatter.format(f));
begin = "Length" + QString::number(counter) + "=";
out.append(begin + QString::number(f->length()));
- counter ++;
+ counter++;
}
out << "NumberOfEntries=" + QString::number(contents.count());
- return out.join("\n");
+ out << "Version=2";
+ return out.join("\n").toUtf8();
}
Q_EXPORT_PLUGIN2(plsplaylistformat, PLSPlaylistFormat)
diff --git a/src/plugins/PlayListFormats/pls/plsplaylistformat.h b/src/plugins/PlayListFormats/pls/plsplaylistformat.h
index 7fed6d810..79bebf91c 100644
--- a/src/plugins/PlayListFormats/pls/plsplaylistformat.h
+++ b/src/plugins/PlayListFormats/pls/plsplaylistformat.h
@@ -36,8 +36,8 @@ class PLSPlaylistFormat : public QObject, public PlayListFormat
Q_INTERFACES(PlayListFormat)
public:
const PlayListFormatProperties properties() const;
- QStringList decode(const QString& contents);
- QString encode(const QList<PlayListTrack*>& contents, const QString &path);
+ QList<PlayListTrack*> decode(const QByteArray& contents);
+ QByteArray encode(const QList<PlayListTrack*> &contents, const QString &path);
};
diff --git a/src/plugins/PlayListFormats/xspf/xspfplaylistformat.cpp b/src/plugins/PlayListFormats/xspf/xspfplaylistformat.cpp
index d5ab21fb5..93d691d3c 100644
--- a/src/plugins/PlayListFormats/xspf/xspfplaylistformat.cpp
+++ b/src/plugins/PlayListFormats/xspf/xspfplaylistformat.cpp
@@ -37,11 +37,11 @@ const PlayListFormatProperties XSPFPlaylistFormat::XSPFPlaylistFormat::propertie
return p;
}
-QStringList XSPFPlaylistFormat::decode(const QString & contents)
+QList<PlayListTrack*> XSPFPlaylistFormat::decode(const QByteArray &contents)
{
- QStringList out;
+ QList<PlayListTrack*> out;
QString currentTag;
- QString contents_copy = contents;
+ QString contents_copy = QString::fromUtf8(contents);
//remove control symbols to avoid xml errors
for(int i = 0; i < contents_copy.size(); ++i)
@@ -54,24 +54,47 @@ QStringList XSPFPlaylistFormat::decode(const QString & contents)
}
QXmlStreamReader xml(contents_copy);
- while(!xml.atEnd())
+ while(!xml.atEnd() || !xml.hasError())
{
xml.readNext();
if (xml.isStartElement())
{
currentTag = xml.name().toString();
-
+ if(currentTag == "track")
+ out << new PlayListTrack();
}
else if (xml.isCharacters() && !xml.isWhitespace())
{
- if (currentTag == "location")
- {
+ if(out.isEmpty())
+ continue;
+ if(currentTag == "location")
+ {
QUrl url(xml.text().toString());
if (url.scheme() == "file") //remove scheme for local files only
- out << QUrl::fromPercentEncoding(url.toString().toLatin1()).remove("file://");
+ out.last()->insert(Qmmp::URL, QUrl::fromPercentEncoding(url.toString().toLatin1()).remove("file://"));
else
- out << QUrl::fromPercentEncoding(url.toString().toLatin1());
+ out.last()->insert(Qmmp::URL, QUrl::fromPercentEncoding(url.toString().toLatin1()));
+ }
+ else if(currentTag == "title")
+ {
+ out.last()->insert(Qmmp::TITLE, xml.text().toString());
+ }
+ else if(currentTag == "creator")
+ {
+ out.last()->insert(Qmmp::ARTIST, xml.text().toString());
+ }
+ else if(currentTag == "annotation")
+ {
+ out.last()->insert(Qmmp::COMMENT, xml.text().toString());
+ }
+ else if(currentTag == "album")
+ {
+ out.last()->insert(Qmmp::ALBUM, xml.text().toString());
+ }
+ else if(currentTag == "meta" && xml.attributes().value("rel") == "year")
+ {
+ out.last()->insert(Qmmp::YEAR, xml.text().toString());
}
else
xml.skipCurrentElement();
@@ -88,10 +111,10 @@ QStringList XSPFPlaylistFormat::decode(const QString & contents)
// Needs more work - it's better use libSpiff there and put it as plugin.
-QString XSPFPlaylistFormat::encode(const QList<PlayListTrack*> & files, const QString &path)
+QByteArray XSPFPlaylistFormat::encode(const QList<PlayListTrack*> &files, const QString &path)
{
- Q_UNUSED(path);
- QString out;
+ QString xspfDir = QFileInfo(path).canonicalPath();
+ QByteArray out;
QXmlStreamWriter xml(&out);
xml.setCodec("UTF-8");
xml.setAutoFormatting(true);
@@ -103,16 +126,27 @@ QString XSPFPlaylistFormat::encode(const QList<PlayListTrack*> & files, const QS
xml.writeStartElement("trackList");
int counter = 1;
- foreach(PlayListTrack* f,files)
+ foreach(PlayListTrack* f, files)
{
xml.writeStartElement("track");
QString url;
if (f->url().contains("://"))
+ {
url = QUrl::toPercentEncoding(f->url(), ":/");
- else //append protocol
- url = QUrl::toPercentEncoding(QString("file://") +
- QFileInfo(f->url()).absoluteFilePath(), ":/");
+ }
+ else if(f->url().startsWith(xspfDir)) //relative path
+ {
+ QString p = f->url();
+ p.remove(0, xspfDir.size());
+ if(p.startsWith("/"))
+ p.remove(0, 1);
+ url = QUrl::toPercentEncoding(p, ":/");
+ }
+ else //absolute path
+ {
+ url = QUrl::toPercentEncoding(QLatin1String("file://") + f->url(), ":/");
+ }
xml.writeTextElement("location", url);
xml.writeTextElement("title", f->value(Qmmp::TITLE));
@@ -133,7 +167,6 @@ QString XSPFPlaylistFormat::encode(const QList<PlayListTrack*> & files, const QS
xml.writeEndElement(); //playlist
xml.writeEndDocument();
return out;
-
}
Q_EXPORT_PLUGIN2(xspfplaylistformat,XSPFPlaylistFormat)
diff --git a/src/plugins/PlayListFormats/xspf/xspfplaylistformat.h b/src/plugins/PlayListFormats/xspf/xspfplaylistformat.h
index d3b03d3ca..dbd1325d5 100644
--- a/src/plugins/PlayListFormats/xspf/xspfplaylistformat.h
+++ b/src/plugins/PlayListFormats/xspf/xspfplaylistformat.h
@@ -36,8 +36,8 @@ class XSPFPlaylistFormat : public QObject, public PlayListFormat
Q_INTERFACES(PlayListFormat)
public:
const PlayListFormatProperties properties() const;
- QStringList decode(const QString& contents);
- QString encode(const QList<PlayListTrack*>& contents, const QString &path);
+ QList<PlayListTrack*> decode(const QByteArray &contents);
+ QByteArray encode(const QList<PlayListTrack*> &contents, const QString &path);
};
#endif
diff --git a/src/qmmpui/addurldialog.cpp b/src/qmmpui/addurldialog.cpp
index 0bfef038a..9af61b516 100644
--- a/src/qmmpui/addurldialog.cpp
+++ b/src/qmmpui/addurldialog.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006-2012 by Ilya Kotov *
+ * Copyright (C) 2006-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -43,8 +43,8 @@ AddUrlDialog::AddUrlDialog(QWidget *parent) : QDialog(parent)
m_history = settings.value("URLDialog/history").toStringList();
urlComboBox->addItems(m_history);
m_downloader = new PlayListDownloader(this);
- connect(m_downloader, SIGNAL(done(QStringList)), SLOT(add(QStringList)));
- connect(m_downloader, SIGNAL(error(QString)), SLOT(showError(QString)));
+ connect(m_downloader, SIGNAL(finished(bool,QString)), SLOT(onFinished(bool,QString)));
+
if(QmmpUiSettings::instance()->useClipboard())
{
QUrl url(QApplication::clipboard()->text().trimmed());
@@ -74,6 +74,19 @@ void AddUrlDialog::popup(QWidget* parent, PlayListModel* model)
m_instance->raise();
}
+void AddUrlDialog::onFinished(bool ok, const QString &message)
+{
+ if(ok)
+ {
+ QDialog::accept();
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Error"), message);
+ addButton->setEnabled(true);
+ }
+}
+
void AddUrlDialog::accept()
{
addButton->setEnabled(false);
@@ -98,9 +111,9 @@ void AddUrlDialog::accept()
m_history.removeAll(s);
m_history.prepend(s);
- if (s.startsWith("http://")) //try to download playlist
+ if (s.startsWith("http://") || s.startsWith("https://")) //try to download playlist
{
- m_downloader->start(QUrl(s));
+ m_downloader->start(QUrl(s), m_model);
return;
}
m_model->add(s);
@@ -111,16 +124,3 @@ void AddUrlDialog::setModel(PlayListModel *m)
{
m_model = m;
}
-
-void AddUrlDialog::add(const QStringList &urls)
-{
- addButton->setEnabled(true);
- m_model->add(urls);
- QDialog::accept();
-}
-
-void AddUrlDialog::showError(const QString &message)
-{
- QMessageBox::warning(this, tr("Error"), message);
- addButton->setEnabled(true);
-}
diff --git a/src/qmmpui/addurldialog_p.h b/src/qmmpui/addurldialog_p.h
index 5835b3fbf..962c7fe38 100644
--- a/src/qmmpui/addurldialog_p.h
+++ b/src/qmmpui/addurldialog_p.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006-2012 by Ilya Kotov *
+ * Copyright (C) 2006-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -41,8 +41,7 @@ public:
static void popup(QWidget* parent ,PlayListModel*);
private slots:
- void add(const QStringList &urls);
- void showError(const QString &message);
+ void onFinished(bool ok, const QString &message);
private:
AddUrlDialog(QWidget *parent);
diff --git a/src/qmmpui/fileloader.cpp b/src/qmmpui/fileloader.cpp
index 0b0958423..e42226a4d 100644
--- a/src/qmmpui/fileloader.cpp
+++ b/src/qmmpui/fileloader.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006-2015 by Ilya Kotov *
+ * Copyright (C) 2006-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -26,6 +26,7 @@
#include "fileloader_p.h"
#include "qmmpuisettings.h"
#include "playlistitem.h"
+#include "playlistparser.h"
#include "playlisttrack.h"
FileLoader::FileLoader(QObject *parent) : QThread(parent)
@@ -53,6 +54,62 @@ QList<PlayListTrack *> FileLoader::processFile(const QString &path, QStringList
return tracks;
}
+void FileLoader::insertPlayList(const QString &fmt, const QByteArray &contents, PlayListItem *before)
+{
+ QList<PlayListTrack *> tracks = PlayListParser::loadPlaylist(fmt, contents);
+
+ while (!tracks.isEmpty() && !m_finished)
+ {
+ PlayListTrack *t = tracks.takeFirst();
+ QList <FileInfo *> infoList = MetaDataManager::instance()->createPlayList(t->url(), m_use_meta);
+ if(infoList.count() != 1) //invalid or unsupported track
+ {
+ qDeleteAll(infoList);
+ infoList.clear();
+ delete t;
+ continue;
+ }
+
+ FileInfo *info = infoList.first();
+ if(!info->metaData(Qmmp::ALBUM).isEmpty() && !info->metaData(Qmmp::ARTIST).isEmpty())
+ t->updateMetaData(infoList.first());
+
+ emit newTracksToInsert(before, QList<PlayListTrack *>() << t);
+ delete info;
+ }
+ //clear remaining tracks
+ qDeleteAll(tracks);
+ tracks.clear();
+}
+
+void FileLoader::insertPlayList(const QString &path, PlayListItem *before)
+{
+ QList<PlayListTrack *> tracks = PlayListParser::loadPlaylist(path);
+
+ while (!tracks.isEmpty() && !m_finished)
+ {
+ PlayListTrack *t = tracks.takeFirst();
+ QList <FileInfo *> infoList = MetaDataManager::instance()->createPlayList(t->url(), m_use_meta);
+ if(infoList.count() != 1) //invalid or unsupported track
+ {
+ qDeleteAll(infoList);
+ infoList.clear();
+ delete t;
+ continue;
+ }
+
+ FileInfo *info = infoList.first();
+ if(!info->metaData(Qmmp::ALBUM).isEmpty() && !info->metaData(Qmmp::ARTIST).isEmpty())
+ t->updateMetaData(infoList.first());
+
+ emit newTracksToInsert(before, QList<PlayListTrack *>() << t);
+ delete info;
+ }
+ //clear remaining tracks
+ qDeleteAll(tracks);
+ tracks.clear();
+}
+
void FileLoader::addDirectory(const QString& s, PlayListItem *before)
{
QList<PlayListTrack *> tracks;
@@ -127,20 +184,31 @@ void FileLoader::run()
PlayListItem *before = i.before;
QString path = i.path;
- QFileInfo info(path);
-
- if(info.isDir())
+ if(!path.isEmpty())
{
- addDirectory(path, before);
+ QFileInfo info(path);
- }
- else if(info.isFile() || path.contains("://"))
- {
- QList<PlayListTrack *> tracks = processFile(path);
- if(!tracks.isEmpty())
+ if(info.isDir())
+ {
+ addDirectory(path, before);
+
+ }
+ else if(info.isFile() && PlayListParser::isPlayList(path))
{
- emit newTracksToInsert(before, tracks);
+ insertPlayList(path, before);
}
+ else if(info.isFile() || path.contains("://"))
+ {
+ QList<PlayListTrack *> tracks = processFile(path);
+ if(!tracks.isEmpty())
+ {
+ emit newTracksToInsert(before, tracks);
+ }
+ }
+ }
+ else if(!i.playListContent.isEmpty() && !i.playListFormat.isEmpty())
+ {
+ insertPlayList(i.playListFormat, i.playListContent, before);
}
m_mutex.lock();
@@ -163,6 +231,25 @@ void FileLoader::add(const QStringList &paths)
insert(0, paths);
}
+void FileLoader::addPlayList(const QString &fmt, const QByteArray &data)
+{
+ m_mutex.lock();
+ LoaderTask task;
+ task.before = 0;
+ task.playListFormat = fmt;
+ task.playListContent = data;
+ m_tasks.append(task);
+ m_mutex.unlock();
+ if(!isRunning())
+ {
+ MetaDataManager::instance()->prepareForAnotherThread();
+ PlayListParser::loadFormats();
+ m_filters = MetaDataManager::instance()->nameFilters();
+ m_use_meta = m_settings->useMetadata();
+ }
+ start(QThread::IdlePriority);
+}
+
void FileLoader::insert(PlayListItem *before, const QString &path)
{
insert(before, QStringList() << path);
diff --git a/src/qmmpui/fileloader_p.h b/src/qmmpui/fileloader_p.h
index 1dd0a823b..58f771ff7 100644
--- a/src/qmmpui/fileloader_p.h
+++ b/src/qmmpui/fileloader_p.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006-2015 by Ilya Kotov *
+ * Copyright (C) 2006-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -61,10 +61,12 @@ public:
* Sets files/directories to load
*/
void add(const QStringList &paths);
+ void addPlayList(const QString &fmt, const QByteArray &data);
void insert(PlayListItem *before, const QString &path);
void insert(PlayListItem *before, const QStringList &paths);
+
public slots:
/*!
* Removes files and directories from queue and waits until thread is finished
@@ -81,6 +83,8 @@ signals:
private:
void run();
QList<PlayListTrack*> processFile(const QString &path, QStringList *ignoredPaths = 0);
+ void insertPlayList(const QString &fmt, const QByteArray &contents, PlayListItem *before);
+ void insertPlayList(const QString &path, PlayListItem *before);
void addDirectory(const QString &s, PlayListItem *before = 0);
bool checkRestrictFilters(const QFileInfo &info);
bool checkExcludeFilters(const QFileInfo &info);
@@ -89,6 +93,8 @@ private:
{
QString path;
PlayListItem *before;
+ QString playListFormat;
+ QByteArray playListContent;
};
QQueue <LoaderTask> m_tasks;
QStringList m_filters;
diff --git a/src/qmmpui/playlistdownloader.cpp b/src/qmmpui/playlistdownloader.cpp
index a88f18460..951877258 100644
--- a/src/qmmpui/playlistdownloader.cpp
+++ b/src/qmmpui/playlistdownloader.cpp
@@ -46,11 +46,13 @@ PlayListDownloader::PlayListDownloader(QObject *parent) : QObject(parent)
}
}
-void PlayListDownloader::start(const QUrl &url)
+void PlayListDownloader::start(const QUrl &url, PlayListModel *model)
{
+ m_model = model;
if(!PlayListParser::findByUrl(url)) //is it playlist?
{
- emit done(QStringList() << QString::fromLatin1(url.toEncoded())); //just send initial URL
+ m_model->add(url.toString());
+ emit finished(true);
return;
}
m_url = url;
@@ -71,7 +73,7 @@ void PlayListDownloader::readResponse(QNetworkReply *reply)
if(reply->error() != QNetworkReply::NoError)
{
- emit error(reply->errorString() + " (" + reply->error() + ")");
+ emit finished(false, reply->errorString() + " (" + reply->error() + ")");
reply->deleteLater();
return;
}
@@ -93,6 +95,13 @@ void PlayListDownloader::readResponse(QNetworkReply *reply)
if(reply == m_getReply)
{
m_getReply = 0;
+
+ if(m_model.isNull())
+ {
+ emit finished(true);
+ return;
+ }
+
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
qDebug("PlayListDownloader: content type: %s", qPrintable(contentType));
PlayListFormat *fmt = PlayListParser::findByMime(contentType);
@@ -100,12 +109,12 @@ void PlayListDownloader::readResponse(QNetworkReply *reply)
fmt = PlayListParser::findByUrl(m_url);
if(fmt)
{
- QStringList list = fmt->decode(QString::fromUtf8(reply->readAll()));
- emit done(list);
+ m_model->loadPlaylist(fmt->properties().shortName, reply->readAll());
+ emit finished(true);
}
else
{
- emit error(tr("Unsupported playlist format"));
+ emit finished(false, tr("Unsupported playlist format"));
}
}
reply->deleteLater();
diff --git a/src/qmmpui/playlistdownloader.h b/src/qmmpui/playlistdownloader.h
index df0a612db..ef044ab6c 100644
--- a/src/qmmpui/playlistdownloader.h
+++ b/src/qmmpui/playlistdownloader.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2012 by Ilya Kotov *
+ * Copyright (C) 2012-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -23,6 +23,8 @@
#include <QObject>
#include <QUrl>
+#include <QPointer>
+#include "playlistmodel.h"
class QNetworkAccessManager;
class QNetworkReply;
@@ -41,23 +43,19 @@ public:
signals:
/*!
- * Emitted when downloading is finished without errors.
- * @param urls A list of extracted URLs or argument of the \b PlayListDownloader::start()
- * function if remote URL doesn't contain playlist.
- */
- void done(const QStringList &urls);
- /*!
- * Emitted when downloading is finished with error.
+ * Emitted when downloading is finished.
+ * @param ok Result of downloading (if an error occurs, \b ok is set to \b false; otherwise \b ok is set to \b true).
* @param message Error message.
*/
- void error(const QString &message);
+ void finished(bool ok, const QString &message = QString());
public slots:
/*!
- * Starts playlist downloading
- * @param url URL of remote playlist
+ * Starts playlist downloading.
+ * @param url URL of remote playlist.
+ * @param model Destination playlist model.
*/
- void start(const QUrl &url);
+ void start(const QUrl &url, PlayListModel *model);
private slots:
void readResponse(QNetworkReply *reply);
@@ -67,6 +65,7 @@ private:
QUrl m_redirect_url, m_url;
QNetworkReply *m_getReply;
QByteArray m_ua;
+ QPointer<PlayListModel> m_model;
};
#endif // PLAYLISTDOWNLOADER_H
diff --git a/src/qmmpui/playlistformat.h b/src/qmmpui/playlistformat.h
index 06927cfbf..16e23a57d 100644
--- a/src/qmmpui/playlistformat.h
+++ b/src/qmmpui/playlistformat.h
@@ -53,13 +53,13 @@ public:
* Takes raw contents of playlist file, should return string list of
* ready file pathes to fill the playlist.
*/
- virtual QStringList decode(const QString& contents) = 0;
+ virtual QList<PlayListTrack*> decode(const QByteArray &contents) = 0;
/*!
- * Takes the list of AbstractPlaylistItem objects, should return string of
+ * Takes the list of \b PlayListTrack objects, should return content of
* encoded playlist file.
- * @param dir Playlist file path (May be used to adjust playlist content).
+ * @param path Playlist file path (May be used to adjust playlist content).
*/
- virtual QString encode(const QList<PlayListTrack*>& contents, const QString &path) = 0;
+ virtual QByteArray encode(const QList<PlayListTrack*> &contents, const QString &path) = 0;
};
Q_DECLARE_INTERFACE(PlayListFormat,"PlayListFormat/1.0")
diff --git a/src/qmmpui/playlistmodel.cpp b/src/qmmpui/playlistmodel.cpp
index 20e82650e..7fe8daacb 100644
--- a/src/qmmpui/playlistmodel.cpp
+++ b/src/qmmpui/playlistmodel.cpp
@@ -143,26 +143,12 @@ void PlayListModel::add(QList<PlayListTrack *> tracks)
void PlayListModel::add(const QString &path)
{
- QStringList paths = PlayListParser::loadPlaylist(path);
- if(paths.isEmpty())
- m_loader->add(path);
- else
- m_loader->add(paths);
+ m_loader->add(path);
}
void PlayListModel::add(const QStringList &paths)
{
- QStringList urls, pl_urls;
- foreach(QString path, paths)
- {
- pl_urls = PlayListParser::loadPlaylist(path); //is it playlist?
- if(pl_urls.isEmpty())
- urls.append(path);
- else
- urls.append(pl_urls);
-
- }
- m_loader->add(urls);
+ m_loader->add(paths);
}
void PlayListModel::insert(int index, PlayListTrack *track)
@@ -242,11 +228,7 @@ void PlayListModel::insert(int index, const QStringList &paths)
else
{
PlayListItem *before = m_container->item(index);
-
- QStringList list = paths;
- foreach (QString path, paths)
- list.append(PlayListParser::loadPlaylist(path));
- m_loader->insert(before, list);
+ m_loader->insert(before, paths);
}
}
@@ -945,8 +927,12 @@ void PlayListModel::doCurrentVisibleRequest()
void PlayListModel::loadPlaylist(const QString &f_name)
{
- QStringList list = PlayListParser::loadPlaylist(f_name);
- m_loader->add(list);
+ m_loader->add(f_name);
+}
+
+void PlayListModel::loadPlaylist(const QString &fmt, const QByteArray &data)
+{
+ m_loader->addPlayList(fmt, data);
}
void PlayListModel::savePlaylist(const QString &f_name)
diff --git a/src/qmmpui/playlistmodel.h b/src/qmmpui/playlistmodel.h
index f7d393162..37fe5497d 100644
--- a/src/qmmpui/playlistmodel.h
+++ b/src/qmmpui/playlistmodel.h
@@ -287,6 +287,8 @@ public:
* Loads playlist with \b f_name name.
*/
void loadPlaylist(const QString& f_name);
+
+ void loadPlaylist(const QString &fmt, const QByteArray &data);
/*!
* Saves current songs to the playlist with \b f_name name.
*/
diff --git a/src/qmmpui/playlistparser.cpp b/src/qmmpui/playlistparser.cpp
index 70c3c3fe9..736a400cc 100644
--- a/src/qmmpui/playlistparser.cpp
+++ b/src/qmmpui/playlistparser.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2008-2014 by Ilya Kotov *
+ * Copyright (C) 2008-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -23,7 +23,6 @@
#include <QList>
#include <QDir>
#include <QApplication>
-#include <QTextStream>
#include <qmmp/qmmp.h>
#include "playlistformat.h"
#include "playlistparser.h"
@@ -32,13 +31,13 @@ QList<PlayListFormat*> *PlayListParser::m_formats = 0;
QList<PlayListFormat *> PlayListParser::formats()
{
- checkFormats();
+ loadFormats();
return *m_formats;
}
QStringList PlayListParser::nameFilters()
{
- checkFormats();
+ loadFormats();
QStringList filters;
foreach(PlayListFormat* format, *m_formats)
{
@@ -47,9 +46,20 @@ QStringList PlayListParser::nameFilters()
return filters;
}
+bool PlayListParser::isPlayList(const QString &url)
+{
+ foreach (QString filter, nameFilters())
+ {
+ QRegExp r(filter, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if(r.exactMatch(url))
+ return true;
+ }
+ return false;
+}
+
PlayListFormat *PlayListParser::findByMime(const QString &mime)
{
- checkFormats();
+ loadFormats();
foreach(PlayListFormat* format, *m_formats)
{
if(format->properties().contentTypes.contains(mime))
@@ -60,7 +70,7 @@ PlayListFormat *PlayListParser::findByMime(const QString &mime)
PlayListFormat *PlayListParser::findByPath(const QString &filePath)
{
- checkFormats();
+ loadFormats();
foreach(PlayListFormat* format, *m_formats)
{
foreach(QString filter, format->properties().filters)
@@ -89,50 +99,65 @@ void PlayListParser::savePlayList(QList<PlayListTrack *> tracks, const QString &
QFile file(f_name);
if (file.open(QIODevice::WriteOnly))
{
- QTextStream ts(&file);
- ts << prs->encode(tracks, QFileInfo(f_name).canonicalFilePath());
+ file.write(prs->encode(tracks, QFileInfo(f_name).canonicalFilePath()));
file.close();
}
else
qWarning("PlayListParser: unable to save playlist, error: %s", qPrintable(file.errorString()));
}
-QStringList PlayListParser::loadPlaylist(const QString &f_name)
+QList<PlayListTrack *> PlayListParser::loadPlaylist(const QString &f_name)
{
- QStringList list;
if(!QFile::exists(f_name))
- return list;
+ return QList<PlayListTrack *>();
PlayListFormat* prs = PlayListParser::findByPath(f_name);
if(!prs)
- return list;
+ return QList<PlayListTrack *>();
QFile file(f_name);
if (!file.open(QIODevice::ReadOnly))
{
qWarning("PlayListParser: unable to open playlist, error: %s", qPrintable(file.errorString()));
- return list;
+ return QList<PlayListTrack *>();
}
- list = prs->decode(QTextStream(&file).readAll());
- if(list.isEmpty())
+ QList <PlayListTrack*> tracks = prs->decode(file.readAll());
+
+ if(tracks.isEmpty())
+ {
qWarning("PlayListParser: error opening %s",qPrintable(f_name));
+ return tracks;
+ }
- for (int i = 0; i < list.size(); ++i)
+ QString url;
+ foreach (PlayListTrack *t, tracks)
{
- if(list.at(i).contains("://"))
+ url = t->value(Qmmp::URL);
+
+ if(url.contains("://"))
continue;
- if (QFileInfo(list.at(i)).isRelative())
- list[i].prepend(QFileInfo(f_name).canonicalPath () + "/");
+ if(QFileInfo(url).isRelative())
+ url.prepend(QFileInfo(f_name).canonicalPath () + "/");
- list[i].replace("\\","/");
- list[i].replace("//","/");
+ url.replace("\\","/");
+ url.replace("//","/");
+ t->insert(Qmmp::URL, url);
+ }
+ return tracks;
+}
+
+QList<PlayListTrack *> PlayListParser::loadPlaylist(const QString &fmt, const QByteArray &contents)
+{
+ foreach (PlayListFormat *p, *m_formats)
+ {
+ if(p->properties().shortName == fmt)
+ return p->decode(contents);
}
- file.close();
- return list;
+ return QList<PlayListTrack *>();
}
-void PlayListParser::checkFormats()
+void PlayListParser::loadFormats()
{
if (m_formats)
return;
diff --git a/src/qmmpui/playlistparser.h b/src/qmmpui/playlistparser.h
index c8e779b84..c171116e0 100644
--- a/src/qmmpui/playlistparser.h
+++ b/src/qmmpui/playlistparser.h
@@ -39,6 +39,9 @@ public:
* Returns a list of the supported files name filters, i.e. "*.m3u *.pls"
*/
static QStringList nameFilters();
+
+ static bool isPlayList(const QString &url);
+
/*!
* Returns PlayListFormat pointer which supports mime type \b mime
* or \b 0 if mime type \b mime is unsupported
@@ -59,17 +62,23 @@ public:
* @param tracks A list of tracks.
* @param f_name File name the playlist.
*/
- static void savePlayList(QList <PlayListTrack *> tracks, const QString &f_name);
+ static void savePlayList(QList<PlayListTrack *> tracks, const QString &f_name);
/*!
* Loads playlist from file \b f_name
* @param f_name File name.
* @return A list of URLs or file paths.
*/
- static QStringList loadPlaylist(const QString &f_name);
+ static QList<PlayListTrack *> loadPlaylist(const QString &f_name);
+
+ static QList<PlayListTrack *> loadPlaylist(const QString &fmt, const QByteArray &contents);
+ /*!
+ * Loads all playlist plugins. Should be called before usage from another thread.
+ */
+ static void loadFormats();
private:
PlayListParser(){}
- static void checkFormats();
+
static QList<PlayListFormat*> *m_formats;
diff --git a/src/qmmpui/playlisttrack.cpp b/src/qmmpui/playlisttrack.cpp
index fc9c139e9..917e95399 100644
--- a/src/qmmpui/playlisttrack.cpp
+++ b/src/qmmpui/playlisttrack.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2008-2015 by Ilya Kotov *
+ * Copyright (C) 2008-2017 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -59,7 +59,7 @@ PlayListTrack::PlayListTrack(FileInfo *info) : QMap<Qmmp::MetaData, QString>(in
m_track_index = -1;
m_settings = QmmpUiSettings::instance();
m_helper = MetaDataHelper::instance();
- setLength(m_length = info->length());
+ m_length = info->length();
insert(Qmmp::URL, info->path());
m_refCount = 0;
m_sheduledForDeletion = false;
@@ -78,17 +78,23 @@ void PlayListTrack::updateMetaData(const QMap <Qmmp::MetaData, QString> &metaDat
formatGroup();
}
+void PlayListTrack::updateMetaData(FileInfo *info)
+{
+ m_length = info->length();
+ QMap <Qmmp::MetaData, QString>::operator =(info->metaData());
+ insert(Qmmp::URL, info->path());
+ m_formattedTitles.clear();
+ m_formattedLength.clear();
+ formatGroup();
+}
+
void PlayListTrack::updateMetaData()
{
QList <FileInfo *> list = MetaDataManager::instance()->createPlayList(value(Qmmp::URL));
if(!list.isEmpty() && !list.at(0)->path().contains("://"))
{
FileInfo *info = list.at(0);
- m_length = info->length();
- QMap <Qmmp::MetaData, QString>::operator =(info->metaData());
- insert(Qmmp::URL, info->path());
- m_formattedTitles.clear();
- formatGroup();
+ updateMetaData(info);
}
qDeleteAll(list);
}
@@ -223,7 +229,7 @@ qint64 PlayListTrack::length() const
void PlayListTrack::setLength(qint64 length)
{
- m_length = length;
+ m_length = qMax(length, 0LL);
m_formattedLength.clear();
}
diff --git a/src/qmmpui/playlisttrack.h b/src/qmmpui/playlisttrack.h
index 2c832f616..97674f0fd 100644
--- a/src/qmmpui/playlisttrack.h
+++ b/src/qmmpui/playlisttrack.h
@@ -84,6 +84,11 @@ public:
*/
void updateMetaData(const QMap <Qmmp::MetaData, QString> &metaData);
/*!
+ * Updates current metadata.
+ * @param info Media file information.
+ */
+ void updateMetaData(FileInfo *info);
+ /*!
* Gets new metadata from file (works for local files only).
*/
void updateMetaData();