mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-09 23:15:38 -05:00
simplify privacy service
This commit is contained in:
@@ -9,131 +9,90 @@ import Quickshell.Services.Pipewire
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool microphoneActive: false
|
readonly property bool microphoneActive: {
|
||||||
property bool cameraActive: false
|
if (!Pipewire.ready || !Pipewire.nodes?.values) return false
|
||||||
property bool screensharingActive: false
|
|
||||||
|
|
||||||
readonly property bool anyPrivacyActive: microphoneActive || cameraActive || screensharingActive
|
|
||||||
|
|
||||||
readonly property var micSource: AudioService.source
|
|
||||||
property var activeMicSources: []
|
|
||||||
property var activeCameraSources: []
|
|
||||||
property var activeScreenSources: []
|
|
||||||
|
|
||||||
function resetPrivacyStates() {
|
|
||||||
root.cameraActive = false;
|
|
||||||
root.screensharingActive = false;
|
|
||||||
root.microphoneActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: portalMonitor
|
|
||||||
command: ["bash", "-c", `
|
|
||||||
screencast_count=0
|
|
||||||
camera_count=0
|
|
||||||
microphone_count=0
|
|
||||||
|
|
||||||
if command -v lsof >/dev/null 2>&1; then
|
|
||||||
video_device_users=$(lsof /dev/video* 2>/dev/null | wc -l || echo "0")
|
|
||||||
if [ "$video_device_users" -gt 0 ]; then
|
|
||||||
camera_count=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v busctl >/dev/null 2>&1; then
|
|
||||||
mic_access_count=$(busctl --user call org.freedesktop.portal.Desktop /org/freedesktop/portal/desktop org.freedesktop.DBus.Properties Get ss "org.freedesktop.portal.Inhibit" "Inhibited" 2>/dev/null | grep -c "microphone" || echo "0")
|
|
||||||
if [ "$mic_access_count" -gt 0 ]; then
|
|
||||||
microphone_count=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$microphone_count" -eq 0 ] && command -v pactl >/dev/null 2>&1; then
|
|
||||||
total_outputs=$(pactl list short source-outputs | wc -l || echo "0")
|
|
||||||
system_outputs=$(pactl list source-outputs | grep -c "media\\.name.*cava" || echo "0")
|
|
||||||
user_outputs=$((total_outputs - system_outputs))
|
|
||||||
if [ "$user_outputs" -gt 0 ]; then
|
|
||||||
microphone_count=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v busctl >/dev/null 2>&1; then
|
|
||||||
screencast_sessions=$(busctl --user list | grep "org.freedesktop.portal.Session" | wc -l || echo "0")
|
|
||||||
if [ "$screencast_sessions" -gt 0 ]; then
|
|
||||||
screencast_count=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v pw-dump >/dev/null 2>&1; then
|
|
||||||
active_video_streams=$(pw-dump 2>/dev/null | grep -i "video" | grep -i "state.*running" | wc -l || echo "0")
|
|
||||||
if [ "$active_video_streams" -gt 0 ]; then
|
|
||||||
camera_count=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
active_screen_streams=$(pw-dump 2>/dev/null | grep -i "screen" | grep -i "state.*running" | wc -l || echo "0")
|
|
||||||
if [ "$active_screen_streams" -gt 0 ]; then
|
|
||||||
screencast_count=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "screencast:$screencast_count"
|
|
||||||
echo "camera:$camera_count"
|
|
||||||
echo "microphone:$microphone_count"
|
|
||||||
`]
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
for (let i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||||
onStreamFinished: {
|
const node = Pipewire.nodes.values[i]
|
||||||
root.resetPrivacyStates();
|
if (!node || !node.ready) continue
|
||||||
|
|
||||||
if (text && text.length > 0) {
|
if (node.properties && node.properties["media.class"] === "Stream/Input/Audio") {
|
||||||
const lines = text.trim().split('\n');
|
if (node.properties["stream.is-live"] === "true") {
|
||||||
let foundScreencast = false;
|
if (!looksLikeSystemVirtualMic(node)) {
|
||||||
let foundCamera = false;
|
return true
|
||||||
let foundMicrophone = false;
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.startsWith('screencast:')) {
|
|
||||||
const count = parseInt(line.split(':')[1]) || 0;
|
|
||||||
foundScreencast = foundScreencast || (count > 0);
|
|
||||||
} else if (line.startsWith('camera:')) {
|
|
||||||
const count = parseInt(line.split(':')[1]) || 0;
|
|
||||||
foundCamera = foundCamera || (count > 0);
|
|
||||||
} else if (line.startsWith('microphone:')) {
|
|
||||||
const count = parseInt(line.split(':')[1]) || 0;
|
|
||||||
foundMicrophone = foundMicrophone || (count > 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root.screensharingActive = foundScreencast;
|
|
||||||
root.cameraActive = foundCamera;
|
|
||||||
root.microphoneActive = foundMicrophone;
|
|
||||||
} else {
|
|
||||||
root.screensharingActive = false;
|
|
||||||
root.cameraActive = false;
|
|
||||||
root.microphoneActive = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PwObjectTracker {
|
||||||
|
objects: Pipewire.nodes.values
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool cameraActive: {
|
||||||
|
if (!Pipewire.ready || !Pipewire.nodes?.values) return false
|
||||||
|
|
||||||
onExited: (exitCode, exitStatus) => {
|
for (let i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||||
if (exitCode !== 0) {
|
const node = Pipewire.nodes.values[i]
|
||||||
console.warn("PrivacyService: Portal monitor process failed with exit code:", exitCode);
|
if (!node || !node.ready) continue
|
||||||
|
|
||||||
|
if (node.properties && node.properties["media.class"] === "Stream/Input/Video") {
|
||||||
|
if (node.properties["stream.is-live"] === "true") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
readonly property bool screensharingActive: {
|
||||||
id: privacyMonitor
|
if (!Pipewire.ready || !Pipewire.nodes?.values) return false
|
||||||
interval: 3000
|
|
||||||
running: true
|
for (let i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||||
repeat: true
|
const node = Pipewire.nodes.values[i]
|
||||||
onTriggered: {
|
if (!node || !node.ready) continue
|
||||||
if (!portalMonitor.running) {
|
|
||||||
portalMonitor.running = true;
|
if ((node.type & PwNodeType.VideoSource) === PwNodeType.VideoSource) {
|
||||||
|
if (looksLikeScreencast(node)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.properties && node.properties["media.class"] === "Stream/Input/Audio") {
|
||||||
|
const mediaName = (node.properties["media.name"] || "").toLowerCase()
|
||||||
|
const appName = (node.properties["application.name"] || "").toLowerCase()
|
||||||
|
|
||||||
|
if (mediaName.includes("desktop") || appName.includes("screen") || appName === "obs") {
|
||||||
|
if (node.properties["stream.is-live"] === "true") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool anyPrivacyActive: microphoneActive || cameraActive || screensharingActive
|
||||||
|
|
||||||
|
|
||||||
|
function looksLikeSystemVirtualMic(node) {
|
||||||
|
if (!node) return false
|
||||||
|
const name = (node.name || "").toLowerCase()
|
||||||
|
const mediaName = (node.properties && node.properties["media.name"] || "").toLowerCase()
|
||||||
|
const appName = (node.properties && node.properties["application.name"] || "").toLowerCase()
|
||||||
|
const combined = name + " " + mediaName + " " + appName
|
||||||
|
return /cava|monitor|system/.test(combined)
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
function looksLikeScreencast(node) {
|
||||||
|
if (!node) return false
|
||||||
|
const appName = (node.properties && node.properties["application.name"] || "").toLowerCase()
|
||||||
|
const nodeName = (node.name || "").toLowerCase()
|
||||||
|
const combined = appName + " " + nodeName
|
||||||
|
return /xdg-desktop-portal|xdpw|screencast|screen|gnome shell|kwin|obs/.test(combined)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMicrophoneStatus() {
|
function getMicrophoneStatus() {
|
||||||
|
|||||||
Reference in New Issue
Block a user