mpris-remote: Support for fetching album art
Implementation of sending album art from phone to PC. Complementary MR for the android side: https://invent.kde.org/network/kdeconnect-android/-/merge_requests/353 Fixes: https://bugs.kde.org/show_bug.cgi?id=422136
This commit is contained in:
parent
ce92c5beba
commit
f2e506e059
8 changed files with 304 additions and 0 deletions
|
@ -2,6 +2,7 @@ kdeconnect_add_plugin(kdeconnect_mprisremote)
|
||||||
|
|
||||||
target_sources(kdeconnect_mprisremote PRIVATE
|
target_sources(kdeconnect_mprisremote PRIVATE
|
||||||
mprisremoteplugin.cpp
|
mprisremoteplugin.cpp
|
||||||
|
albumart_cache.cpp
|
||||||
mprisremoteplayer.cpp
|
mprisremoteplayer.cpp
|
||||||
mprisremoteplayermediaplayer2.cpp
|
mprisremoteplayermediaplayer2.cpp
|
||||||
mprisremoteplayermediaplayer2player.cpp
|
mprisremoteplayermediaplayer2player.cpp
|
||||||
|
@ -9,4 +10,5 @@ target_sources(kdeconnect_mprisremote PRIVATE
|
||||||
target_link_libraries(kdeconnect_mprisremote
|
target_link_libraries(kdeconnect_mprisremote
|
||||||
kdeconnectcore
|
kdeconnectcore
|
||||||
Qt::DBus
|
Qt::DBus
|
||||||
|
Qt::Core # for hash
|
||||||
)
|
)
|
||||||
|
|
121
plugins/mprisremote/albumart_cache.cpp
Normal file
121
plugins/mprisremote/albumart_cache.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
|
||||||
|
#include "albumart_cache.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QReadLocker>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include "filetransferjob.h"
|
||||||
|
#include "kjob.h"
|
||||||
|
#include "mprisremoteplugin.h"
|
||||||
|
#include "plugin_mprisremote_debug.h"
|
||||||
|
|
||||||
|
// TODO: Not sure where to put such utils
|
||||||
|
constexpr std::size_t operator""_MB(unsigned long long v)
|
||||||
|
{
|
||||||
|
return 1024u * 1024u * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr qsizetype CACHE_SIZE = 5_MB;
|
||||||
|
|
||||||
|
AlbumArtCache::AlbumArtCache()
|
||||||
|
{
|
||||||
|
m_cachedFiles.setMaxCost(CACHE_SIZE);
|
||||||
|
m_cacheDir = QDir{QStandardPaths::writableLocation(QStandardPaths::CacheLocation).append(QStringLiteral("/kdeconnect/albumart"))};
|
||||||
|
if (!m_cacheDir.exists()) {
|
||||||
|
m_cacheDir.mkpath(QStringLiteral("."));
|
||||||
|
} else {
|
||||||
|
// clear the directory
|
||||||
|
// TODO: Better thing to do would be to re-populate the m_cachedFiles
|
||||||
|
qDebug() << "Clearing existing entries" << m_cacheDir.entryList(QDir::Files).size();
|
||||||
|
for (auto &file : m_cacheDir.entryList(QDir::Files)) {
|
||||||
|
m_cacheDir.remove(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumArtCache::~AlbumArtCache() = default;
|
||||||
|
|
||||||
|
AlbumArtCache *AlbumArtCache::instance()
|
||||||
|
{
|
||||||
|
static auto *s_albumArtCache = new AlbumArtCache();
|
||||||
|
|
||||||
|
return s_albumArtCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumArtCache::IndexItem AlbumArtCache::getAlbumArt(const QString &remoteUrl, MprisRemotePlugin *plugin, const QString &player)
|
||||||
|
{
|
||||||
|
if (remoteUrl.isEmpty()) {
|
||||||
|
// Can't fetch an empty remoteUrl. Do we want to add a separate status for this?
|
||||||
|
return IndexItem{IndexItem::FAILED};
|
||||||
|
}
|
||||||
|
QReadLocker locker{&instance()->m_cacheLock};
|
||||||
|
IndexItem *item = instance()->m_cachedFiles.object(remoteUrl);
|
||||||
|
if (item != nullptr) {
|
||||||
|
if (item->fetchStatus == IndexItem::SUCCESS) {
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_MPRISREMOTE) << "album art already present" << remoteUrl << "at" << item->file->localPath;
|
||||||
|
if (!item->file->localPath.isLocalFile()) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_MPRISREMOTE) << "No file for cached art!" << item->file->localPath;
|
||||||
|
return IndexItem{IndexItem::FAILED};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *item;
|
||||||
|
} else {
|
||||||
|
// TODO: First check if we are already fetching it
|
||||||
|
|
||||||
|
// fetch the album art from plugin
|
||||||
|
plugin->requestAlbumArt(player, remoteUrl);
|
||||||
|
return IndexItem{IndexItem::FETCHING};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlbumArtCache::handleAlbumArt(const NetworkPacket &np)
|
||||||
|
{
|
||||||
|
auto remoteUrl = np.get<QString>(QStringLiteral("albumArtUrl"));
|
||||||
|
if (np.payloadSize() > CACHE_SIZE) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_MPRISREMOTE) << "Art is too big! Ignoring.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (remoteUrl.isEmpty()) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_MPRISREMOTE) << "No url with art";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto player = np.get<QString>(QStringLiteral("player"));
|
||||||
|
// TODO: Track in-flight requests and reject if not present
|
||||||
|
{
|
||||||
|
QReadLocker locker{&instance()->m_cacheLock};
|
||||||
|
auto *entry = m_cachedFiles.object(remoteUrl);
|
||||||
|
if (entry != nullptr) {
|
||||||
|
if (entry->fetchStatus == IndexItem::SUCCESS) {
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_MPRISREMOTE) << "Cache hit" << entry->file->localPath.fileName() << "for" << remoteUrl;
|
||||||
|
Q_EMIT albumArtFetched(player, remoteUrl, entry->file);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// fetch again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: better local file path
|
||||||
|
auto filename = QStringLiteral("%1.jpg").arg(qHash(remoteUrl));
|
||||||
|
auto localUrl = QUrl::fromLocalFile(m_cacheDir.filePath(filename));
|
||||||
|
auto *job = np.createPayloadTransferJob(localUrl);
|
||||||
|
connect(job, &FileTransferJob::result, this, [this, job, remoteUrl, localUrl, player]() {
|
||||||
|
if (job->error()) {
|
||||||
|
// TODO: Handle error, retry?
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_MPRISREMOTE) << "art transfer error" << remoteUrl << "to" << localUrl << job->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto fileSize = static_cast<qsizetype>(job->totalAmount(KJob::Unit::Bytes));
|
||||||
|
qCInfo(KDECONNECT_PLUGIN_MPRISREMOTE) << "Finished art transfer! from" << remoteUrl << "to" << localUrl << "size" << fileSize;
|
||||||
|
auto *indexItem = new IndexItem{localUrl};
|
||||||
|
auto localPath = indexItem->file;
|
||||||
|
QWriteLocker locker{&instance()->m_cacheLock};
|
||||||
|
m_cachedFiles.insert(remoteUrl, indexItem, fileSize);
|
||||||
|
if (!QFile{localUrl.toLocalFile()}.exists()) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_MPRISREMOTE) << "File doesn't exist" << localUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Q_EMIT albumArtFetched(player, remoteUrl, localPath);
|
||||||
|
});
|
||||||
|
job->start();
|
||||||
|
}
|
99
plugins/mprisremote/albumart_cache.h
Normal file
99
plugins/mprisremote/albumart_cache.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2023 Krut Patel <kroot.patel@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ALBUMARTCACHE_H
|
||||||
|
#define ALBUMARTCACHE_H
|
||||||
|
|
||||||
|
#include "networkpacket.h"
|
||||||
|
#include <QCache>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QReadWriteLock>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class MprisRemotePlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper that automatically deletes the file from disk when destroyed.
|
||||||
|
*/
|
||||||
|
class LocalFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QUrl localPath;
|
||||||
|
explicit LocalFile(QUrl localPath)
|
||||||
|
: localPath(std::move(localPath))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~LocalFile()
|
||||||
|
{
|
||||||
|
// delete the file from disk
|
||||||
|
// TODO: Log warning if this failed
|
||||||
|
QFile::remove(localPath.toLocalFile());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlbumArtCache : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
AlbumArtCache();
|
||||||
|
|
||||||
|
~AlbumArtCache() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct IndexItem {
|
||||||
|
enum Status {
|
||||||
|
FETCHING,
|
||||||
|
SUCCESS,
|
||||||
|
FAILED,
|
||||||
|
};
|
||||||
|
Status fetchStatus;
|
||||||
|
QSharedPointer<LocalFile> file;
|
||||||
|
|
||||||
|
explicit IndexItem(QUrl localPath)
|
||||||
|
: fetchStatus(Status::SUCCESS)
|
||||||
|
, file(new LocalFile{std::move(localPath)})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
explicit IndexItem(Status fetchStatus)
|
||||||
|
: fetchStatus(fetchStatus)
|
||||||
|
, file(nullptr)
|
||||||
|
{
|
||||||
|
// Need localPath in this case
|
||||||
|
Q_ASSERT(fetchStatus != Status::SUCCESS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static AlbumArtCache *instance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Album Art object. Called from mpris media player to be sent to dbus.
|
||||||
|
*
|
||||||
|
* @return IndexItem Current status of the art file.
|
||||||
|
*/
|
||||||
|
static IndexItem getAlbumArt(const QString &remoteUrl, MprisRemotePlugin *plugin, const QString &player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for when plugin receives a packet with album art.
|
||||||
|
* Can't use slot since NetworkPacket isn't a registered type.
|
||||||
|
*/
|
||||||
|
void handleAlbumArt(const NetworkPacket &np);
|
||||||
|
|
||||||
|
// called by handleAlbumArt when the album art is fetched and stored to disk
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
void albumArtFetched(const QString &player, const QString &remoteUrl, QSharedPointer<LocalFile> localPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Index = QCache<QString, IndexItem>;
|
||||||
|
QDir m_cacheDir;
|
||||||
|
Index m_cachedFiles;
|
||||||
|
QReadWriteLock m_cacheLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ALBUMARTCACHE_H
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mprisremoteplayer.h"
|
#include "mprisremoteplayer.h"
|
||||||
|
#include "albumart_cache.h"
|
||||||
#include "mprisremoteplayermediaplayer2.h"
|
#include "mprisremoteplayermediaplayer2.h"
|
||||||
#include "mprisremoteplayermediaplayer2player.h"
|
#include "mprisremoteplayermediaplayer2player.h"
|
||||||
#include "mprisremoteplugin.h"
|
#include "mprisremoteplugin.h"
|
||||||
|
@ -14,6 +15,8 @@
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <networkpacket.h>
|
#include <networkpacket.h>
|
||||||
|
|
||||||
|
#include "plugin_mprisremote_debug.h"
|
||||||
|
|
||||||
MprisRemotePlayer::MprisRemotePlayer(QString id, MprisRemotePlugin *plugin)
|
MprisRemotePlayer::MprisRemotePlayer(QString id, MprisRemotePlugin *plugin)
|
||||||
: QObject(plugin)
|
: QObject(plugin)
|
||||||
, id(id)
|
, id(id)
|
||||||
|
@ -33,6 +36,7 @@ MprisRemotePlayer::MprisRemotePlayer(QString id, MprisRemotePlugin *plugin)
|
||||||
, m_dbusConnectionName(QStringLiteral("mpris_") + QUuid::createUuid().toString(QUuid::Id128))
|
, m_dbusConnectionName(QStringLiteral("mpris_") + QUuid::createUuid().toString(QUuid::Id128))
|
||||||
, m_dbusConnection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_dbusConnectionName))
|
, m_dbusConnection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_dbusConnectionName))
|
||||||
{
|
{
|
||||||
|
connect(AlbumArtCache::instance(), &AlbumArtCache::albumArtFetched, this, &MprisRemotePlayer::albumArtFetched);
|
||||||
// Expose this player on the newly created connection. This allows multiple mpris services in the same Qt process
|
// Expose this player on the newly created connection. This allows multiple mpris services in the same Qt process
|
||||||
new MprisRemotePlayerMediaPlayer2(this, plugin);
|
new MprisRemotePlayerMediaPlayer2(this, plugin);
|
||||||
new MprisRemotePlayerMediaPlayer2Player(this, plugin);
|
new MprisRemotePlayerMediaPlayer2Player(this, plugin);
|
||||||
|
@ -56,7 +60,17 @@ void MprisRemotePlayer::parseNetworkPacket(const NetworkPacket &np)
|
||||||
QString newTitle = np.get<QString>(QStringLiteral("title"), m_title);
|
QString newTitle = np.get<QString>(QStringLiteral("title"), m_title);
|
||||||
QString newArtist = np.get<QString>(QStringLiteral("artist"), m_artist);
|
QString newArtist = np.get<QString>(QStringLiteral("artist"), m_artist);
|
||||||
QString newAlbum = np.get<QString>(QStringLiteral("album"), m_album);
|
QString newAlbum = np.get<QString>(QStringLiteral("album"), m_album);
|
||||||
|
QString newAlbumArtUrl = np.get<QString>(QStringLiteral("albumArtUrl"), QStringLiteral(""));
|
||||||
int newLength = np.get<int>(QStringLiteral("length"), m_length);
|
int newLength = np.get<int>(QStringLiteral("length"), m_length);
|
||||||
|
if (newAlbumArtUrl != m_albumArtUrl) {
|
||||||
|
// album art changed
|
||||||
|
m_albumArtUrl = newAlbumArtUrl;
|
||||||
|
auto url = AlbumArtCache::getAlbumArt(newAlbumArtUrl, (MprisRemotePlugin *)(parent()), identity());
|
||||||
|
// if empty, will be populated once album art has been fetched
|
||||||
|
if (url.fetchStatus != AlbumArtCache::IndexItem::FETCHING) {
|
||||||
|
setLocalAlbumArtUrl(url.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if they changed
|
// Check if they changed
|
||||||
if (newTitle != m_title || newArtist != m_artist || newAlbum != m_album || newLength != m_length) {
|
if (newTitle != m_title || newArtist != m_artist || newAlbum != m_album || newLength != m_length) {
|
||||||
|
@ -126,6 +140,13 @@ void MprisRemotePlayer::setPosition(long position)
|
||||||
m_lastPositionTime = QDateTime::currentMSecsSinceEpoch();
|
m_lastPositionTime = QDateTime::currentMSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MprisRemotePlayer::setLocalAlbumArtUrl(const QSharedPointer<LocalFile> &url)
|
||||||
|
{
|
||||||
|
m_localAlbumArtUrl = url;
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_MPRISREMOTE) << "Setting local url" << (url ? url->localPath.toDisplayString() : QStringLiteral("(null)"));
|
||||||
|
Q_EMIT trackInfoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
int MprisRemotePlayer::volume() const
|
int MprisRemotePlayer::volume() const
|
||||||
{
|
{
|
||||||
return m_volume;
|
return m_volume;
|
||||||
|
@ -191,4 +212,32 @@ QDBusConnection &MprisRemotePlayer::dbus()
|
||||||
return m_dbusConnection;
|
return m_dbusConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString MprisRemotePlayer::albumArtUrl() const
|
||||||
|
{
|
||||||
|
return m_albumArtUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl MprisRemotePlayer::localAlbumArtUrl() const
|
||||||
|
{
|
||||||
|
return m_localAlbumArtUrl ? m_localAlbumArtUrl->localPath : QUrl{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisRemotePlayer::albumArtFetched(const QString &player, const QString &remoteUrl, const QSharedPointer<LocalFile> &localPath)
|
||||||
|
{
|
||||||
|
if (identity() != player) {
|
||||||
|
// doesn't concern us
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (albumArtUrl() != remoteUrl) {
|
||||||
|
// doesn't concern us
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Q_ASSERT(localPath);
|
||||||
|
if (localAlbumArtUrl() == localPath->localPath) {
|
||||||
|
// already set
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLocalAlbumArtUrl(localPath);
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_mprisremoteplayer.cpp"
|
#include "moc_mprisremoteplayer.cpp"
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "albumart_cache.h"
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
class NetworkPacket;
|
class NetworkPacket;
|
||||||
class MprisRemotePlugin;
|
class MprisRemotePlugin;
|
||||||
|
@ -22,12 +24,15 @@ public:
|
||||||
void parseNetworkPacket(const NetworkPacket &np);
|
void parseNetworkPacket(const NetworkPacket &np);
|
||||||
long position() const;
|
long position() const;
|
||||||
void setPosition(long position);
|
void setPosition(long position);
|
||||||
|
void setLocalAlbumArtUrl(const QSharedPointer<LocalFile> &url);
|
||||||
int volume() const;
|
int volume() const;
|
||||||
long length() const;
|
long length() const;
|
||||||
bool playing() const;
|
bool playing() const;
|
||||||
QString title() const;
|
QString title() const;
|
||||||
QString artist() const;
|
QString artist() const;
|
||||||
QString album() const;
|
QString album() const;
|
||||||
|
QString albumArtUrl() const;
|
||||||
|
QUrl localAlbumArtUrl() const;
|
||||||
QString identity() const;
|
QString identity() const;
|
||||||
|
|
||||||
bool canSeek() const;
|
bool canSeek() const;
|
||||||
|
@ -45,6 +50,9 @@ Q_SIGNALS:
|
||||||
void volumeChanged();
|
void volumeChanged();
|
||||||
void playingChanged();
|
void playingChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void albumArtFetched(const QString &player, const QString &remoteUrl, const QSharedPointer<LocalFile> &localPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString id;
|
QString id;
|
||||||
bool m_playing;
|
bool m_playing;
|
||||||
|
@ -59,6 +67,11 @@ private:
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_artist;
|
QString m_artist;
|
||||||
QString m_album;
|
QString m_album;
|
||||||
|
QString m_albumArtUrl;
|
||||||
|
// hold a strong reference so that the file doesn't get deleted while in use
|
||||||
|
QSharedPointer<LocalFile> m_localAlbumArtUrl;
|
||||||
|
|
||||||
|
private:
|
||||||
bool m_canSeek;
|
bool m_canSeek;
|
||||||
|
|
||||||
// Use an unique connection for every player, otherwise we can't distinguish which mpris player is being controlled
|
// Use an unique connection for every player, otherwise we can't distinguish which mpris player is being controlled
|
||||||
|
|
|
@ -58,6 +58,9 @@ QVariantMap MprisRemotePlayerMediaPlayer2Player::Metadata() const
|
||||||
if (!m_parent->album().isEmpty()) {
|
if (!m_parent->album().isEmpty()) {
|
||||||
metadata[QStringLiteral("xesam:album")] = m_parent->album();
|
metadata[QStringLiteral("xesam:album")] = m_parent->album();
|
||||||
}
|
}
|
||||||
|
if (!m_parent->localAlbumArtUrl().isEmpty()) {
|
||||||
|
metadata[QStringLiteral("mpris:artUrl")] = m_parent->localAlbumArtUrl().toString();
|
||||||
|
}
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
#include <KPluginFactory>
|
#include <KPluginFactory>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include <core/device.h>
|
#include <core/device.h>
|
||||||
|
#include <filetransferjob.h>
|
||||||
|
|
||||||
|
#include "albumart_cache.h"
|
||||||
#include "plugin_mprisremote_debug.h"
|
#include "plugin_mprisremote_debug.h"
|
||||||
|
|
||||||
K_PLUGIN_CLASS_WITH_JSON(MprisRemotePlugin, "kdeconnect_mprisremote.json")
|
K_PLUGIN_CLASS_WITH_JSON(MprisRemotePlugin, "kdeconnect_mprisremote.json")
|
||||||
|
@ -21,6 +24,11 @@ void MprisRemotePlugin::receivePacket(const NetworkPacket &np)
|
||||||
if (np.type() != PACKET_TYPE_MPRIS)
|
if (np.type() != PACKET_TYPE_MPRIS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (np.get<bool>(QStringLiteral("transferringAlbumArt"), false)) {
|
||||||
|
AlbumArtCache::instance()->handleAlbumArt(np);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (np.has(QStringLiteral("player"))) {
|
if (np.has(QStringLiteral("player"))) {
|
||||||
const QString player = np.get<QString>(QStringLiteral("player"));
|
const QString player = np.get<QString>(QStringLiteral("player"));
|
||||||
if (!m_players.contains(player)) {
|
if (!m_players.contains(player)) {
|
||||||
|
@ -83,6 +91,13 @@ void MprisRemotePlugin::requestPlayerList()
|
||||||
sendPacket(np);
|
sendPacket(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MprisRemotePlugin::requestAlbumArt(const QString &player, const QString &album_art_url)
|
||||||
|
{
|
||||||
|
NetworkPacket np(PACKET_TYPE_MPRIS_REQUEST, {{QStringLiteral("player"), player}, {QStringLiteral("albumArtUrl"), album_art_url}});
|
||||||
|
qInfo(KDECONNECT_PLUGIN_MPRISREMOTE) << "Requesting album art " << np.serialize();
|
||||||
|
sendPacket(np);
|
||||||
|
}
|
||||||
|
|
||||||
void MprisRemotePlugin::sendAction(const QString &action)
|
void MprisRemotePlugin::sendAction(const QString &action)
|
||||||
{
|
{
|
||||||
NetworkPacket np(PACKET_TYPE_MPRIS_REQUEST, {{QStringLiteral("player"), m_currentPlayer}, {QStringLiteral("action"), action}});
|
NetworkPacket np(PACKET_TYPE_MPRIS_REQUEST, {{QStringLiteral("player"), m_currentPlayer}, {QStringLiteral("action"), action}});
|
||||||
|
|
|
@ -54,6 +54,8 @@ public:
|
||||||
Q_SCRIPTABLE void seek(int offset) const;
|
Q_SCRIPTABLE void seek(int offset) const;
|
||||||
Q_SCRIPTABLE void requestPlayerList();
|
Q_SCRIPTABLE void requestPlayerList();
|
||||||
Q_SCRIPTABLE void sendAction(const QString &action);
|
Q_SCRIPTABLE void sendAction(const QString &action);
|
||||||
|
// we don't want this to be exposed via dbus, right?
|
||||||
|
void requestAlbumArt(const QString &player, const QString &album_art_url);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void propertiesChanged();
|
Q_SCRIPTABLE void propertiesChanged();
|
||||||
|
|
Loading…
Reference in a new issue