forked from quickshell/quickshell
		
	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
						d8fa9e7bb3
					
				
					 2 changed files with 116 additions and 5 deletions
				
			
		| 
						 | 
					@ -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 artists, or an empty list if none were provided.
 | 
				
			||||||
 | 
						Q_PROPERTY(QVector<QString> trackArtists READ trackArtists NOTIFY trackArtistsChanged);
 | 
				
			||||||
 | 
						/// The current track's art url, or `""` if none was 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue