Add MPRIS blacklist

This commit is contained in:
Ly-sec 2025-08-26 13:11:49 +02:00
parent 7bcb227d7b
commit 1533b2d3a1
5 changed files with 171 additions and 10 deletions

View file

@ -218,6 +218,9 @@ Singleton {
property string visualizerType: "linear"
property int volumeStep: 5
property int cavaFrameRate: 60
// MPRIS controls
property list<string> mprisBlacklist: []
property string preferredPlayer: ""
}
// ui

View file

@ -50,7 +50,7 @@ Row {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
active: Settings.data.audio.showMiniplayerCava && Settings.data.audio.visualizerType == "linear"
&& MediaService.isPlaying
&& MediaService.isPlaying && MediaService.trackLength > 0
z: 0
sourceComponent: LinearSpectrum {
@ -65,7 +65,7 @@ Row {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
active: Settings.data.audio.showMiniplayerCava && Settings.data.audio.visualizerType == "mirrored"
&& MediaService.isPlaying
&& MediaService.isPlaying && MediaService.trackLength > 0
z: 0
sourceComponent: MirroredSpectrum {
@ -81,7 +81,7 @@ Row {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
active: Settings.data.audio.showMiniplayerCava && Settings.data.audio.visualizerType == "wave"
&& MediaService.isPlaying
&& MediaService.isPlaying && MediaService.trackLength > 0
z: 0
sourceComponent: WaveSpectrum {

View file

@ -227,6 +227,134 @@ ColumnLayout {
Layout.bottomMargin: Style.marginXL * scaling
}
// MPRIS Player Preferences
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "MPRIS Player Preferences"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Preferred player (persistent)
NTextInput {
label: "Preferred Player"
description: "Substring to match MPRIS player (identity/bus/desktop)."
placeholderText: "e.g. spotify, vlc, mpv"
text: Settings.data.audio.preferredPlayer
onTextChanged: {
Settings.data.audio.preferredPlayer = text
MediaService.updateCurrentPlayer()
}
}
// Blacklist editor
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
RowLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
NTextInput {
id: blacklistInput
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
label: "Blacklist player"
description: "Substring, e.g. plex, shim, mpv"
placeholderText: "type substring and press +"
}
// Button aligned to the center of the actual input field
NIconButton {
icon: "add"
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
const val = (blacklistInput.text || "").trim()
if (val !== "") {
const arr = (Settings.data.audio.mprisBlacklist || [])
if (!arr.find(x => String(x).toLowerCase() === val.toLowerCase())) {
Settings.data.audio.mprisBlacklist = [...arr, val]
blacklistInput.text = ""
MediaService.updateCurrentPlayer()
}
}
}
}
}
// Current blacklist entries
Flow {
Layout.fillWidth: true
Layout.leftMargin: Style.marginS * scaling
spacing: Style.marginS * scaling
Repeater {
model: Settings.data.audio.mprisBlacklist
delegate: Rectangle {
required property string modelData
// Padding around the inner row
property real pad: Style.marginS * scaling
// Visuals
color: Color.applyOpacity(Color.mOnSurface, "20")
border.color: Color.applyOpacity(Color.mOnSurface, "50")
border.width: Math.max(1, Style.borderS * scaling)
// Content
RowLayout {
id: chipRow
spacing: Style.marginXS * scaling
anchors.fill: parent
anchors.margins: pad
NText {
text: modelData
color: Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Style.marginS * scaling
}
NIconButton {
icon: "close"
sizeRatio: 0.8
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.marginXS * scaling
onClicked: {
const arr = (Settings.data.audio.mprisBlacklist || [])
const idx = arr.findIndex(x => String(x) === modelData)
if (idx >= 0) {
arr.splice(idx, 1)
Settings.data.audio.mprisBlacklist = arr
MediaService.updateCurrentPlayer()
}
}
}
}
// Intrinsic size derived from inner row + padding
implicitWidth: chipRow.implicitWidth + pad * 2
implicitHeight: Math.max(chipRow.implicitHeight + pad * 2, Style.baseWidgetSize * 0.8 * scaling)
radius: Style.radiusM * scaling
}
}
}
}
}
// Divider
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// Bar Mini Media player
ColumnLayout {
spacing: Style.marginL * scaling
@ -350,4 +478,4 @@ ColumnLayout {
}
}
}
}
}

View file

@ -51,6 +51,7 @@ NBox {
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
@ -330,7 +331,7 @@ NBox {
}
Loader {
active: Settings.data.audio.visualizerType == "linear"
active: Settings.data.audio.visualizerType == "linear" && MediaService.isPlaying && MediaService.trackLength > 0
Layout.alignment: Qt.AlignHCenter
sourceComponent: LinearSpectrum {
@ -343,7 +344,7 @@ NBox {
}
Loader {
active: Settings.data.audio.visualizerType == "mirrored"
active: Settings.data.audio.visualizerType == "mirrored" && MediaService.isPlaying && MediaService.trackLength > 0
Layout.alignment: Qt.AlignHCenter
sourceComponent: MirroredSpectrum {
@ -356,7 +357,7 @@ NBox {
}
Loader {
active: Settings.data.audio.visualizerType == "wave"
active: Settings.data.audio.visualizerType == "wave" && MediaService.isPlaying && MediaService.trackLength > 0
Layout.alignment: Qt.AlignHCenter
sourceComponent: WaveSpectrum {

View file

@ -12,7 +12,7 @@ Singleton {
property var currentPlayer: null
property real currentPosition: 0
property int selectedPlayerIndex: 0
property bool isPlaying: currentPlayer ? currentPlayer.isPlaying : false
property bool isPlaying: currentPlayer ? (currentPlayer.playbackState === MprisPlaybackState.Playing || currentPlayer.isPlaying) : false
property string trackTitle: currentPlayer ? (currentPlayer.trackTitle || "") : ""
property string trackArtist: currentPlayer ? (currentPlayer.trackArtist || "") : ""
property string trackAlbum: currentPlayer ? (currentPlayer.trackAlbum || "") : ""
@ -37,11 +37,24 @@ Singleton {
let allPlayers = Mpris.players.values
let controllablePlayers = []
// Apply blacklist and controllable filter
const blacklist = (Settings.data.audio && Settings.data.audio.mprisBlacklist) ? Settings.data.audio.mprisBlacklist : []
for (var i = 0; i < allPlayers.length; i++) {
let player = allPlayers[i]
if (player && player.canControl) {
if (!player)
continue
const identity = String(player.identity || "")
const busName = String(player.busName || "")
const desktop = String(player.desktopEntry || "")
const idKey = identity.toLowerCase()
const match = blacklist.find(b => {
const s = String(b || "").toLowerCase()
return s && (idKey.includes(s) || busName.toLowerCase().includes(s) || desktop.toLowerCase().includes(s))
})
if (match)
continue
if (player.canControl)
controllablePlayers.push(player)
}
}
return controllablePlayers
@ -54,6 +67,22 @@ Singleton {
return null
}
// Preferred player logic (preferred > fallback)
const preferred = (Settings.data.audio.preferredPlayer || "")
if (preferred !== "") {
for (var i = 0; i < availablePlayers.length; i++) {
const p = availablePlayers[i]
const identity = String(p.identity || "").toLowerCase()
const busName = String(p.busName || "").toLowerCase()
const desktop = String(p.desktopEntry || "").toLowerCase()
const pref = preferred.toLowerCase()
if (identity.includes(pref) || busName.includes(pref) || desktop.includes(pref)) {
selectedPlayerIndex = i
return p
}
}
}
if (selectedPlayerIndex < availablePlayers.length) {
return availablePlayers[selectedPlayerIndex]
} else {