diff --git a/CMakeLists.txt b/CMakeLists.txt index e94cda84f..8187025db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -247,7 +247,7 @@ set(CANTATA_MOC_HDRS widgets/playqueueview.h widgets/groupedview.h widgets/actionitemdelegate.h widgets/coverwidget.h widgets/volumeslider.h widgets/genrecombo.h widgets/toolbar.h widgets/searchwidget.h widgets/messageoverlay.h widgets/servicestatuslabel.h network/networkaccessmanager.h - http/httpserversettings.h http/httpsocket.h + http/httpserver.h http/httpsocket.h context/togglelist.h context/ultimatelyrics.h context/ultimatelyricsprovider.h context/lyricsdialog.h context/contextwidget.h context/artistview.h context/albumview.h context/songview.h context/view.h context/contextengine.h context/wikipediaengine.h context/wikipediasettings.h context/othersettings.h context/lastfmengine.h context/metaengine.h diff --git a/ChangeLog b/ChangeLog index 0eb45c35b..ba6862ded 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,7 +21,9 @@ 12. When adding files to playqueue, only add in batches of up to 2000 songs. This 'chunk size' may be altered by setting mpdListSize in Cantata's config file - see README for details. -13. Add 'Remove dusplicates' functionality to play queue and play lists. +13. Add 'Remove duplicates' functionality to play queue and play lists. +14. Only start internal HTTP server when required, and stop 1 second after + last Cantata stream is removed. 1.2.2 ----- diff --git a/http/httpserver.cpp b/http/httpserver.cpp index 569153ecb..0a1d17f6a 100644 --- a/http/httpserver.cpp +++ b/http/httpserver.cpp @@ -30,6 +30,7 @@ #include "thread.h" #include #include +#include #if QT_VERSION >= 0x050000 #include #endif @@ -72,51 +73,72 @@ HttpServer * HttpServer::self() #endif } -void HttpServer::stop() +HttpServer::HttpServer() + : QObject(0) + , thread(0) + , socket(0) + , closeTimer(0) { - if (socket) { - socket->terminate(); - socket=0; - } - - if (thread) { - thread->stop(); - thread=0; - } + connect(MPDConnection::self(), SIGNAL(socketAddress(QString)), this, SLOT(mpdAddress(QString))); + connect(MPDConnection::self(), SIGNAL(cantataStreams(QList,bool)), this, SLOT(cantataStreams(QList,bool))); + connect(MPDConnection::self(), SIGNAL(cantataStreams(QStringList)), this, SLOT(cantataStreams(QStringList))); + connect(MPDConnection::self(), SIGNAL(removedIds(QSet)), this, SLOT(removedIds(QSet))); } -bool HttpServer::readConfig() +bool HttpServer::start() { - QString iface=Settings::self()->httpInterface(); + if (closeTimer) { + DBUG << "stop close timer"; + closeTimer->stop(); + } - if (socket && socket->isListening() && iface==socket->configuredInterface()) { + if (socket) { + DBUG << "already open"; return true; } - if (socket) { - socket->terminate(); - socket=0; - } - - if (thread) { - thread->stop(); - thread=0; - } - + DBUG << "open new socket"; quint16 prevPort=Settings::self()->httpAllocatedPort(); - thread=new Thread("HttpServer"); - socket=new HttpSocket(iface, prevPort); + bool newThread=0==thread; + if (newThread) { + thread=new Thread("HttpServer"); + } + socket=new HttpSocket(Settings::self()->httpInterface(), prevPort); + socket->mpdAddress(mpdAddr); + connect(this, SIGNAL(terminateSocket()), socket, SLOT(terminate()), Qt::QueuedConnection); if (socket->serverPort()!=prevPort) { Settings::self()->saveHttpAllocatedPort(socket->serverPort()); } socket->moveToThread(thread); - thread->start(); - return socket->isListening(); + bool started=socket->isListening(); + if (newThread) { + thread->start(); + } + return started; } -bool HttpServer::isAlive() const +void HttpServer::stop() { - return socket && socket->isListening(); + if (socket) { + DBUG; + emit terminateSocket(); + socket=0; + } +} + +void HttpServer::readConfig() +{ + QString iface=Settings::self()->httpInterface(); + + if (socket && socket->isListening() && iface==socket->configuredInterface()) { + return; + } + + bool wasStarted=0!=socket; + stop(); + if (wasStarted) { + start(); + } } QString HttpServer::address() const @@ -127,13 +149,13 @@ QString HttpServer::address() const bool HttpServer::isOurs(const QString &url) const { - return isAlive() ? url.startsWith(address()+"/") : false; + return 0!=socket ? url.startsWith(address()+"/") : false; } -QByteArray HttpServer::encodeUrl(const Song &s) const +QByteArray HttpServer::encodeUrl(const Song &s) { DBUG << "song" << s.file << isAlive(); - if (!isAlive()) { + if (!start()) { return QByteArray(); } #if QT_VERSION < 0x050000 @@ -186,7 +208,7 @@ QByteArray HttpServer::encodeUrl(const Song &s) const return url.toEncoded(); } -QByteArray HttpServer::encodeUrl(const QString &file) const +QByteArray HttpServer::encodeUrl(const QString &file) { Song s; #ifdef Q_OS_WIN @@ -284,3 +306,57 @@ Song HttpServer::decodeUrl(const QUrl &url) const return s; } + +void HttpServer::startCloseTimer() +{ + if (!closeTimer) { + closeTimer=new QTimer(this); + closeTimer->setSingleShot(true); + connect(closeTimer, SIGNAL(timeout()), this, SLOT(stop())); + } + DBUG; + closeTimer->start(1000); +} + +void HttpServer::mpdAddress(const QString &a) +{ + mpdAddr=a; +} + +void HttpServer::cantataStreams(const QStringList &files) +{ + DBUG << files; + foreach (const QString &f, files) { + Song s=HttpServer::self()->decodeUrl(f); + if (s.isCantataStream() || s.isCdda()) { + start(); + break; + } + } +} + +void HttpServer::cantataStreams(const QList &songs, bool isUpdate) +{ + DBUG << isUpdate << songs.count(); + if (!isUpdate) { + streamIds.clear(); + } + + foreach (const Song &s, songs) { + streamIds.insert(s.id); + } + + if (streamIds.isEmpty()) { + startCloseTimer(); + } else { + start(); + } +} + +void HttpServer::removedIds(const QSet &ids) +{ + streamIds+=ids; + if (streamIds.isEmpty()) { + startCloseTimer(); + } +} diff --git a/http/httpserver.h b/http/httpserver.h index 231898eac..5fd54061d 100644 --- a/http/httpserver.h +++ b/http/httpserver.h @@ -24,39 +24,60 @@ #ifndef _HTTP_SERVER_H #define _HTTP_SERVER_H -#include +#include #include +#include #include "song.h" #include "config.h" class HttpSocket; class Thread; class QUrl; +class QTimer; -class HttpServer +class HttpServer : public QObject { + Q_OBJECT + public: static void enableDebug(); static bool debugEnabled(); static HttpServer * self(); - HttpServer() : thread(0), socket(0) { } + HttpServer(); virtual ~HttpServer() { } - void stop(); - bool isAlive() const; - bool readConfig(); + bool start(); + bool isAlive() const { return true; } // Started on-demamnd! + void readConfig(); QString address() const; bool isOurs(const QString &url) const; - QByteArray encodeUrl(const Song &s) const; - QByteArray encodeUrl(const QString &file) const; + QByteArray encodeUrl(const Song &s); + QByteArray encodeUrl(const QString &file); Song decodeUrl(const QUrl &url) const; Song decodeUrl(const QString &file) const; +public Q_SLOTS: + void stop(); + +private Q_SLOTS: + void startCloseTimer(); + void mpdAddress(const QString &a); + void cantataStreams(const QStringList &files); + void cantataStreams(const QList &songs, bool isUpdate); + void removedIds(const QSet &ids); + +Q_SIGNALS: + void terminateSocket(); + private: Thread *thread; HttpSocket *socket; + + QString mpdAddr; + QSet streamIds; // Currently playing MPD stream IDs + QTimer *closeTimer; }; #endif diff --git a/http/httpserversettings.cpp b/http/httpserversettings.cpp index dc24e5daf..86f68c987 100644 --- a/http/httpserversettings.cpp +++ b/http/httpserversettings.cpp @@ -26,7 +26,6 @@ #include "localize.h" #include "httpserver.h" #include -#include #include static int isIfaceType(const QNetworkInterface &iface, const QString &prefix) @@ -64,7 +63,6 @@ HttpServerSettings::HttpServerSettings(QWidget *p) { setupUi(this); initInterfaces(httpInterface); - updateStatus(); } void HttpServerSettings::load() @@ -87,14 +85,4 @@ void HttpServerSettings::save() { Settings::self()->saveHttpInterface(httpInterface->itemData(httpInterface->currentIndex()).toString()); HttpServer::self()->readConfig(); - QTimer::singleShot(250, this, SLOT(updateStatus())); -} - -void HttpServerSettings::updateStatus() -{ - if (HttpServer::self()->isAlive()) { - status->setText(HttpServer::self()->address()); - } else { - status->setText(i18n("Inactive")); - } } diff --git a/http/httpserversettings.h b/http/httpserversettings.h index 240fa48e5..6c829bda1 100644 --- a/http/httpserversettings.h +++ b/http/httpserversettings.h @@ -28,7 +28,6 @@ class HttpServerSettings : public QWidget, private Ui::HttpServerSettings { - Q_OBJECT public: HttpServerSettings(QWidget *p); virtual ~HttpServerSettings() { } @@ -36,9 +35,6 @@ public: void load(); void save(); bool haveMultipleInterfaces() const; - -private Q_SLOTS: - void updateStatus(); }; #endif diff --git a/http/httpserversettings.ui b/http/httpserversettings.ui index 0e6d3720e..8388de154 100644 --- a/http/httpserversettings.ui +++ b/http/httpserversettings.ui @@ -32,22 +32,6 @@ - - - - Current URL: - - - - - - - - true - - - - diff --git a/http/httpsocket.cpp b/http/httpsocket.cpp index 8705921af..6883d9eeb 100644 --- a/http/httpsocket.cpp +++ b/http/httpsocket.cpp @@ -259,6 +259,8 @@ HttpSocket::HttpSocket(const QString &iface, quint16 port) ifaceAddress=QLatin1String("127.0.0.1"); } + DBUG << isListening() << ifaceAddress << serverPort(); + connect(MPDConnection::self(), SIGNAL(socketAddress(QString)), this, SLOT(mpdAddress(QString))); connect(MPDConnection::self(), SIGNAL(cantataStreams(QList,bool)), this, SLOT(cantataStreams(QList,bool))); connect(MPDConnection::self(), SIGNAL(cantataStreams(QStringList)), this, SLOT(cantataStreams(QStringList))); @@ -293,7 +295,12 @@ bool HttpSocket::openPort(const QHostAddress &a, quint16 p) void HttpSocket::terminate() { + if (terminated) { + return; + } + DBUG; terminated=true; + close(); deleteLater(); } diff --git a/http/httpsocket.h b/http/httpsocket.h index 2ac951bd3..c3cacbd42 100644 --- a/http/httpsocket.h +++ b/http/httpsocket.h @@ -41,11 +41,14 @@ public: HttpSocket(const QString &iface, quint16 port); virtual ~HttpSocket() { } - void terminate(); void incomingConnection(int socket); QString address() const { return ifaceAddress; } QString configuredInterface() { return cfgInterface; } +public Q_SLOTS: + void terminate(); + void mpdAddress(const QString &a); + private: bool openPort(const QHostAddress &a, quint16 p); bool isCantataStream(const QString &file) const; @@ -54,7 +57,6 @@ private: private Q_SLOTS: void readClient(); void discardClient(); - void mpdAddress(const QString &a); void cantataStreams(const QStringList &files); void cantataStreams(const QList &songs, bool isUpdate); void removedIds(const QSet &ids);