1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-29 14:32:08 -04:00

feat(mpris): allow excluding specific media players by identity (#2712)

* feat(mpris): allow excluding specific media players by identity

* chore(translation): update settings search index and clean trailing whitespace
This commit is contained in:
Huỳnh Thiện Lộc
2026-06-29 23:01:19 +07:00
committed by GitHub
parent a874f76d72
commit de3e8cffa0
6 changed files with 238 additions and 2 deletions
+27
View File
@@ -448,6 +448,7 @@ Singleton {
property string audioScrollMode: "volume"
property int audioWheelScrollAmount: 5
property bool audioDeviceScrollVolumeEnabled: false
property var mediaExcludePlayers: []
property bool clockCompactMode: false
property int focusedWindowSize: 1
property bool focusedWindowCompactMode: false
@@ -3062,6 +3063,32 @@ Singleton {
saveSettings();
}
function addMediaExcludePlayer(identity) {
if (identity === undefined || identity === null)
return;
var normalizedIdentity = identity.toString().trim().toLowerCase();
if (!normalizedIdentity)
return;
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
var normalizedList = list.map(function(id) {
return id ? id.toString().trim().toLowerCase() : "";
});
if (normalizedList.indexOf(normalizedIdentity) >= 0)
return;
list.push(normalizedIdentity);
mediaExcludePlayers = list;
saveSettings();
}
function removeMediaExcludePlayer(index) {
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
if (index < 0 || index >= list.length)
return;
list.splice(index, 1);
mediaExcludePlayers = list;
saveSettings();
}
property bool _pendingExpandNotificationRules: false
property int _pendingNotificationRuleIndex: -1
@@ -184,6 +184,7 @@ var SPEC = {
audioScrollMode: { def: "volume" },
audioWheelScrollAmount: { def: 5 },
audioDeviceScrollVolumeEnabled: { def: false },
mediaExcludePlayers: { def: [] },
clockCompactMode: { def: false },
focusedWindowCompactMode: { def: false },
focusedWindowSize: { def: 1 },
@@ -434,7 +434,9 @@ FocusScope {
visible: active
focus: active
sourceComponent: MediaPlayerTab {}
sourceComponent: MediaPlayerTab {
parentModal: root.parentModal
}
onActiveChanged: {
if (active && item)
@@ -2,10 +2,22 @@ import QtQuick
import qs.Common
import qs.Widgets
import qs.Modules.Settings.Widgets
import qs.Services
Item {
id: root
property var desktopApps: []
property var parentModal: null
Component.onCompleted: {
desktopApps = AppSearchService.getVisibleApplications() || [];
}
Component.onDestruction: {
desktopApps = [];
}
DankFlickable {
anchors.fill: parent
clip: true
@@ -121,6 +133,149 @@ Item {
onToggled: checked => SettingsData.set("audioDeviceScrollVolumeEnabled", checked)
}
}
SettingsCard {
width: parent.width
iconName: "do_not_disturb_on"
title: I18n.tr("Excluded Media Players")
settingKey: "mediaExcludePlayers"
tags: ["media", "music", "exclude", "ignore", "player", "mpris"]
Column {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: I18n.tr("Prevent specific applications from displaying in the media controllers (e.g., browser audio streams, background tools). Matches player identity or desktop file name case-insensitively.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
Row {
width: parent.width
spacing: Theme.spacingS
DankTextField {
id: newExcludePlayerField
width: parent.width - addBtn.width - selectAppBtn.width - Theme.spacingS * 2
height: 36
placeholderText: I18n.tr("App name or identity (e.g., firefox)")
font.pixelSize: Theme.fontSizeSmall
onAccepted: {
if (text.trim() !== "") {
SettingsData.addMediaExcludePlayer(text.trim());
text = "";
}
}
}
DankActionButton {
id: addBtn
buttonSize: 36
iconName: "add"
iconSize: 20
backgroundColor: Theme.primary
iconColor: Theme.onPrimary
onClicked: {
if (newExcludePlayerField.text.trim() !== "") {
SettingsData.addMediaExcludePlayer(newExcludePlayerField.text.trim());
newExcludePlayerField.text = "";
}
}
}
DankActionButton {
id: selectAppBtn
buttonSize: 36
iconName: "apps"
iconSize: 20
backgroundColor: Theme.surfaceContainer
iconColor: Theme.primary
onClicked: appBrowserPopup.show()
}
}
Column {
width: parent.width
spacing: Theme.spacingS
Repeater {
model: SettingsData.mediaExcludePlayers
delegate: Rectangle {
width: parent.width
height: 48
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingS
spacing: Theme.spacingM
Row {
width: parent.width - deleteBtn.width - Theme.spacingS
height: parent.height
spacing: Theme.spacingS
DankIcon {
name: "music_off"
size: 20
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankActionButton {
id: deleteBtn
buttonSize: 32
iconName: "delete"
iconSize: 18
iconColor: Theme.error
backgroundColor: "transparent"
anchors.verticalCenter: parent.verticalCenter
onClicked: SettingsData.removeMediaExcludePlayer(index)
}
}
}
}
}
StyledText {
visible: !SettingsData.mediaExcludePlayers || SettingsData.mediaExcludePlayers.length === 0
text: I18n.tr("No excluded players configured")
font.pixelSize: Theme.fontSizeSmall
font.italic: true
color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter
width: parent.width
topPadding: Theme.spacingS
}
}
}
}
}
AppBrowserPopup {
id: appBrowserPopup
appsModel: root.desktopApps
parentModal: root.parentModal
onAppSelected: appId => {
var name = appId;
if (name.endsWith(".desktop")) {
name = name.slice(0, -8);
}
SettingsData.addMediaExcludePlayer(name);
}
}
}
+32 -1
View File
@@ -9,7 +9,38 @@ import qs.Common
Singleton {
id: root
readonly property list<MprisPlayer> availablePlayers: Mpris.players.values
readonly property list<MprisPlayer> availablePlayers: {
const players = Mpris.players.values;
const excluded = SettingsData.mediaExcludePlayers || [];
if (excluded.length === 0)
return players;
return players.filter(p => {
const identity = (p.identity || "").toLowerCase();
const desktopEntry = ("desktopEntry" in p && p.desktopEntry) ? String(p.desktopEntry).toLowerCase() : "";
return !excluded.some(ex => {
const exLower = String(ex).toLowerCase().trim();
if (!exLower) return false;
// 1. Substring match
if (identity.includes(exLower) || desktopEntry.includes(exLower))
return true;
// 2. Match reverse-DNS segments (e.g. app.zen_browser.zen -> zen)
if (exLower.indexOf(".") !== -1) {
const parts = exLower.split(".");
const lastPart = parts[parts.length - 1];
if (lastPart && (identity.includes(lastPart) || desktopEntry.includes(lastPart)))
return true;
}
// 3. Bidirectional match (longer excluded name contains shorter player identity)
if (identity.length >= 3 && exLower.includes(identity))
return true;
return false;
});
});
}
property MprisPlayer activePlayer: null
property real activePlayerStableLength: 0
@@ -5643,6 +5643,26 @@
],
"description": "Play sound when volume is adjusted"
},
{
"section": "mediaExcludePlayers",
"label": "Excluded Media Players",
"tabIndex": 16,
"category": "Media Player",
"keywords": [
"audio",
"exclude",
"excluded",
"ignore",
"media",
"mpris",
"music",
"playback",
"player",
"players",
"spotify"
],
"icon": "do_not_disturb_on"
},
{
"section": "_tab_16",
"label": "Media Player",