1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-02 19:48:27 -04:00

refactor(mpris): consolidate equivalent-player resolution & update track matching

Port 1.5

(cherry picked from commit 19d919ed5c)
This commit is contained in:
purian23
2026-08-02 18:09:18 -04:00
committed by dms-ci[bot]
parent 6edb985847
commit 52afbc9801
3 changed files with 31 additions and 23 deletions
+4 -3
View File
@@ -156,9 +156,10 @@ DankOSD {
if (MprisController.isFirefoxYoutubeHoverPreview(player))
return;
const newTitle = player.trackTitle || "";
const newArtist = player.trackArtist || "";
const newAlbum = player.trackAlbum || "";
const metaPlayer = MprisController.bestMetadataPlayer(player);
const newTitle = MprisController.displayTrackTitle(metaPlayer);
const newArtist = metaPlayer.trackArtist || "";
const newAlbum = metaPlayer.trackAlbum || "";
const trackChanged = newTitle !== root._displayTitle || newArtist !== root._displayArtist || newAlbum !== root._displayAlbum;
root._displayTitle = newTitle;
+24 -13
View File
@@ -93,7 +93,7 @@ Singleton {
}
if (isFirefoxYoutubeHoverPreview(p))
return;
const metadataPlayer = _bestMetadataPlayer(p);
const metadataPlayer = bestMetadataPlayer(p);
const nextTitle = displayTrackTitle(metadataPlayer);
const trackChanged = nextTitle && stableTitle && nextTitle.toLowerCase() !== stableTitle.toLowerCase();
if (trackChanged) {
@@ -171,8 +171,7 @@ Singleton {
return player && player.playbackState === MprisPlaybackState.Stopped && !player.trackTitle && !player.trackArtist;
}
// App-name suffixes that browsers/integrations append as "<title> | <App>".
// Only these are stripped for track matching; display always keeps the full title.
// Known "<title> | <App>" suffixes stripped for matching only; display keeps the full title
readonly property var _appTitleSuffixes: ["youtube", "youtube music", "soundcloud", "spotify", "chrome", "chromium", "firefox", "brave", "vivaldi", "twitch"]
function _stripAppTitleSuffix(title: string): string {
@@ -183,12 +182,10 @@ Singleton {
return _appTitleSuffixes.indexOf(suffix) !== -1 ? title.substring(0, idx).trim() : title;
}
// Matching key: strip only known app suffixes so equivalent players line up.
function normalizedTrackTitle(player: MprisPlayer): string {
return _stripAppTitleSuffix((player?.trackTitle || "").trim()).toLowerCase();
}
// Display: never strip — a generic " | " cut would mangle legitimate titles.
function displayTrackTitle(player: MprisPlayer): string {
return (player?.trackTitle || "").trim();
}
@@ -197,14 +194,24 @@ Singleton {
return (player?.trackArtist || "").trim().toLowerCase();
}
// Artist missing on either side: fall back to URL, then album, before trusting a title-only match
function isSameTrack(first: MprisPlayer, second: MprisPlayer): bool {
const firstTitle = normalizedTrackTitle(first);
const secondTitle = normalizedTrackTitle(second);
if (!firstTitle || firstTitle !== secondTitle)
if (!firstTitle || firstTitle !== normalizedTrackTitle(second))
return false;
const firstArtist = normalizedTrackArtist(first);
const secondArtist = normalizedTrackArtist(second);
return !firstArtist || !secondArtist || firstArtist === secondArtist;
if (firstArtist && secondArtist)
return firstArtist === secondArtist;
const firstUrl = (first?.metadata?.["xesam:url"] || "").toString();
const secondUrl = (second?.metadata?.["xesam:url"] || "").toString();
if (firstUrl && secondUrl)
return firstUrl === secondUrl;
const firstAlbum = (first?.trackAlbum || "").trim().toLowerCase();
const secondAlbum = (second?.trackAlbum || "").trim().toLowerCase();
if (firstAlbum && secondAlbum)
return firstAlbum === secondAlbum;
return true;
}
function metadataQuality(player: MprisPlayer): int {
@@ -218,10 +225,16 @@ Singleton {
return quality;
}
function _bestMetadataPlayer(player: MprisPlayer): MprisPlayer {
const equivalents = availablePlayers.filter(candidate => {
function equivalentPlayers(player: MprisPlayer): var {
if (!player)
return [];
return availablePlayers.filter(candidate => {
return candidate.playbackState !== MprisPlaybackState.Stopped && isSameTrack(player, candidate);
});
}
function bestMetadataPlayer(player: MprisPlayer): MprisPlayer {
const equivalents = equivalentPlayers(player);
if (equivalents.length === 0)
return player;
return equivalents.reduce((best, candidate) => {
@@ -238,9 +251,7 @@ Singleton {
if (activePlayer?.isPlaying) {
if (activePlayer.canControl || controllable.length === 0)
return activePlayer;
// Active source is playing but not controllable: only hand ownership to a
// controllable *equivalent* peer (same track). Never let an unrelated
// player steal the active source while it is still playing.
// Playing but not controllable: only a same-track controllable peer may take over
const mirror = controllable.find(player => isSameTrack(activePlayer, player));
return mirror || activePlayer;
}
+3 -7
View File
@@ -59,11 +59,8 @@ Singleton {
if (directUrl !== "")
return directUrl;
const equivalent = MprisController.availablePlayers.find(candidate => {
return candidate !== player
&& candidate.playbackState !== MprisPlaybackState.Stopped
&& MprisController.isSameTrack(player, candidate)
&& _directArtworkUrl(candidate) !== "";
const equivalent = MprisController.equivalentPlayers(player).find(candidate => {
return candidate !== player && _directArtworkUrl(candidate) !== "";
});
return _directArtworkUrl(equivalent);
}
@@ -229,8 +226,7 @@ Singleton {
}
_pendingArtKey = key;
const url = getArtworkUrl(activePlayer);
// Ignore duplicate notifications, but allow a richer peer to replace
// the artwork for the same canonical track.
// Ignore duplicate notifications, but let a richer peer replace same-track art
if (key !== "" && key === _committedArtKey && url === _committedSrcUrl)
return;
if (key !== "" && url !== "" && url === _committedSrcUrl) {