Skip to content

Commit b9c5698

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 b9c5698

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/services/mpris/player.cpp

Lines changed: 30 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,23 @@ 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, [&]() { this->pPosition.requestUpdate(); });
410+
411+
// For exceptionally bad players that don't update length (or other metadata) until a new track actually
412+
// starts playing, and then don't trigger a metadata update when they do. (Jellyfin)
413+
if (this->trackChangedBeforeState) {
414+
this->trackChangedBeforeState = false;
415+
this->pMetadata.requestUpdate();
416+
}
417+
}
418+
389419
bool MprisPlayer::loopSupported() const { return this->pLoopStatus.exists(); }
390420

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