spotify-player: run a daemon; fix progress bar; add progress+volume to media card
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2652d14a8f
commit
82de631064
2 changed files with 144 additions and 1 deletions
|
|
@ -6159,6 +6159,14 @@ in
|
|||
};
|
||||
add(player.identity);
|
||||
add(player.desktopEntry);
|
||||
// The bus name's last segment is the app's own token —
|
||||
// spotify-player advertises identity "Spotify Player"
|
||||
// but its Pipewire stream is "spotify_player", and the
|
||||
// space/underscore mismatch defeats substring matching,
|
||||
// so the card never found its stream and the volume row
|
||||
// stayed hidden. Only the last segment: everything
|
||||
// before it is the shared org.mpris.MediaPlayer2 prefix.
|
||||
add((player.dbusName || "").split(".").pop());
|
||||
|
||||
let ns = Pipewire.nodes.values;
|
||||
for (let i = 0; i < ns.length; i++) {
|
||||
|
|
@ -6182,6 +6190,11 @@ in
|
|||
return null;
|
||||
}
|
||||
|
||||
function fmtTime(s) {
|
||||
if (!isFinite(s) || s < 0) s = 0;
|
||||
return Math.floor(s / 60) + ":" + ("0" + Math.floor(s % 60)).slice(-2);
|
||||
}
|
||||
|
||||
// Live spectrum for the media cards' rings. cava runs only
|
||||
// while this popup is open AND something is playing, so it
|
||||
// isn't capturing audio in the background. levels is a
|
||||
|
|
@ -6699,6 +6712,63 @@ in
|
|||
}
|
||||
}
|
||||
|
||||
// Track progress. MPRIS only pushes a
|
||||
// position on seek or track change, so
|
||||
// `position` would sit frozen between
|
||||
// them; re-emitting positionChanged
|
||||
// makes bindings re-read it against the
|
||||
// clock. Ticking only while the popup is
|
||||
// open and the track is playing keeps it
|
||||
// off the CPU the rest of the time.
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 8
|
||||
visible: mediaCard.modelData.lengthSupported
|
||||
&& mediaCard.modelData.length > 0
|
||||
|
||||
Timer {
|
||||
running: calPopup.open
|
||||
&& mediaCard.modelData.playbackState === MprisPlaybackState.Playing
|
||||
interval: 1000
|
||||
repeat: true
|
||||
onTriggered: mediaCard.modelData.positionChanged()
|
||||
}
|
||||
|
||||
SText {
|
||||
id: mediaPosLabel
|
||||
width: 32
|
||||
text: calPopup.fmtTime(mediaCard.modelData.position)
|
||||
color: Theme.base04
|
||||
font.pixelSize: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
PillSlider {
|
||||
width: parent.width - mediaPosLabel.width - mediaLenLabel.width - 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 16
|
||||
trackH: 4
|
||||
value: mediaCard.modelData.length > 0
|
||||
? Math.min(1, mediaCard.modelData.position / mediaCard.modelData.length)
|
||||
: 0
|
||||
fillColor: Theme.base05
|
||||
onMoved: (v) => {
|
||||
let p = mediaCard.modelData;
|
||||
if (p && p.canSeek && p.length > 0) p.position = v * p.length;
|
||||
}
|
||||
}
|
||||
|
||||
SText {
|
||||
id: mediaLenLabel
|
||||
width: 32
|
||||
text: calPopup.fmtTime(mediaCard.modelData.length)
|
||||
color: Theme.base04
|
||||
font.pixelSize: 10
|
||||
horizontalAlignment: Text.AlignRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Per-source volume — same per-app path
|
||||
// as the volume widget. Shown when the
|
||||
// player's Pipewire stream is matched.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue