Skip to content

Commit fce1a09

Browse files
bbedwarddms-ci[bot]
authored andcommitted
osd/media playback: delay showing until album art is ready and avoid
re-showing when duplicate metadata comes from mpris related #2787 port 1.5 (cherry picked from commit 6a58adf)
1 parent 554e55c commit fce1a09

3 files changed

Lines changed: 77 additions & 23 deletions

File tree

quickshell/Modules/OSD/MediaPlaybackOSD.qml

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ DankOSD {
2323
if (!player) {
2424
_displayIcon = "music_note";
2525
iconDebounce.stop();
26-
return;
26+
return false;
2727
}
2828
let icon = "music_note";
2929
switch (player.playbackState) {
@@ -35,10 +35,13 @@ DankOSD {
3535
icon = "play_arrow";
3636
break;
3737
}
38-
if (icon === _displayIcon)
39-
return;
38+
if (icon === _displayIcon) {
39+
iconDebounce.stop();
40+
return false;
41+
}
4042
iconDebounce.pendingIcon = icon;
4143
iconDebounce.restart();
44+
return true;
4245
}
4346

4447
function togglePlaying() {
@@ -52,13 +55,47 @@ DankOSD {
5255
property string _displayArtist: ""
5356
property string _displayAlbum: ""
5457

58+
function _showPending() {
59+
_pendingShow = false;
60+
pendingShowFallback.stop();
61+
show();
62+
}
63+
64+
function _evaluateShow() {
65+
// art url can land in a later metadata update than the title
66+
if (TrackArtService.getArtworkUrl(player) === "") {
67+
_pendingShow = true;
68+
pendingShowFallback.interval = 600;
69+
pendingShowFallback.restart();
70+
return;
71+
}
72+
if (TrackArtService.artReadyFor(player) && artPreloader.status === Image.Ready) {
73+
_showPending();
74+
return;
75+
}
76+
_pendingShow = true;
77+
pendingShowFallback.interval = 1500;
78+
pendingShowFallback.restart();
79+
}
80+
5581
Timer {
5682
id: iconDebounce
5783
interval: 150
5884
property string pendingIcon: "music_note"
5985
onTriggered: root._displayIcon = pendingIcon
6086
}
6187

88+
Timer {
89+
id: pendingShowFallback
90+
interval: 1500
91+
onTriggered: {
92+
if (!root._pendingShow)
93+
return;
94+
root._pendingShow = false;
95+
root.show();
96+
}
97+
}
98+
6299
Image {
63100
id: artPreloader
64101
source: TrackArtService.resolvedArtUrl
@@ -70,19 +107,27 @@ DankOSD {
70107
onPlayerChanged: {
71108
if (!player) {
72109
_pendingShow = false;
110+
pendingShowFallback.stop();
73111
hide();
74112
}
75113
}
76114

77115
Connections {
78116
target: TrackArtService
79117
function onLoadingChanged() {
80-
if (TrackArtService.loading || !root._pendingShow)
118+
if (!root._pendingShow)
119+
return;
120+
if (TrackArtService.loading) {
121+
pendingShowFallback.interval = 1500;
122+
pendingShowFallback.restart();
123+
return;
124+
}
125+
if (!TrackArtService.resolvedArtUrl) {
126+
root._showPending();
81127
return;
82-
if (!TrackArtService.resolvedArtUrl || artPreloader.status === Image.Ready) {
83-
root._pendingShow = false;
84-
root.show();
85128
}
129+
if (TrackArtService.artReadyFor(root.player) && artPreloader.status === Image.Ready)
130+
root._showPending();
86131
}
87132
}
88133

@@ -94,8 +139,7 @@ DankOSD {
94139
switch (artPreloader.status) {
95140
case Image.Ready:
96141
case Image.Error:
97-
root._pendingShow = false;
98-
root.show();
142+
root._showPending();
99143
break;
100144
}
101145
}
@@ -112,26 +156,32 @@ DankOSD {
112156
if (MprisController.isFirefoxYoutubeHoverPreview(player))
113157
return;
114158

115-
root._displayTitle = player.trackTitle || "";
116-
root._displayArtist = player.trackArtist || "";
117-
root._displayAlbum = player.trackAlbum || "";
159+
const newTitle = player.trackTitle || "";
160+
const newArtist = player.trackArtist || "";
161+
const newAlbum = player.trackAlbum || "";
162+
const trackChanged = newTitle !== root._displayTitle || newArtist !== root._displayArtist || newAlbum !== root._displayAlbum;
163+
164+
root._displayTitle = newTitle;
165+
root._displayArtist = newArtist;
166+
root._displayAlbum = newAlbum;
118167

119-
root.updatePlaybackIcon();
120-
const resolvedArtUrl = TrackArtService.resolvedArtUrl;
168+
const iconChanged = root.updatePlaybackIcon();
169+
170+
// live streams re-emit metadata as mpris:length grows - ignore churn
171+
if (!trackChanged && !iconChanged)
172+
return;
121173

122-
if (!resolvedArtUrl || resolvedArtUrl === "") {
174+
// vertical layout has no art background
175+
if (root.useVertical) {
123176
root.show();
124177
return;
125178
}
126-
if (TrackArtService.loading) {
127-
root._pendingShow = true;
179+
if (trackChanged) {
180+
root._evaluateShow();
128181
return;
129182
}
130-
if (!TrackArtService.resolvedArtUrl || artPreloader.status === Image.Ready) {
183+
if (!root._pendingShow)
131184
root.show();
132-
return;
133-
}
134-
root._pendingShow = true;
135185
}
136186

137187
function onTrackArtUrlChanged() {

quickshell/Modules/OSD/MicVolumeOSD.qml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ DankOSD {
2323
Connections {
2424
target: AudioService.source?.audio ?? null
2525

26-
// Sync only - apps adjusting mic gain (WebRTC AGC etc.) fire this
27-
// constantly, so external volume changes must not surface the OSD
26+
// sync only - app AGC rewrites mic gain constantly, must not surface the OSD
2827
function onVolumeChanged() {
2928
root._syncVolume();
3029
}

quickshell/Services/TrackArtService.qml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ Singleton {
191191
return (p.trackTitle || "") + "" + (p.trackArtist || "") + "" + (p.trackAlbum || "");
192192
}
193193

194+
function artReadyFor(player) {
195+
const url = getArtworkUrl(player);
196+
return url !== "" && url === _lastArtUrl && !loading && resolvedArtUrl !== "";
197+
}
198+
194199
function _updateArtUrl() {
195200
const key = _trackKey();
196201
// Skip once real art is committed for this track (dedup Chrome's multi-size

0 commit comments

Comments
 (0)