service/mpris: add properties for common track metadata
This was done to work around bad player implementations sending weird metadata, such as removing the art url halfway through a song.
This commit is contained in:
parent
c56a3ec966
commit
8cfebb3baf
|
@ -1,4 +1,5 @@
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qdatetime.h>
|
#include <qdatetime.h>
|
||||||
|
@ -255,6 +256,11 @@ void MprisPlayer::setVolume(qreal volume) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap MprisPlayer::metadata() const { return this->pMetadata.get(); }
|
QVariantMap MprisPlayer::metadata() const { return this->pMetadata.get(); }
|
||||||
|
QString MprisPlayer::trackTitle() const { return this->mTrackTitle; }
|
||||||
|
QString MprisPlayer::trackAlbum() const { return this->mTrackAlbum; }
|
||||||
|
QString MprisPlayer::trackAlbumArtist() const { return this->mTrackAlbumArtist; }
|
||||||
|
QVector<QString> MprisPlayer::trackArtists() const { return this->mTrackArtists; }
|
||||||
|
QString MprisPlayer::trackArtUrl() const { return this->mTrackArtUrl; }
|
||||||
|
|
||||||
void MprisPlayer::onMetadataChanged() {
|
void MprisPlayer::onMetadataChanged() {
|
||||||
emit this->metadataChanged();
|
emit this->metadataChanged();
|
||||||
|
@ -274,7 +280,7 @@ void MprisPlayer::onMetadataChanged() {
|
||||||
|
|
||||||
auto trackidVariant = this->pMetadata.get().value("mpris:trackid");
|
auto trackidVariant = this->pMetadata.get().value("mpris:trackid");
|
||||||
if (trackidVariant.isValid() && trackidVariant.canConvert<QString>()) {
|
if (trackidVariant.isValid() && trackidVariant.canConvert<QString>()) {
|
||||||
auto trackId = trackidVariant.value<QString>();
|
auto trackId = trackidVariant.toString();
|
||||||
|
|
||||||
if (trackId != this->mTrackId) {
|
if (trackId != this->mTrackId) {
|
||||||
this->mTrackId = trackId;
|
this->mTrackId = trackId;
|
||||||
|
@ -285,14 +291,49 @@ void MprisPlayer::onMetadataChanged() {
|
||||||
// Helps to catch players without trackid.
|
// Helps to catch players without trackid.
|
||||||
auto urlVariant = this->pMetadata.get().value("xesam:url");
|
auto urlVariant = this->pMetadata.get().value("xesam:url");
|
||||||
if (urlVariant.isValid() && urlVariant.canConvert<QString>()) {
|
if (urlVariant.isValid() && urlVariant.canConvert<QString>()) {
|
||||||
auto url = urlVariant.value<QString>();
|
auto url = urlVariant.toString();
|
||||||
|
|
||||||
if (url != this->mUrl) {
|
if (url != this->mTrackUrl) {
|
||||||
this->mUrl = url;
|
this->mTrackUrl = url;
|
||||||
trackChanged = true;
|
trackChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto trackTitle = this->pMetadata.get().value("xesam:title");
|
||||||
|
if (trackTitle.isValid() && trackTitle.canConvert<QString>()) {
|
||||||
|
this->setTrackTitle(trackTitle.toString());
|
||||||
|
} else if (trackChanged) {
|
||||||
|
this->setTrackTitle("Unknown Track");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto trackAlbum = this->pMetadata.get().value("xesam:album");
|
||||||
|
if (trackAlbum.isValid() && trackAlbum.canConvert<QString>()) {
|
||||||
|
this->setTrackAlbum(trackAlbum.toString());
|
||||||
|
} else if (trackChanged) {
|
||||||
|
this->setTrackAlbum("Unknown Album");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto trackAlbumArtist = this->pMetadata.get().value("xesam:albumArtist");
|
||||||
|
if (trackAlbumArtist.isValid() && trackAlbumArtist.canConvert<QString>()) {
|
||||||
|
this->setTrackAlbumArtist(trackAlbumArtist.toString());
|
||||||
|
} else if (trackChanged) {
|
||||||
|
this->setTrackAlbumArtist("Unknown Artist");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto trackArtists = this->pMetadata.get().value("xesam:artist");
|
||||||
|
if (trackArtists.isValid() && trackArtists.canConvert<QVector<QString>>()) {
|
||||||
|
this->setTrackArtists(trackArtists.value<QVector<QString>>());
|
||||||
|
} else if (trackChanged) {
|
||||||
|
this->setTrackArtists({});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto trackArtUrl = this->pMetadata.get().value("mpris:artUrl");
|
||||||
|
if (trackArtUrl.isValid() && trackArtUrl.canConvert<QString>()) {
|
||||||
|
this->setTrackArtUrl(trackArtUrl.toString());
|
||||||
|
} else if (trackChanged) {
|
||||||
|
this->setTrackArtUrl("");
|
||||||
|
}
|
||||||
|
|
||||||
if (trackChanged) {
|
if (trackChanged) {
|
||||||
// Some players don't seem to send position updates or seeks on track change.
|
// Some players don't seem to send position updates or seeks on track change.
|
||||||
this->pPosition.update();
|
this->pPosition.update();
|
||||||
|
@ -300,6 +341,41 @@ void MprisPlayer::onMetadataChanged() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MprisPlayer::setTrackTitle(QString title) {
|
||||||
|
if (title == this->mTrackTitle) return;
|
||||||
|
|
||||||
|
this->mTrackTitle = std::move(title);
|
||||||
|
emit this->trackTitleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisPlayer::setTrackAlbum(QString album) {
|
||||||
|
if (album == this->mTrackAlbum) return;
|
||||||
|
|
||||||
|
this->mTrackAlbum = std::move(album);
|
||||||
|
emit this->trackAlbumChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisPlayer::setTrackAlbumArtist(QString albumArtist) {
|
||||||
|
if (albumArtist == this->mTrackAlbumArtist) return;
|
||||||
|
|
||||||
|
this->mTrackAlbumArtist = std::move(albumArtist);
|
||||||
|
emit this->trackAlbumArtistChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisPlayer::setTrackArtists(QVector<QString> artists) {
|
||||||
|
if (artists == this->mTrackArtists) return;
|
||||||
|
|
||||||
|
this->mTrackArtists = std::move(artists);
|
||||||
|
emit this->trackArtistsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MprisPlayer::setTrackArtUrl(QString artUrl) {
|
||||||
|
if (artUrl == this->mTrackArtUrl) return;
|
||||||
|
|
||||||
|
this->mTrackArtUrl = std::move(artUrl);
|
||||||
|
emit this->trackArtUrlChanged();
|
||||||
|
}
|
||||||
|
|
||||||
MprisPlaybackState::Enum MprisPlayer::playbackState() const { return this->mPlaybackState; }
|
MprisPlaybackState::Enum MprisPlayer::playbackState() const { return this->mPlaybackState; }
|
||||||
|
|
||||||
void MprisPlayer::setPlaybackState(MprisPlaybackState::Enum playbackState) {
|
void MprisPlayer::setPlaybackState(MprisPlaybackState::Enum playbackState) {
|
||||||
|
|
|
@ -122,7 +122,21 @@ class MprisPlayer: public QObject {
|
||||||
///
|
///
|
||||||
/// A map of common properties is available [here](https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata).
|
/// A map of common properties is available [here](https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata).
|
||||||
/// Do not count on any of them actually being present.
|
/// Do not count on any of them actually being present.
|
||||||
|
///
|
||||||
|
/// Note that the `trackTitle`, `trackAlbum`, `trackAlbumArtist`, `trackArtists` and `trackArtUrl`
|
||||||
|
/// properties have extra logic to guard against bad players sending weird metadata, and should
|
||||||
|
/// be used over grabbing the properties directly from the metadata.
|
||||||
Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged);
|
Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged);
|
||||||
|
/// The title of the current track, or "Unknown Track" if none was provided.
|
||||||
|
Q_PROPERTY(QString trackTitle READ trackTitle NOTIFY trackTitleChanged);
|
||||||
|
/// The current track's album, or "Unknown Album" if none was provided.
|
||||||
|
Q_PROPERTY(QString trackAlbum READ trackAlbum NOTIFY trackAlbumChanged);
|
||||||
|
/// The current track's album artist, or "Unknown Artist" if none was provided.
|
||||||
|
Q_PROPERTY(QString trackAlbumArtist READ trackAlbumArtist NOTIFY trackAlbumArtistChanged);
|
||||||
|
/// The current track's album artist, or "Unknown Artist" if none was provided.
|
||||||
|
Q_PROPERTY(QVector<QString> trackArtists READ trackArtists NOTIFY trackArtistsChanged);
|
||||||
|
/// The current track's artists, or an empty list if none were provided.
|
||||||
|
Q_PROPERTY(QString trackArtUrl READ trackArtUrl NOTIFY trackArtUrlChanged);
|
||||||
/// The playback state of the media player.
|
/// The playback state of the media player.
|
||||||
///
|
///
|
||||||
/// - If `canPlay` is false, you cannot assign the `Playing` state.
|
/// - If `canPlay` is false, you cannot assign the `Playing` state.
|
||||||
|
@ -234,6 +248,11 @@ public:
|
||||||
void setVolume(qreal volume);
|
void setVolume(qreal volume);
|
||||||
|
|
||||||
[[nodiscard]] QVariantMap metadata() const;
|
[[nodiscard]] QVariantMap metadata() const;
|
||||||
|
[[nodiscard]] QString trackTitle() const;
|
||||||
|
[[nodiscard]] QString trackAlbum() const;
|
||||||
|
[[nodiscard]] QString trackAlbumArtist() const;
|
||||||
|
[[nodiscard]] QVector<QString> trackArtists() const;
|
||||||
|
[[nodiscard]] QString trackArtUrl() const;
|
||||||
|
|
||||||
[[nodiscard]] MprisPlaybackState::Enum playbackState() const;
|
[[nodiscard]] MprisPlaybackState::Enum playbackState() const;
|
||||||
void setPlaybackState(MprisPlaybackState::Enum playbackState);
|
void setPlaybackState(MprisPlaybackState::Enum playbackState);
|
||||||
|
@ -280,6 +299,11 @@ signals:
|
||||||
void volumeChanged();
|
void volumeChanged();
|
||||||
void volumeSupportedChanged();
|
void volumeSupportedChanged();
|
||||||
void metadataChanged();
|
void metadataChanged();
|
||||||
|
void trackTitleChanged();
|
||||||
|
void trackAlbumChanged();
|
||||||
|
void trackAlbumArtistChanged();
|
||||||
|
void trackArtistsChanged();
|
||||||
|
void trackArtUrlChanged();
|
||||||
void playbackStateChanged();
|
void playbackStateChanged();
|
||||||
void loopStateChanged();
|
void loopStateChanged();
|
||||||
void loopSupportedChanged();
|
void loopSupportedChanged();
|
||||||
|
@ -302,6 +326,12 @@ private slots:
|
||||||
void onLoopStatusChanged();
|
void onLoopStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setTrackTitle(QString title);
|
||||||
|
void setTrackAlbum(QString album);
|
||||||
|
void setTrackAlbumArtist(QString albumArtist);
|
||||||
|
void setTrackArtists(QVector<QString> artists);
|
||||||
|
void setTrackArtUrl(QString artUrl);
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
dbus::DBusPropertyGroup appProperties;
|
dbus::DBusPropertyGroup appProperties;
|
||||||
dbus::DBusProperty<QString> pIdentity {this->appProperties, "Identity"};
|
dbus::DBusProperty<QString> pIdentity {this->appProperties, "Identity"};
|
||||||
|
@ -340,7 +370,12 @@ private:
|
||||||
DBusMprisPlayerApp* app = nullptr;
|
DBusMprisPlayerApp* app = nullptr;
|
||||||
DBusMprisPlayer* player = nullptr;
|
DBusMprisPlayer* player = nullptr;
|
||||||
QString mTrackId;
|
QString mTrackId;
|
||||||
QString mUrl;
|
QString mTrackUrl;
|
||||||
|
QString mTrackTitle;
|
||||||
|
QString mTrackAlbum;
|
||||||
|
QString mTrackAlbumArtist;
|
||||||
|
QVector<QString> mTrackArtists;
|
||||||
|
QString mTrackArtUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace qs::service::mpris
|
} // namespace qs::service::mpris
|
||||||
|
|
Loading…
Reference in a new issue