Skip to content

Commit e6a37b9

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 e6a37b9

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

src/services/mpris/player.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,24 @@ void MprisPlayer::onMetadataChanged() {
317317
}
318318
}
319319

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

322334
if (trackChanged) {
323335
emit this->trackChanged();
324336
this->bUniqueId = this->bUniqueId + 1;
337+
this->trackChangedBeforeState = true;
325338

326339
// Some players don't seem to send position updates or seeks on track change.
327340
this->pPosition.requestUpdate();
@@ -386,6 +399,25 @@ void MprisPlayer::setPlaying(bool playing) {
386399
this->togglePlaying();
387400
}
388401

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

391423
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)