mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
refactor: unify media control calls to MprisController sync
This commit is contained in:
@@ -531,9 +531,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function next(): void {
|
function next(): void {
|
||||||
if (MprisController.activePlayer && MprisController.activePlayer.canGoNext) {
|
MprisController.next();
|
||||||
MprisController.activePlayer.next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop(): void {
|
function stop(): void {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ BasePill {
|
|||||||
if (deltaY > 0) {
|
if (deltaY > 0) {
|
||||||
MprisController.previousOrRewind();
|
MprisController.previousOrRewind();
|
||||||
} else {
|
} else {
|
||||||
activePlayer.next();
|
MprisController.next();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scrollAccumulatorY += deltaY;
|
scrollAccumulatorY += deltaY;
|
||||||
@@ -137,7 +137,7 @@ BasePill {
|
|||||||
if (scrollAccumulatorY > 0) {
|
if (scrollAccumulatorY > 0) {
|
||||||
MprisController.previousOrRewind();
|
MprisController.previousOrRewind();
|
||||||
} else {
|
} else {
|
||||||
activePlayer.next();
|
MprisController.next();
|
||||||
}
|
}
|
||||||
scrollAccumulatorY = 0;
|
scrollAccumulatorY = 0;
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ BasePill {
|
|||||||
} else if (mouse.button === Qt.MiddleButton) {
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
MprisController.previousOrRewind();
|
MprisController.previousOrRewind();
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
activePlayer.next();
|
MprisController.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,7 +532,7 @@ BasePill {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (activePlayer) {
|
if (activePlayer) {
|
||||||
activePlayer.next();
|
MprisController.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -662,11 +662,12 @@ Item {
|
|||||||
weight: 500
|
weight: 500
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
StateLayer {
|
||||||
anchors.fill: parent
|
id: playPauseArea
|
||||||
hoverEnabled: true
|
disabled: !root.activePlayer || !root.activePlayer.canTogglePlaying
|
||||||
cursorShape: Qt.PointingHandCursor
|
stateColor: root.onAccent
|
||||||
onClicked: activePlayer && activePlayer.togglePlaying()
|
cornerRadius: parent.radius
|
||||||
|
onClicked: root.activePlayer.togglePlaying()
|
||||||
}
|
}
|
||||||
|
|
||||||
ElevationShadow {
|
ElevationShadow {
|
||||||
@@ -706,7 +707,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: activePlayer && activePlayer.next()
|
onClicked: MprisController.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ Card {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: activePlayer?.next()
|
onClicked: MprisController.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1635,7 +1635,7 @@ Item {
|
|||||||
enabled: MprisController.activePlayer?.canGoNext ?? false
|
enabled: MprisController.activePlayer?.canGoNext ?? false
|
||||||
hoverEnabled: enabled
|
hoverEnabled: enabled
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
onClicked: MprisController.activePlayer?.next()
|
onClicked: MprisController.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,22 +48,12 @@ Singleton {
|
|||||||
target: root.activePlayer
|
target: root.activePlayer
|
||||||
function onTrackTitleChanged() {
|
function onTrackTitleChanged() {
|
||||||
root.activePlayerStableLength = (root.activePlayer && root.activePlayer.lengthSupported && root.activePlayer.length > 1) ? root.activePlayer.length : 0;
|
root.activePlayerStableLength = (root.activePlayer && root.activePlayer.lengthSupported && root.activePlayer.length > 1) ? root.activePlayer.length : 0;
|
||||||
if (root.isIdle(root.activePlayer))
|
|
||||||
root._resolveActivePlayer();
|
|
||||||
}
|
|
||||||
function onTrackArtistChanged() {
|
|
||||||
if (root.isIdle(root.activePlayer))
|
|
||||||
root._resolveActivePlayer();
|
|
||||||
}
|
}
|
||||||
function onLengthChanged() {
|
function onLengthChanged() {
|
||||||
if (root.activePlayer && root.activePlayer.lengthSupported && root.activePlayer.length > 1) {
|
if (root.activePlayer && root.activePlayer.lengthSupported && root.activePlayer.length > 1) {
|
||||||
root.activePlayerStableLength = root.activePlayer.length;
|
root.activePlayerStableLength = root.activePlayer.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onPlaybackStateChanged() {
|
|
||||||
if (root.isIdle(root.activePlayer))
|
|
||||||
root._resolveActivePlayer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivePlayerChanged: {
|
onActivePlayerChanged: {
|
||||||
@@ -73,18 +63,6 @@ Singleton {
|
|||||||
onAvailablePlayersChanged: _resolveActivePlayer()
|
onAvailablePlayersChanged: _resolveActivePlayer()
|
||||||
Component.onCompleted: _resolveActivePlayer()
|
Component.onCompleted: _resolveActivePlayer()
|
||||||
|
|
||||||
Instantiator {
|
|
||||||
model: root.availablePlayers
|
|
||||||
delegate: Connections {
|
|
||||||
required property MprisPlayer modelData
|
|
||||||
target: modelData
|
|
||||||
function onIsPlayingChanged() {
|
|
||||||
if (modelData.isPlaying)
|
|
||||||
root._resolveActivePlayer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isIdle(player: MprisPlayer): bool {
|
function isIdle(player: MprisPlayer): bool {
|
||||||
return player
|
return player
|
||||||
&& player.playbackState === MprisPlaybackState.Stopped
|
&& player.playbackState === MprisPlaybackState.Stopped
|
||||||
@@ -93,14 +71,15 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _resolveActivePlayer(): void {
|
function _resolveActivePlayer(): void {
|
||||||
|
// Keep the selected player stable across transient metadata changes.
|
||||||
|
if (activePlayer && availablePlayers.indexOf(activePlayer) >= 0)
|
||||||
|
return;
|
||||||
const playing = availablePlayers.find(p => p.isPlaying);
|
const playing = availablePlayers.find(p => p.isPlaying);
|
||||||
if (playing) {
|
if (playing) {
|
||||||
activePlayer = playing;
|
activePlayer = playing;
|
||||||
_persistIdentity(playing.identity);
|
_persistIdentity(playing.identity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (activePlayer && availablePlayers.indexOf(activePlayer) >= 0 && !isIdle(activePlayer))
|
|
||||||
return;
|
|
||||||
const savedId = SessionData.lastPlayerIdentity;
|
const savedId = SessionData.lastPlayerIdentity;
|
||||||
if (savedId) {
|
if (savedId) {
|
||||||
const match = availablePlayers.find(p => p.identity === savedId);
|
const match = availablePlayers.find(p => p.identity === savedId);
|
||||||
@@ -150,4 +129,10 @@ Singleton {
|
|||||||
else if (activePlayer.canGoPrevious)
|
else if (activePlayer.canGoPrevious)
|
||||||
activePlayer.previous();
|
activePlayer.previous();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function next(): void {
|
||||||
|
const player = activePlayer;
|
||||||
|
if (player?.canGoNext)
|
||||||
|
player.next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ Singleton {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function _commit(u) {
|
function _commit(u, artKey, srcUrl) {
|
||||||
resolvedArtUrl = u;
|
resolvedArtUrl = u;
|
||||||
_committedArtKey = u !== "" ? _pendingArtKey : "";
|
_committedArtKey = u !== "" ? artKey : "";
|
||||||
_committedSrcUrl = u !== "" ? _lastArtUrl : "";
|
_committedSrcUrl = u !== "" ? srcUrl : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadArtwork(url) {
|
function loadArtwork(url, artKey, requestSerial) {
|
||||||
if (!url || url === "") {
|
if (!url || url === "") {
|
||||||
// Keep stale art; only blank once the empty url debounce settles.
|
// Keep stale art; only blank once the empty url debounce settles.
|
||||||
_lastArtUrl = "";
|
_lastArtUrl = "";
|
||||||
@@ -85,11 +85,11 @@ Singleton {
|
|||||||
|
|
||||||
// 1. First, check if the file already exists locally
|
// 1. First, check if the file already exists locally
|
||||||
Proc.runCommand(null, ["test", "-f", filePath], (output, exitCode) => {
|
Proc.runCommand(null, ["test", "-f", filePath], (output, exitCode) => {
|
||||||
if (_lastArtUrl !== targetUrl)
|
if (_lastArtUrl !== targetUrl || _requestSerial !== requestSerial)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
_commit(localFileUrl);
|
_commit(localFileUrl, artKey, targetUrl);
|
||||||
loading = false;
|
loading = false;
|
||||||
} else {
|
} else {
|
||||||
const dlCmd = "mkdir -p \"$(dirname \"$1\")\" && curl -f -s -L -o \"$1\" \"$2\" && mv \"$1\" \"$3\" || { rm -f \"$1\"; exit 1; }";
|
const dlCmd = "mkdir -p \"$(dirname \"$1\")\" && curl -f -s -L -o \"$1\" \"$2\" && mv \"$1\" \"$3\" || { rm -f \"$1\"; exit 1; }";
|
||||||
@@ -102,18 +102,18 @@ Singleton {
|
|||||||
const tmpPath = filePath + ".tmp";
|
const tmpPath = filePath + ".tmp";
|
||||||
|
|
||||||
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, maxresUrl, filePath], (maxOutput, maxExitCode) => {
|
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, maxresUrl, filePath], (maxOutput, maxExitCode) => {
|
||||||
if (_lastArtUrl !== targetUrl)
|
if (_lastArtUrl !== targetUrl || _requestSerial !== requestSerial)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (maxExitCode === 0) {
|
if (maxExitCode === 0) {
|
||||||
_commit(localFileUrl);
|
_commit(localFileUrl, artKey, targetUrl);
|
||||||
loading = false;
|
loading = false;
|
||||||
} else {
|
} else {
|
||||||
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, mqUrl, filePath], (mqOutput, mqExitCode) => {
|
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, mqUrl, filePath], (mqOutput, mqExitCode) => {
|
||||||
if (_lastArtUrl !== targetUrl)
|
if (_lastArtUrl !== targetUrl || _requestSerial !== requestSerial)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_commit(mqExitCode === 0 ? localFileUrl : targetUrl);
|
_commit(mqExitCode === 0 ? localFileUrl : targetUrl, artKey, targetUrl);
|
||||||
loading = false;
|
loading = false;
|
||||||
}, 50, 15000);
|
}, 50, 15000);
|
||||||
}
|
}
|
||||||
@@ -122,10 +122,10 @@ Singleton {
|
|||||||
// Standard curl download for other remote URLs (e.g. SoundCloud)
|
// Standard curl download for other remote URLs (e.g. SoundCloud)
|
||||||
const tmpPath = filePath + ".tmp";
|
const tmpPath = filePath + ".tmp";
|
||||||
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, targetUrl, filePath], (dlOutput, dlExitCode) => {
|
Proc.runCommand(null, ["sh", "-c", dlCmd, "sh", tmpPath, targetUrl, filePath], (dlOutput, dlExitCode) => {
|
||||||
if (_lastArtUrl !== targetUrl)
|
if (_lastArtUrl !== targetUrl || _requestSerial !== requestSerial)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_commit(dlExitCode === 0 ? localFileUrl : targetUrl);
|
_commit(dlExitCode === 0 ? localFileUrl : targetUrl, artKey, targetUrl);
|
||||||
loading = false;
|
loading = false;
|
||||||
}, 50, 15000);
|
}, 50, 15000);
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ Singleton {
|
|||||||
// Cover lands after metadata, so poll; commit a content-addressed copy so identical bytes keep an identical url
|
// Cover lands after metadata, so poll; commit a content-addressed copy so identical bytes keep an identical url
|
||||||
const script = "f=\"$1\"; d=\"$2\"; i=0; while [ ! -f \"$f\" ] && [ \"$i\" -lt 20 ]; do sleep 0.15; i=$((i + 1)); done; [ -f \"$f\" ] || exit 1; s=$(sha1sum \"$f\" | cut -c1-40); if [ ! -f \"$d/art_$s\" ]; then mkdir -p \"$d\" && cp \"$f\" \"$d/art_$s.tmp\" && mv \"$d/art_$s.tmp\" \"$d/art_$s\" || exit 1; fi; echo \"$s\"";
|
const script = "f=\"$1\"; d=\"$2\"; i=0; while [ ! -f \"$f\" ] && [ \"$i\" -lt 20 ]; do sleep 0.15; i=$((i + 1)); done; [ -f \"$f\" ] || exit 1; s=$(sha1sum \"$f\" | cut -c1-40); if [ ! -f \"$d/art_$s\" ]; then mkdir -p \"$d\" && cp \"$f\" \"$d/art_$s.tmp\" && mv \"$d/art_$s.tmp\" \"$d/art_$s\" || exit 1; fi; echo \"$s\"";
|
||||||
Proc.runCommand(null, ["sh", "-c", script, "sh", filePath, cacheDir], (output, exitCode) => {
|
Proc.runCommand(null, ["sh", "-c", script, "sh", filePath, cacheDir], (output, exitCode) => {
|
||||||
if (_lastArtUrl !== localUrl)
|
if (_lastArtUrl !== localUrl || _requestSerial !== requestSerial)
|
||||||
return;
|
return;
|
||||||
loading = false;
|
loading = false;
|
||||||
if (exitCode !== 0)
|
if (exitCode !== 0)
|
||||||
@@ -149,7 +149,7 @@ Singleton {
|
|||||||
const sha = (output || "").trim();
|
const sha = (output || "").trim();
|
||||||
if (_artHashDenylist.indexOf(sha) !== -1)
|
if (_artHashDenylist.indexOf(sha) !== -1)
|
||||||
return;
|
return;
|
||||||
_commit("file://" + cacheDir + "/art_" + sha);
|
_commit("file://" + cacheDir + "/art_" + sha, artKey, localUrl);
|
||||||
}, 50, 5000);
|
}, 50, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ Singleton {
|
|||||||
interval: 800
|
interval: 800
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root._lastArtUrl === "")
|
if (root._lastArtUrl === "")
|
||||||
root._commit("");
|
root._commit("", "", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +167,7 @@ Singleton {
|
|||||||
property string _committedArtKey: ""
|
property string _committedArtKey: ""
|
||||||
property string _pendingArtKey: ""
|
property string _pendingArtKey: ""
|
||||||
property string _committedSrcUrl: ""
|
property string _committedSrcUrl: ""
|
||||||
|
property int _requestSerial: 0
|
||||||
|
|
||||||
onActivePlayerChanged: _updateArtUrl()
|
onActivePlayerChanged: _updateArtUrl()
|
||||||
|
|
||||||
@@ -182,9 +183,10 @@ Singleton {
|
|||||||
const p = activePlayer;
|
const p = activePlayer;
|
||||||
if (!p)
|
if (!p)
|
||||||
return "";
|
return "";
|
||||||
// +title/artist: KDEconnect reuses one trackid forever; album excluded: Chrome delivers it late, orphaning the lock
|
// Scope artwork ownership to the MPRIS object and track.
|
||||||
|
const playerId = p.uniqueId || p.identity || "";
|
||||||
const tid = p.metadata && p.metadata["mpris:trackid"] ? p.metadata["mpris:trackid"].toString() : "";
|
const tid = p.metadata && p.metadata["mpris:trackid"] ? p.metadata["mpris:trackid"].toString() : "";
|
||||||
return tid + " " + (p.trackTitle || "") + " " + (p.trackArtist || "");
|
return playerId + " " + tid + " " + (p.trackTitle || "") + " " + (p.trackArtist || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function artReadyFor(player) {
|
function artReadyFor(player) {
|
||||||
@@ -194,17 +196,19 @@ Singleton {
|
|||||||
|
|
||||||
function _updateArtUrl() {
|
function _updateArtUrl() {
|
||||||
const key = _trackKey();
|
const key = _trackKey();
|
||||||
// Skip once real art is committed for this track (dedup Chrome's multi-size
|
if (key !== _pendingArtKey) {
|
||||||
// re-publish). The lock is set in _commit(), never optimistically, so a rejected
|
_requestSerial++;
|
||||||
// placeholder or a short-circuited duplicate url can't wedge the real cover out.
|
loading = false;
|
||||||
if (key !== "" && key === _committedArtKey)
|
}
|
||||||
return;
|
|
||||||
_pendingArtKey = key;
|
_pendingArtKey = key;
|
||||||
const url = getArtworkUrl(activePlayer);
|
const url = getArtworkUrl(activePlayer);
|
||||||
|
// Ignore Chrome's same-track thumbnail size updates.
|
||||||
|
if (key !== "" && key === _committedArtKey)
|
||||||
|
return;
|
||||||
if (key !== "" && url !== "" && url === _committedSrcUrl) {
|
if (key !== "" && url !== "" && url === _committedSrcUrl) {
|
||||||
_committedArtKey = key;
|
// Chrome can publish track metadata before its new artwork URL.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loadArtwork(url);
|
loadArtwork(url, key, _requestSerial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user