forked from quickshell/quickshell
		
	service/mpris: hack around more non-compliant players
Mpris is currently winning the competition for least compliant clients.
This commit is contained in:
		
							parent
							
								
									1eabf5b3c3
								
							
						
					
					
						commit
						d1a172751d
					
				
					 2 changed files with 36 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include "player.hpp"
 | 
			
		||||
 | 
			
		||||
#include <qtimer.h>
 | 
			
		||||
#include <qcontainerfwd.h>
 | 
			
		||||
#include <qdatetime.h>
 | 
			
		||||
#include <qdbusconnection.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -317,11 +318,24 @@ void MprisPlayer::onMetadataChanged() {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Some players (Jellyfin) specify xesam:url or mpris:trackid
 | 
			
		||||
	// and DON'T ACTUALLY CHANGE THEM WHEN THE TRACK CHANGES.
 | 
			
		||||
	auto titleVariant = this->bpMetadata.value().value("xesam:title");
 | 
			
		||||
	if (titleVariant.isValid() && titleVariant.canConvert<QString>()) {
 | 
			
		||||
		auto title = titleVariant.toString();
 | 
			
		||||
 | 
			
		||||
		if (title != this->mTrackTitle) {
 | 
			
		||||
			this->mTrackTitle = title;
 | 
			
		||||
			trackChanged = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Qt::beginPropertyUpdateGroup();
 | 
			
		||||
 | 
			
		||||
	if (trackChanged) {
 | 
			
		||||
		emit this->trackChanged();
 | 
			
		||||
		this->bUniqueId = this->bUniqueId + 1;
 | 
			
		||||
		this->trackChangedBeforeState = true;
 | 
			
		||||
 | 
			
		||||
		// Some players don't seem to send position updates or seeks on track change.
 | 
			
		||||
		this->pPosition.requestUpdate();
 | 
			
		||||
| 
						 | 
				
			
			@ -386,6 +400,23 @@ void MprisPlayer::setPlaying(bool playing) {
 | 
			
		|||
	this->togglePlaying();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MprisPlayer::onPlaybackStatusUpdated() {
 | 
			
		||||
	// Insurance - have not yet seen a player where this particular check is required that doesn't
 | 
			
		||||
	// require the late query below.
 | 
			
		||||
	this->pPosition.requestUpdate();
 | 
			
		||||
 | 
			
		||||
	// For exceptionally bad players that update playback timestamps at an indeterminate time AFTER
 | 
			
		||||
	// updating playback state. (Youtube)
 | 
			
		||||
	QTimer::singleShot(100, this, [&]() { this->pPosition.requestUpdate(); });
 | 
			
		||||
 | 
			
		||||
	// For exceptionally bad players that don't update length (or other metadata) until a new track actually
 | 
			
		||||
	// starts playing, and then don't trigger a metadata update when they do. (Jellyfin)
 | 
			
		||||
	if (this->trackChangedBeforeState) {
 | 
			
		||||
		this->trackChangedBeforeState = false;
 | 
			
		||||
		this->pMetadata.requestUpdate();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MprisPlayer::loopSupported() const { return this->pLoopStatus.exists(); }
 | 
			
		||||
 | 
			
		||||
void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -242,7 +242,7 @@ public:
 | 
			
		|||
	/// Equivalent to calling @@play() if not playing or @@pause() if playing.
 | 
			
		||||
	///
 | 
			
		||||
	/// May only be called if @@canTogglePlaying is true, which is equivalent to
 | 
			
		||||
	/// @@canPlay or @@canPause() depending on the current playback state.
 | 
			
		||||
	/// @@canPlay or @@canPause depending on the current playback state.
 | 
			
		||||
	Q_INVOKABLE void togglePlaying();
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool isValid() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -391,6 +391,7 @@ private slots:
 | 
			
		|||
private:
 | 
			
		||||
	void onMetadataChanged();
 | 
			
		||||
	void onPositionUpdated();
 | 
			
		||||
	void onPlaybackStatusUpdated();
 | 
			
		||||
	// call instead of setting bpPosition
 | 
			
		||||
	void setPosition(qlonglong position);
 | 
			
		||||
	void requestPositionUpdate() { this->pPosition.requestUpdate(); };
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +463,7 @@ private:
 | 
			
		|||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, qlonglong, pPosition, bpPosition, onPositionUpdated, playerProperties, "Position", false);
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pVolume, bVolume, playerProperties, "Volume", false);
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMetadata, bpMetadata, playerProperties, "Metadata");
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPlaybackStatus, bpPlaybackStatus, playerProperties, "PlaybackStatus");
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, void, pPlaybackStatus, bpPlaybackStatus, onPlaybackStatusUpdated, playerProperties, "PlaybackStatus", true);
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pLoopStatus, bpLoopStatus, playerProperties, "LoopStatus", false);
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pRate, bRate, playerProperties, "Rate", false);
 | 
			
		||||
	QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMinRate, bMinRate, playerProperties, "MinimumRate", false);
 | 
			
		||||
| 
						 | 
				
			
			@ -477,6 +478,8 @@ private:
 | 
			
		|||
	DBusMprisPlayer* player = nullptr;
 | 
			
		||||
	QString mTrackId;
 | 
			
		||||
	QString mTrackUrl;
 | 
			
		||||
	QString mTrackTitle;
 | 
			
		||||
	bool trackChangedBeforeState = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace qs::service::mpris
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue