Skip to content

Commit d1a1727

Browse files
committed
service/mpris: hack around more non-compliant players
Mpris is currently winning the competition for least compliant clients.
1 parent 1eabf5b commit d1a1727

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/services/mpris/player.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "player.hpp"
22

3+
#include <qtimer.h>
34
#include <qcontainerfwd.h>
45
#include <qdatetime.h>
56
#include <qdbusconnection.h>
@@ -317,11 +318,24 @@ void MprisPlayer::onMetadataChanged() {
317318
}
318319
}
319320

321+
// Some players (Jellyfin) specify xesam:url or mpris:trackid
322+
// and DON'T ACTUALLY CHANGE THEM WHEN THE TRACK CHANGES.
323+
auto titleVariant = this->bpMetadata.value().value("xesam:title");
324+
if (titleVariant.isValid() && titleVariant.canConvert<QString>()) {
325+
auto title = titleVariant.toString();
326+
327+
if (title != this->mTrackTitle) {
328+
this->mTrackTitle = title;
329+
trackChanged = true;
330+
}
331+
}
332+
320333
Qt::beginPropertyUpdateGroup();
321334

322335
if (trackChanged) {
323336
emit this->trackChanged();
324337
this->bUniqueId = this->bUniqueId + 1;
338+
this->trackChangedBeforeState = true;
325339

326340
// Some players don't seem to send position updates or seeks on track change.
327341
this->pPosition.requestUpdate();
@@ -386,6 +400,23 @@ void MprisPlayer::setPlaying(bool playing) {
386400
this->togglePlaying();
387401
}
388402

403+
void MprisPlayer::onPlaybackStatusUpdated() {
404+
// Insurance - have not yet seen a player where this particular check is required that doesn't
405+
// require the late query below.
406+
this->pPosition.requestUpdate();
407+
408+
// For exceptionally bad players that update playback timestamps at an indeterminate time AFTER
409+
// updating playback state. (Youtube)
410+
QTimer::singleShot(100, this, [&]() { this->pPosition.requestUpdate(); });
411+
412+
// For exceptionally bad players that don't update length (or other metadata) until a new track actually
413+
// starts playing, and then don't trigger a metadata update when they do. (Jellyfin)
414+
if (this->trackChangedBeforeState) {
415+
this->trackChangedBeforeState = false;
416+
this->pMetadata.requestUpdate();
417+
}
418+
}
419+
389420
bool MprisPlayer::loopSupported() const { return this->pLoopStatus.exists(); }
390421

391422
void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {

src/services/mpris/player.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ class MprisPlayer: public QObject {
242242
/// Equivalent to calling @@play() if not playing or @@pause() if playing.
243243
///
244244
/// May only be called if @@canTogglePlaying is true, which is equivalent to
245-
/// @@canPlay or @@canPause() depending on the current playback state.
245+
/// @@canPlay or @@canPause depending on the current playback state.
246246
Q_INVOKABLE void togglePlaying();
247247

248248
[[nodiscard]] bool isValid() const;
@@ -391,6 +391,7 @@ private slots:
391391
private:
392392
void onMetadataChanged();
393393
void onPositionUpdated();
394+
void onPlaybackStatusUpdated();
394395
// call instead of setting bpPosition
395396
void setPosition(qlonglong position);
396397
void requestPositionUpdate() { this->pPosition.requestUpdate(); };
@@ -462,7 +463,7 @@ private slots:
462463
QS_DBUS_PROPERTY_BINDING(MprisPlayer, qlonglong, pPosition, bpPosition, onPositionUpdated, playerProperties, "Position", false);
463464
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pVolume, bVolume, playerProperties, "Volume", false);
464465
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMetadata, bpMetadata, playerProperties, "Metadata");
465-
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPlaybackStatus, bpPlaybackStatus, playerProperties, "PlaybackStatus");
466+
QS_DBUS_PROPERTY_BINDING(MprisPlayer, void, pPlaybackStatus, bpPlaybackStatus, onPlaybackStatusUpdated, playerProperties, "PlaybackStatus", true);
466467
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pLoopStatus, bpLoopStatus, playerProperties, "LoopStatus", false);
467468
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pRate, bRate, playerProperties, "Rate", false);
468469
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMinRate, bMinRate, playerProperties, "MinimumRate", false);
@@ -477,6 +478,8 @@ private slots:
477478
DBusMprisPlayer* player = nullptr;
478479
QString mTrackId;
479480
QString mTrackUrl;
481+
QString mTrackTitle;
482+
bool trackChangedBeforeState = false;
480483
};
481484

482485
} // namespace qs::service::mpris

0 commit comments

Comments
 (0)