Switch media controls to QS MPRIS
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var shell: null
|
||||
property string preferredPlayerKey: ""
|
||||
|
||||
readonly property var players: Mpris.players ? Mpris.players.values : []
|
||||
readonly property var activePlayer: selectActivePlayer()
|
||||
readonly property bool hasMedia: activePlayer !== null && (activePlayer.trackTitle || activePlayer.trackArtist)
|
||||
readonly property string title: activePlayer ? (activePlayer.trackTitle || "") : ""
|
||||
readonly property string artist: activePlayer ? (activePlayer.trackArtist || "") : ""
|
||||
readonly property string album: activePlayer && activePlayer.trackAlbum ? activePlayer.trackAlbum : ""
|
||||
readonly property string artUrl: activePlayer && activePlayer.trackArtUrl ? activePlayer.trackArtUrl : ""
|
||||
readonly property string identity: activePlayer ? (activePlayer.identity || activePlayer.desktopEntry || "") : ""
|
||||
|
||||
function isProxyPlayer(player) {
|
||||
var dbusName = String(player && player.dbusName || "").toLowerCase()
|
||||
var desktopEntry = String(player && player.desktopEntry || "").toLowerCase()
|
||||
return dbusName.indexOf("playerctld") !== -1 || desktopEntry === "playerctld"
|
||||
}
|
||||
|
||||
function hasMetadata(player) {
|
||||
return !!(player && (player.trackTitle || player.trackArtist || player.identity || player.desktopEntry))
|
||||
}
|
||||
|
||||
function hasTrackMetadata(player) {
|
||||
return !!(player && (player.trackTitle || player.trackArtist || player.trackAlbum || player.trackArtUrl))
|
||||
}
|
||||
|
||||
function playerKey(player) {
|
||||
if (!player) return ""
|
||||
return String(player.dbusName || player.desktopEntry || player.identity || "")
|
||||
}
|
||||
|
||||
function selectActivePlayer() {
|
||||
var playingProxy = null
|
||||
var preferred = null
|
||||
var trackPlayer = null
|
||||
var trackProxy = null
|
||||
var identityPlayer = null
|
||||
var identityProxy = null
|
||||
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
var p = players[i]
|
||||
if (!p) continue
|
||||
|
||||
var proxy = isProxyPlayer(p)
|
||||
if (p.isPlaying) {
|
||||
if (!proxy) return p
|
||||
if (!playingProxy) playingProxy = p
|
||||
}
|
||||
|
||||
if (preferredPlayerKey && playerKey(p) === preferredPlayerKey && hasMetadata(p)) preferred = p
|
||||
|
||||
if (hasTrackMetadata(p)) {
|
||||
if (!proxy && !trackPlayer) trackPlayer = p
|
||||
else if (proxy && !trackProxy) trackProxy = p
|
||||
} else if (hasMetadata(p)) {
|
||||
if (!proxy && !identityPlayer) identityPlayer = p
|
||||
else if (proxy && !identityProxy) identityProxy = p
|
||||
}
|
||||
}
|
||||
|
||||
return playingProxy || preferred || trackPlayer || trackProxy || identityPlayer || identityProxy || null
|
||||
}
|
||||
|
||||
function labelFor(player) {
|
||||
if (!player) return ""
|
||||
return player.trackTitle || player.identity || player.desktopEntry || ""
|
||||
}
|
||||
|
||||
function osdMessage(player, fallback) {
|
||||
if (!player) return fallback
|
||||
var label = labelFor(player)
|
||||
if (label && player.trackArtist) return label + " - " + player.trackArtist
|
||||
return label || fallback
|
||||
}
|
||||
|
||||
function showOsd(actionLabel, iconName) {
|
||||
if (!shell) return
|
||||
shell.summon("omarchy.osd", JSON.stringify({
|
||||
icon: iconName || "media",
|
||||
message: osdMessage(activePlayer, actionLabel)
|
||||
}))
|
||||
}
|
||||
|
||||
function runAction(action, showFeedback) {
|
||||
var player = activePlayer
|
||||
var key = playerKey(player)
|
||||
var actionLabel = "Play/pause"
|
||||
var iconName = "media"
|
||||
var handled = false
|
||||
|
||||
if (action === "next") {
|
||||
actionLabel = "Next"
|
||||
iconName = "media-next"
|
||||
if (player && player.canGoNext) {
|
||||
player.next()
|
||||
handled = true
|
||||
}
|
||||
} else if (action === "previous") {
|
||||
actionLabel = "Previous"
|
||||
iconName = "media-previous"
|
||||
if (player && player.canGoPrevious) {
|
||||
player.previous()
|
||||
handled = true
|
||||
}
|
||||
} else if (action === "play") {
|
||||
actionLabel = "Play"
|
||||
iconName = "media-play"
|
||||
if (player && player.canPlay) {
|
||||
player.play()
|
||||
handled = true
|
||||
} else if (player && player.canTogglePlaying && !player.isPlaying) {
|
||||
player.togglePlaying()
|
||||
handled = true
|
||||
}
|
||||
} else if (action === "pause") {
|
||||
actionLabel = "Pause"
|
||||
iconName = "media-pause"
|
||||
if (player && player.canPause) {
|
||||
player.pause()
|
||||
handled = true
|
||||
} else if (player && player.canTogglePlaying && player.isPlaying) {
|
||||
player.togglePlaying()
|
||||
handled = true
|
||||
}
|
||||
} else if (action === "playPause") {
|
||||
actionLabel = player && player.isPlaying ? "Pause" : "Play"
|
||||
iconName = player && player.isPlaying ? "media-pause" : "media-play"
|
||||
if (player && player.isPlaying && player.canPause) {
|
||||
player.pause()
|
||||
handled = true
|
||||
} else if (player && !player.isPlaying && player.canPlay) {
|
||||
player.play()
|
||||
handled = true
|
||||
} else if (player && player.canTogglePlaying) {
|
||||
player.togglePlaying()
|
||||
handled = true
|
||||
}
|
||||
}
|
||||
|
||||
if (handled && key) preferredPlayerKey = key
|
||||
if (showFeedback !== false) Qt.callLater(function() { root.showOsd(actionLabel, iconName) })
|
||||
return handled
|
||||
}
|
||||
|
||||
function statusJson() {
|
||||
var p = activePlayer
|
||||
return JSON.stringify({
|
||||
hasPlayer: p !== null,
|
||||
hasMedia: root.hasMedia,
|
||||
playing: p ? !!p.isPlaying : false,
|
||||
identity: p ? (p.identity || "") : "",
|
||||
desktopEntry: p ? (p.desktopEntry || "") : "",
|
||||
title: p ? (p.trackTitle || "") : "",
|
||||
artist: p ? (p.trackArtist || "") : "",
|
||||
album: p && p.trackAlbum ? p.trackAlbum : "",
|
||||
artUrl: p && p.trackArtUrl ? p.trackArtUrl : "",
|
||||
canGoNext: p ? !!p.canGoNext : false,
|
||||
canGoPrevious: p ? !!p.canGoPrevious : false,
|
||||
canTogglePlaying: p ? !!p.canTogglePlaying : false
|
||||
})
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "media"
|
||||
|
||||
function status(): string {
|
||||
return root.statusJson()
|
||||
}
|
||||
|
||||
function playPause(): string {
|
||||
return root.runAction("playPause", true) ? "ok" : "unhandled"
|
||||
}
|
||||
|
||||
function next(): string {
|
||||
return root.runAction("next", true) ? "ok" : "unhandled"
|
||||
}
|
||||
|
||||
function previous(): string {
|
||||
return root.runAction("previous", true) ? "ok" : "unhandled"
|
||||
}
|
||||
|
||||
function play(): string {
|
||||
return root.runAction("play", true) ? "ok" : "unhandled"
|
||||
}
|
||||
|
||||
function pause(): string {
|
||||
return root.runAction("pause", true) ? "ok" : "unhandled"
|
||||
}
|
||||
|
||||
function ping(): string {
|
||||
return "ok"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "omarchy.media",
|
||||
"name": "Media",
|
||||
"version": "1.0.0",
|
||||
"author": "Omarchy",
|
||||
"description": "MPRIS media control service",
|
||||
"kinds": [
|
||||
"service"
|
||||
],
|
||||
"keepLoaded": true,
|
||||
"entryPoints": {
|
||||
"service": "Service.qml"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user