#include #include #include #include #include #include #include "qmafwwatchlet.h" #include "qmafwwatchletplayer.h" using namespace sowatch; const QLatin1String QMafwWatchletPlayer::_volumeProp("volume"); QMafwWatchletPlayer::QMafwWatchletPlayer(QMafwWatchlet* watchlet) : QObject(watchlet), _active(false), _renderer(0), _state(MafwRenderer::Stopped), _title(), _album(), _artist(), _rendererArt(), _mediaArt() { Q_ASSERT(watchlet); } QString QMafwWatchletPlayer::title() const { return _title; } QString QMafwWatchletPlayer::album() const { return _album; } QString QMafwWatchletPlayer::artist() const { return _artist; } QUrl QMafwWatchletPlayer::mediaArt() const { return _mediaArt; } void QMafwWatchletPlayer::activate() { _active = true; reconnect(); } void QMafwWatchletPlayer::deactivate() { _active = false; reconnect(); } void QMafwWatchletPlayer::playPause() { if (!_renderer) return; if (_state == MafwRenderer::Playing) { _renderer->pause(); } else if (_state == MafwRenderer::Paused) { _renderer->resume(); } else { _renderer->play(); } } void QMafwWatchletPlayer::play() { if (!_renderer) return; _renderer->play(); } void QMafwWatchletPlayer::pause() { if (!_renderer) return; _renderer->pause(); } void QMafwWatchletPlayer::stop() { if (!_renderer) return; _renderer->stop(); } void QMafwWatchletPlayer::next() { if (!_renderer) return; _renderer->next(); } void QMafwWatchletPlayer::previous() { if (!_renderer) return; _renderer->previous(); } void QMafwWatchletPlayer::volumeUp() { if (!_renderer) return; QString prop(_volumeProp); _renderer->mafwProperty(prop, qobject_cast(this), SLOT(doVolumeUp(QString,QVariant))); } void QMafwWatchletPlayer::volumeDown() { if (!_renderer) return; QString prop(_volumeProp); _renderer->mafwProperty(prop, qobject_cast(this), SLOT(doVolumeDown(QString,QVariant))); } void QMafwWatchletPlayer::setRenderer(MafwRenderer * renderer) { if (_renderer && _active) { disconnect(_renderer, 0, this, 0); _title.clear(); _album.clear(); _artist.clear(); handleMediaChange(); emit titleChanged(); updateMediaArt(); } _renderer = renderer; reconnect(); } void QMafwWatchletPlayer::reconnect() { if (_renderer && _active) { connect(_renderer, SIGNAL(mediaChanged(int, const MafwContent&)), this, SLOT(handleMediaChange())); connect(_renderer, SIGNAL(metadataChanged(const QString&, const QList&)), this, SLOT(handleChangedMetadata(const QString&, const QList&))); connect(_renderer, SIGNAL(stateChanged(MafwRenderer::State)), this, SLOT(handleChangedState(MafwRenderer::State))); _renderer->getStatus(this, SLOT(handleStatusResults(QString,uint,int))); _renderer->getCurrentMediaInfo(this, SLOT(handleMediaInfo(MafwMediaInfo))); } else if (_renderer) { disconnect(_renderer, 0, this, 0); } } QString QMafwWatchletPlayer::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 QMafwWatchletPlayer::mediaArtPath() const { QDir dir(QDir::homePath() + "/.cache/media-art/"); QString album = stripAlbumArtComponent(_album); QString artist = stripAlbumArtComponent(_artist); QByteArray first_hash = QCryptographicHash::hash(artist.toUtf8(), QCryptographicHash::Md5).toHex(); QByteArray second_hash = QCryptographicHash::hash(album.toUtf8(), QCryptographicHash::Md5).toHex(); QString file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData()); qDebug() << "checking for albumart in" << file; if (dir.exists(file)) { return dir.absoluteFilePath(file); } artist = " "; first_hash = QCryptographicHash::hash(artist.toUtf8(), QCryptographicHash::Md5).toHex(); file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData()); qDebug() << "checking for albumart in" << file; if (dir.exists(file)) { return dir.absoluteFilePath(file); } return QString(); } void QMafwWatchletPlayer::updateMediaArt() { QUrl newArt; if (!_rendererArt.isEmpty()) { newArt = QUrl::fromLocalFile(_rendererArt); } else { QString path = mediaArtPath(); if (!path.isEmpty()) { newArt = QUrl::fromLocalFile(path); } } if (newArt != _mediaArt) { _mediaArt = newArt; emit mediaArtChanged(); } } void QMafwWatchletPlayer::handleMediaChange() { // Sometimes qmafw does not send the renderer-art metadata, so we assume it's been cleared here. _rendererArt.clear(); } void QMafwWatchletPlayer::handleChangedMetadata(const QString &s, const QList &l) { if (s == MAFW_METADATA_KEY_TITLE) { if (!l.isEmpty()) { _title = l[0].toString(); } else { _title.clear(); } emit titleChanged(); } else if (s == MAFW_METADATA_KEY_ALBUM) { if (!l.isEmpty()) { _album = l[0].toString(); } else { _album.clear(); } emit albumChanged(); updateMediaArt(); } else if (s == MAFW_METADATA_KEY_ARTIST) { if (!l.isEmpty()) { _artist = l[0].toString(); } else { _artist.clear(); } emit artistChanged(); updateMediaArt(); } else if (s == MAFW_METADATA_KEY_RENDERER_ART_URI) { if (!l.isEmpty()) { _rendererArt = l[0].toString(); } else { _rendererArt.clear(); } updateMediaArt(); } } void QMafwWatchletPlayer::handleChangedState(MafwRenderer::State state) { _state = state; } void QMafwWatchletPlayer::handleMediaInfo(const MafwMediaInfo &info) { const QMap > & data = info.metaData(); handleChangedMetadata(MAFW_METADATA_KEY_TITLE, data[MAFW_METADATA_KEY_TITLE]); handleChangedMetadata(MAFW_METADATA_KEY_ALBUM, data[MAFW_METADATA_KEY_ALBUM]); handleChangedMetadata(MAFW_METADATA_KEY_ARTIST, data[MAFW_METADATA_KEY_ARTIST]); handleChangedMetadata(MAFW_METADATA_KEY_RENDERER_ART_URI, data[MAFW_METADATA_KEY_RENDERER_ART_URI]); } void QMafwWatchletPlayer::handleStatusResults(const QString &playlistId, uint playbackIndex, int playbackState) { Q_UNUSED(playlistId); Q_UNUSED(playbackIndex); _state = static_cast(playbackState); } void QMafwWatchletPlayer::doVolumeUp(const QString& name, const QVariant& value) { _renderer->setMafwProperty(name, value.toUInt() + 10); } void QMafwWatchletPlayer::doVolumeDown(const QString& name, const QVariant& value) { _renderer->setMafwProperty(name, value.toUInt() - 10); }