2018-04-27 23:22:45 +01:00
|
|
|
/**
|
2020-08-17 10:48:10 +01:00
|
|
|
* SPDX-FileCopyrightText: 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
2018-04-27 23:22:45 +01:00
|
|
|
*
|
2020-08-17 10:48:10 +01:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
2018-04-27 23:22:45 +01:00
|
|
|
*/
|
|
|
|
|
2019-02-03 00:44:22 +00:00
|
|
|
#include "mprisremoteplayer.h"
|
2024-07-31 17:39:28 +01:00
|
|
|
#include "albumart_cache.h"
|
2019-07-25 22:40:58 +01:00
|
|
|
#include "mprisremoteplayermediaplayer2.h"
|
|
|
|
#include "mprisremoteplayermediaplayer2player.h"
|
2022-09-10 22:23:52 +01:00
|
|
|
#include "mprisremoteplugin.h"
|
2019-02-03 00:44:22 +00:00
|
|
|
|
2018-04-27 23:22:45 +01:00
|
|
|
#include <QDateTime>
|
|
|
|
|
2019-07-25 22:40:58 +01:00
|
|
|
#include <QUuid>
|
2022-09-10 22:23:52 +01:00
|
|
|
#include <networkpacket.h>
|
2018-04-27 23:22:45 +01:00
|
|
|
|
2024-07-31 17:39:28 +01:00
|
|
|
#include "plugin_mprisremote_debug.h"
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
MprisRemotePlayer::MprisRemotePlayer(QString id, MprisRemotePlugin *plugin)
|
|
|
|
: QObject(plugin)
|
2019-07-25 22:40:58 +01:00
|
|
|
, id(id)
|
|
|
|
, m_playing(false)
|
2019-07-19 21:08:56 +01:00
|
|
|
, m_canPlay(true)
|
|
|
|
, m_canPause(true)
|
|
|
|
, m_canGoPrevious(true)
|
|
|
|
, m_canGoNext(true)
|
2018-04-27 23:22:45 +01:00
|
|
|
, m_volume(50)
|
|
|
|
, m_length(0)
|
|
|
|
, m_lastPosition(0)
|
|
|
|
, m_lastPositionTime()
|
|
|
|
, m_title()
|
|
|
|
, m_artist()
|
|
|
|
, m_album()
|
2019-07-17 22:19:53 +01:00
|
|
|
, m_canSeek(false)
|
2019-07-25 22:40:58 +01:00
|
|
|
, m_dbusConnectionName(QStringLiteral("mpris_") + QUuid::createUuid().toString(QUuid::Id128))
|
|
|
|
, m_dbusConnection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_dbusConnectionName))
|
2018-04-27 23:22:45 +01:00
|
|
|
{
|
2024-07-31 17:39:28 +01:00
|
|
|
connect(AlbumArtCache::instance(), &AlbumArtCache::albumArtFetched, this, &MprisRemotePlayer::albumArtFetched);
|
2022-09-10 22:23:52 +01:00
|
|
|
// Expose this player on the newly created connection. This allows multiple mpris services in the same Qt process
|
2019-07-25 22:40:58 +01:00
|
|
|
new MprisRemotePlayerMediaPlayer2(this, plugin);
|
|
|
|
new MprisRemotePlayerMediaPlayer2Player(this, plugin);
|
|
|
|
|
|
|
|
m_dbusConnection.registerObject(QStringLiteral("/org/mpris/MediaPlayer2"), this);
|
2022-09-10 22:23:52 +01:00
|
|
|
// Make sure our service name is unique. Reuse the connection name for this.
|
2019-07-25 22:40:58 +01:00
|
|
|
m_dbusConnection.registerService(QStringLiteral("org.mpris.MediaPlayer2.kdeconnect.") + m_dbusConnectionName);
|
2018-04-27 23:22:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MprisRemotePlayer::~MprisRemotePlayer()
|
|
|
|
{
|
2022-09-10 22:23:52 +01:00
|
|
|
// Drop the DBus connection (it was only used for this class)
|
2019-07-25 22:40:58 +01:00
|
|
|
QDBusConnection::disconnectFromBus(m_dbusConnectionName);
|
2018-04-27 23:22:45 +01:00
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
void MprisRemotePlayer::parseNetworkPacket(const NetworkPacket &np)
|
2018-04-27 23:22:45 +01:00
|
|
|
{
|
2019-07-25 22:40:58 +01:00
|
|
|
bool trackInfoHasChanged = false;
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
// Track properties
|
2019-07-25 22:40:58 +01:00
|
|
|
QString newTitle = np.get<QString>(QStringLiteral("title"), m_title);
|
|
|
|
QString newArtist = np.get<QString>(QStringLiteral("artist"), m_artist);
|
|
|
|
QString newAlbum = np.get<QString>(QStringLiteral("album"), m_album);
|
2024-07-31 17:39:28 +01:00
|
|
|
QString newAlbumArtUrl = np.get<QString>(QStringLiteral("albumArtUrl"), QStringLiteral(""));
|
2019-07-25 22:40:58 +01:00
|
|
|
int newLength = np.get<int>(QStringLiteral("length"), m_length);
|
2024-07-31 17:39:28 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2019-07-25 22:40:58 +01:00
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
// Check if they changed
|
2023-06-07 19:20:21 +01:00
|
|
|
if (newTitle != m_title || newArtist != m_artist || newAlbum != m_album || newLength != m_length) {
|
2019-07-25 22:40:58 +01:00
|
|
|
trackInfoHasChanged = true;
|
2023-06-07 19:20:21 +01:00
|
|
|
m_title = newTitle;
|
|
|
|
m_artist = newArtist;
|
|
|
|
m_album = newAlbum;
|
|
|
|
m_length = newLength;
|
2019-07-25 22:40:58 +01:00
|
|
|
Q_EMIT trackInfoChanged();
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
// Check volume changes
|
2019-07-25 22:40:58 +01:00
|
|
|
int newVolume = np.get<int>(QStringLiteral("volume"), m_volume);
|
|
|
|
if (newVolume != m_volume) {
|
2023-06-07 19:20:21 +01:00
|
|
|
m_volume = newVolume;
|
2019-07-25 22:40:58 +01:00
|
|
|
Q_EMIT volumeChanged();
|
|
|
|
}
|
|
|
|
|
2019-07-19 21:08:56 +01:00
|
|
|
if (np.has(QStringLiteral("pos"))) {
|
2022-09-10 22:23:52 +01:00
|
|
|
// Check position
|
2019-07-25 22:40:58 +01:00
|
|
|
int newLastPosition = np.get<int>(QStringLiteral("pos"), m_lastPosition);
|
|
|
|
int positionDiff = qAbs(position() - newLastPosition);
|
|
|
|
m_lastPosition = newLastPosition;
|
2018-04-27 23:22:45 +01:00
|
|
|
m_lastPositionTime = QDateTime::currentMSecsSinceEpoch();
|
2019-07-25 22:40:58 +01:00
|
|
|
|
2023-06-07 19:20:21 +01:00
|
|
|
// Only consider it seeking if the position changed more than 1 second or the track has changed
|
|
|
|
if (qAbs(positionDiff) >= 1000 || trackInfoHasChanged) {
|
2019-07-25 22:40:58 +01:00
|
|
|
Q_EMIT positionChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
// Check if we started/stopped playing
|
2019-07-25 22:40:58 +01:00
|
|
|
bool newPlaying = np.get<bool>(QStringLiteral("isPlaying"), m_playing);
|
|
|
|
if (newPlaying != m_playing) {
|
2023-06-07 19:20:21 +01:00
|
|
|
m_playing = newPlaying;
|
2019-07-25 22:40:58 +01:00
|
|
|
Q_EMIT playingChanged();
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
// Control properties
|
2019-07-25 22:40:58 +01:00
|
|
|
bool newCanSeek = np.get<bool>(QStringLiteral("canSeek"), m_canSeek);
|
|
|
|
bool newCanPlay = np.get<bool>(QStringLiteral("canPlay"), m_canPlay);
|
|
|
|
bool newCanPause = np.get<bool>(QStringLiteral("canPause"), m_canPause);
|
|
|
|
bool newCanGoPrevious = np.get<bool>(QStringLiteral("canGoPrevious"), m_canGoPrevious);
|
|
|
|
bool newCanGoNext = np.get<bool>(QStringLiteral("canGoNext"), m_canGoNext);
|
|
|
|
if (newCanSeek != m_canSeek || newCanPlay != m_canPlay || newCanPause != m_canPause || newCanGoPrevious != m_canGoPrevious || newCanGoNext != m_canGoNext) {
|
2023-06-07 19:20:21 +01:00
|
|
|
m_canSeek = newCanSeek;
|
|
|
|
m_canPlay = newCanPlay;
|
|
|
|
m_canPause = newCanPause;
|
|
|
|
m_canGoPrevious = newCanGoPrevious;
|
|
|
|
m_canGoNext = newCanGoNext;
|
2019-07-25 22:40:58 +01:00
|
|
|
Q_EMIT controlsChanged();
|
2018-04-27 23:22:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long MprisRemotePlayer::position() const
|
|
|
|
{
|
2022-09-10 22:23:52 +01:00
|
|
|
if (m_playing) {
|
2018-04-27 23:22:45 +01:00
|
|
|
return m_lastPosition + (QDateTime::currentMSecsSinceEpoch() - m_lastPositionTime);
|
|
|
|
} else {
|
|
|
|
return m_lastPosition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MprisRemotePlayer::setPosition(long position)
|
|
|
|
{
|
|
|
|
m_lastPosition = position;
|
|
|
|
m_lastPositionTime = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
}
|
|
|
|
|
2024-07-31 17:39:28 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-04-27 23:22:45 +01:00
|
|
|
int MprisRemotePlayer::volume() const
|
|
|
|
{
|
|
|
|
return m_volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
long int MprisRemotePlayer::length() const
|
|
|
|
{
|
|
|
|
return m_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MprisRemotePlayer::playing() const
|
|
|
|
{
|
|
|
|
return m_playing;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString MprisRemotePlayer::title() const
|
|
|
|
{
|
|
|
|
return m_title;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString MprisRemotePlayer::artist() const
|
|
|
|
{
|
|
|
|
return m_artist;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString MprisRemotePlayer::album() const
|
|
|
|
{
|
|
|
|
return m_album;
|
|
|
|
}
|
2019-07-17 22:19:53 +01:00
|
|
|
|
|
|
|
bool MprisRemotePlayer::canSeek() const
|
|
|
|
{
|
|
|
|
return m_canSeek;
|
|
|
|
}
|
2019-07-19 21:08:56 +01:00
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
QString MprisRemotePlayer::identity() const
|
|
|
|
{
|
2019-07-25 22:40:58 +01:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
bool MprisRemotePlayer::canPlay() const
|
|
|
|
{
|
2019-07-19 21:08:56 +01:00
|
|
|
return m_canPlay;
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
bool MprisRemotePlayer::canPause() const
|
|
|
|
{
|
2019-07-19 21:08:56 +01:00
|
|
|
return m_canPause;
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
bool MprisRemotePlayer::canGoPrevious() const
|
|
|
|
{
|
2019-07-19 21:08:56 +01:00
|
|
|
return m_canGoPrevious;
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
bool MprisRemotePlayer::canGoNext() const
|
|
|
|
{
|
2019-07-19 21:08:56 +01:00
|
|
|
return m_canGoNext;
|
|
|
|
}
|
2019-07-25 22:40:58 +01:00
|
|
|
|
2022-09-10 22:23:52 +01:00
|
|
|
QDBusConnection &MprisRemotePlayer::dbus()
|
|
|
|
{
|
2019-07-25 22:40:58 +01:00
|
|
|
return m_dbusConnection;
|
|
|
|
}
|
2023-07-26 09:15:11 +01:00
|
|
|
|
2024-07-31 17:39:28 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-07-26 09:15:11 +01:00
|
|
|
#include "moc_mprisremoteplayer.cpp"
|