summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-12-27 21:55:19 +0100
committerJavier <dev.git@javispedro.com>2015-12-27 21:55:19 +0100
commit41677b58d971ab57a79514d972f10acb04797130 (patch)
tree2f85a5427f1bfc8952ef731dccb1ee09123f7895
parentffeca2b8740fba10e916fe04e89ef2fd5c606a90 (diff)
downloadlibwatchfish-41677b58d971ab57a79514d972f10acb04797130.tar.gz
libwatchfish-41677b58d971ab57a79514d972f10acb04797130.zip
initial music controller implementation
-rw-r--r--musiccontroller.cpp277
-rw-r--r--musiccontroller.h59
-rw-r--r--musiccontroller_p.h27
-rw-r--r--notificationmonitor.h2
-rw-r--r--walltimemonitor.h2
5 files changed, 362 insertions, 5 deletions
diff --git a/musiccontroller.cpp b/musiccontroller.cpp
index ba9fc39..638d440 100644
--- a/musiccontroller.cpp
+++ b/musiccontroller.cpp
@@ -16,21 +16,183 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <QtCore/QDir>
+#include <QtCore/QCryptographicHash>
+
#include "musiccontroller.h"
#include "musiccontroller_p.h"
namespace watchfish
{
+Q_LOGGING_CATEGORY(musicControllerCat, "watchfish-MusicController")
+
MusicControllerPrivate::MusicControllerPrivate(MusicController *q)
- : q_ptr(q)
+ : manager(new MprisManager(this)), q_ptr(q)
{
+ connect(manager, &MprisManager::currentServiceChanged,
+ this, &MusicControllerPrivate::handleCurrentServiceChanged);
+ connect(manager, &MprisManager::playbackStatusChanged,
+ this, &MusicControllerPrivate::handlePlaybackStatusChanged);
+ connect(manager, &MprisManager::metadataChanged,
+ this, &MusicControllerPrivate::handleMetadataChanged);
+ connect(manager, &MprisManager::shuffleChanged,
+ q, &MusicController::shuffleChanged);
+ connect(manager, &MprisManager::loopStatusChanged,
+ q, &MusicController::repeatChanged);
}
MusicControllerPrivate::~MusicControllerPrivate()
{
}
+QString MusicControllerPrivate::stripAlbumArtComponent(const QString& component)
+{
+ static QRegExp rsb("\\[.*\\]");
+ static QRegExp rfb("{.*}");
+ static QRegExp rrb("\\(.*\\)");
+ static QRegExp stripB("^[()_{}[]!@#$^&*+=|\\\\/\"'?<>~`\\s\\t]*");
+ static QRegExp stripE("[()_{}[]!@#$^&*+=|\\\\/\"'?<>~`\\s\\t]*$");
+ QString s(component);
+
+ if (s.isEmpty()) {
+ return QString(" ");
+ }
+
+ s = s.replace(rsb, "");
+ s = s.replace(rfb, "");
+ s = s.replace(rrb, "");
+ s = s.replace(stripB, "");
+ s = s.replace(stripE, "");
+ s = s.replace(" ", " ");
+ s = s.replace("\t", " ");
+
+ return s.toLower();
+}
+
+QString MusicControllerPrivate::findAlbumArt(const QString &artist, const QString &album)
+{
+ QDir dir(QDir::homePath() + "/.cache/media-art/");
+ QByteArray first_hash = QCryptographicHash::hash(stripAlbumArtComponent(artist).toUtf8(),
+ QCryptographicHash::Md5).toHex();
+ QByteArray second_hash = QCryptographicHash::hash(stripAlbumArtComponent(album).toUtf8(),
+ QCryptographicHash::Md5).toHex();
+ QString file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData());
+ qCDebug(musicControllerCat()) << "checking for albumart in" << file;
+ if (dir.exists(file)) {
+ return dir.absoluteFilePath(file);
+ }
+
+ // Now try with an empty artist name
+ first_hash = QCryptographicHash::hash(QString(" ").toUtf8(), QCryptographicHash::Md5).toHex();
+ file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData());
+ qCDebug(musicControllerCat()) << "checking for albumart in" << file;
+ if (dir.exists(file)) {
+ return dir.absoluteFilePath(file);
+ }
+
+ return QString();
+}
+
+void MusicControllerPrivate::updateStatus()
+{
+ Q_Q(MusicController);
+ QString service = manager->currentService();
+ MusicController::Status newStatus;
+
+ if (service.isEmpty()) {
+ newStatus = MusicController::StatusNoPlayer;
+ } else {
+ switch (manager->playbackStatus()) {
+ case Mpris::Playing:
+ newStatus = MusicController::StatusPlaying;
+ break;
+ case Mpris::Paused:
+ newStatus = MusicController::StatusPaused;
+ break;
+ default:
+ newStatus = MusicController::StatusStopped;
+ break;
+ }
+ }
+
+ if (newStatus != curStatus) {
+ curStatus = newStatus;
+ emit q->statusChanged();
+ }
+}
+
+void MusicControllerPrivate::updateAlbumArt()
+{
+ Q_Q(MusicController);
+ QString newAlbumArt = findAlbumArt(curArtist, curAlbum);
+ if (newAlbumArt != curAlbumArt) {
+ curAlbumArt = newAlbumArt;
+ emit q->albumArtChanged();
+ }
+}
+
+void MusicControllerPrivate::updateMetadata()
+{
+ Q_Q(MusicController);
+ QVariantMap metadata = manager->metadata();
+ bool checkAlbumArt = false;
+
+ qCDebug(musicControllerCat()) << metadata;
+
+ QString newArtist = metadata.value("xesam:artist").toString(),
+ newAlbum = metadata.value("xesam:album").toString(),
+ newTitle = metadata.value("xesam:title").toString();
+
+ if (newArtist != curArtist) {
+ curArtist = newArtist;
+ checkAlbumArt = true;
+ emit q->artistChanged();
+ }
+
+ if (newAlbum != curAlbum) {
+ curAlbum = newAlbum;
+ checkAlbumArt = true;
+ emit q->albumChanged();
+ }
+
+ if (newTitle != curTitle) {
+ curTitle = newTitle;
+ emit q->titleChanged();
+ }
+
+ if (checkAlbumArt) {
+ updateAlbumArt();
+ }
+
+ int newDuration = metadata.value("mpris:length").toULongLong() / 1000UL;
+ if (newDuration != curDuration) {
+ curDuration = newDuration;
+ emit q->durationChanged();
+ }
+
+ emit q->metadataChanged();
+}
+
+void MusicControllerPrivate::handleCurrentServiceChanged()
+{
+ Q_Q(MusicController);
+ qCDebug(musicControllerCat()) << manager->currentService();
+ updateStatus();
+ emit q->serviceChanged();
+}
+
+void MusicControllerPrivate::handlePlaybackStatusChanged()
+{
+ qCDebug(musicControllerCat()) << manager->playbackStatus();
+ updateStatus();
+}
+
+void MusicControllerPrivate::handleMetadataChanged()
+{
+ updateMetadata();
+}
+
MusicController::MusicController(QObject *parent)
: QObject(parent), d_ptr(new MusicControllerPrivate(this))
{
@@ -41,4 +203,117 @@ MusicController::~MusicController()
delete d_ptr;
}
+MusicController::Status MusicController::status() const
+{
+ Q_D(const MusicController);
+ return d->curStatus;
+}
+
+QString MusicController::service() const
+{
+ Q_D(const MusicController);
+ return d->manager->currentService();
+}
+
+QVariantMap MusicController::metadata() const
+{
+ Q_D(const MusicController);
+ return d->manager->metadata();
+}
+
+QString MusicController::title() const
+{
+ Q_D(const MusicController);
+ return d->curTitle;
+}
+
+QString MusicController::album() const
+{
+ Q_D(const MusicController);
+ return d->curAlbum;
+}
+
+QString MusicController::artist() const
+{
+ Q_D(const MusicController);
+ return d->curArtist;
+}
+
+QString MusicController::albumArt() const
+{
+ Q_D(const MusicController);
+ return d->curAlbumArt;
+}
+
+int MusicController::duration() const
+{
+ Q_D(const MusicController);
+ return d->curDuration;
+}
+
+MusicController::RepeatStatus MusicController::repeat() const
+{
+ Q_D(const MusicController);
+ switch (d->manager->loopStatus()) {
+ case Mpris::None:
+ default:
+ return RepeatNone;
+ case Mpris::Track:
+ return RepeatTrack;
+ case Mpris::Playlist:
+ return RepeatPlaylist;
+ }
+}
+
+bool MusicController::shuffle() const
+{
+ Q_D(const MusicController);
+ return d->manager->shuffle();
+}
+
+int MusicController::volume() const
+{
+ return 100; // TODO volume
+}
+
+void MusicController::play()
+{
+ Q_D(MusicController);
+ d->manager->play();
+}
+
+void MusicController::pause()
+{
+ Q_D(MusicController);
+ d->manager->pause();
+}
+
+void MusicController::playPause()
+{
+ Q_D(MusicController);
+ d->manager->playPause();
+}
+
+void MusicController::next()
+{
+ Q_D(MusicController);
+ d->manager->next();
+}
+
+void MusicController::previous()
+{
+ Q_D(MusicController);
+ d->manager->previous();
+}
+
+void MusicController::volumeUp()
+{
+
+}
+
+void MusicController::volumeDown()
+{
+
+}
+
}
diff --git a/musiccontroller.h b/musiccontroller.h
index 33f6810..acf5beb 100644
--- a/musiccontroller.h
+++ b/musiccontroller.h
@@ -19,22 +19,79 @@
#ifndef WATCHFISH_MUSICCONTROLLER_H
#define WATCHFISH_MUSICCONTROLLER_H
-#include <QtCore/QObject>
+#include <QtCore/QLoggingCategory>
namespace watchfish
{
+Q_DECLARE_LOGGING_CATEGORY(musicControllerCat)
+
class MusicControllerPrivate;
class MusicController : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(MusicController)
+ Q_ENUMS(Status)
public:
explicit MusicController(QObject *parent = 0);
~MusicController();
+ enum Status {
+ StatusNoPlayer = 0,
+ StatusStopped,
+ StatusPaused,
+ StatusPlaying
+ };
+
+ enum RepeatStatus {
+ RepeatNone = 0,
+ RepeatTrack,
+ RepeatPlaylist
+ };
+
+ Status status() const;
+ QString service() const;
+
+ QVariantMap metadata() const;
+
+ QString title() const;
+ QString album() const;
+ QString artist() const;
+
+ QString albumArt() const;
+
+ int duration() const;
+
+ RepeatStatus repeat() const;
+ bool shuffle() const;
+
+ int volume() const;
+
+public slots:
+ void play();
+ void pause();
+ void playPause();
+ void next();
+ void previous();
+
+ void volumeUp();
+ void volumeDown();
+
+signals:
+ void statusChanged();
+ void serviceChanged();
+ void metadataChanged();
+ void titleChanged();
+ void albumChanged();
+ void artistChanged();
+ void albumArtChanged();
+ void durationChanged();
+ void repeatChanged();
+ void shuffleChanged();
+ void volumeChanged();
+
private:
MusicControllerPrivate * const d_ptr;
};
diff --git a/musiccontroller_p.h b/musiccontroller_p.h
index 5711e65..dd26ff0 100644
--- a/musiccontroller_p.h
+++ b/musiccontroller_p.h
@@ -1,15 +1,15 @@
#ifndef WATCHFISH_MUSICCONTROLLER_P_H
#define WATCHFISH_MUSICCONTROLLER_P_H
-#include <QtDBus/QDBusServiceWatcher>
-#include <QtDBus/QDBusContext>
+#include <MprisQt/mpris.h>
+#include <MprisQt/mprismanager.h>
#include "musiccontroller.h"
namespace watchfish
{
-class MusicControllerPrivate : public QObject, protected QDBusContext
+class MusicControllerPrivate : public QObject
{
Q_OBJECT
@@ -17,6 +17,27 @@ public:
MusicControllerPrivate(MusicController *q);
~MusicControllerPrivate();
+public:
+ MprisManager *manager;
+ MusicController::Status curStatus;
+ QString curTitle;
+ QString curAlbum;
+ QString curArtist;
+ QString curAlbumArt;
+ int curDuration;
+
+private:
+ static QString stripAlbumArtComponent(const QString& component);
+ static QString findAlbumArt(const QString &artist, const QString &album);
+ void updateStatus();
+ void updateAlbumArt();
+ void updateMetadata();
+
+private slots:
+ void handleCurrentServiceChanged();
+ void handlePlaybackStatusChanged();
+ void handleMetadataChanged();
+
private:
MusicController * const q_ptr;
Q_DECLARE_PUBLIC(MusicController)
diff --git a/notificationmonitor.h b/notificationmonitor.h
index 03683ca..4aad942 100644
--- a/notificationmonitor.h
+++ b/notificationmonitor.h
@@ -28,6 +28,8 @@
namespace watchfish
{
+Q_DECLARE_LOGGING_CATEGORY(notificationMonitorCat)
+
class NotificationMonitorPrivate;
class NotificationMonitor : public QObject
diff --git a/walltimemonitor.h b/walltimemonitor.h
index f2f6b95..8001b02 100644
--- a/walltimemonitor.h
+++ b/walltimemonitor.h
@@ -26,6 +26,8 @@
namespace watchfish
{
+Q_DECLARE_LOGGING_CATEGORY(walltimeMonitorCat)
+
class WallTimeMonitorPrivate;
class WallTimeMonitor : public QObject