internal: use stdiocollector
Removes dependency on jq Also fix beatdetector
This commit is contained in:
parent
4c475548af
commit
05e9561fd6
10 changed files with 150 additions and 123 deletions
|
|
@ -69,8 +69,8 @@ Row {
|
|||
|
||||
running: true
|
||||
command: ["uptime", "-p"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => uptimeProc.uptime = data
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: uptimeProc.uptime = text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Singleton {
|
|||
|
||||
Process {
|
||||
running: true
|
||||
command: [`${Quickshell.shellRoot}/assets/realtime-beat-detector.py`]
|
||||
command: [`${Quickshell.configDir}/assets/realtime-beat-detector.py`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => root.bpm = parseFloat(data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,31 +24,47 @@ Singleton {
|
|||
|
||||
Process {
|
||||
id: getInfo
|
||||
|
||||
running: true
|
||||
command: ["sh", "-c", "bluetoothctl show | paste -s"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.powered = data.includes("Powered: yes");
|
||||
root.discovering = data.includes("Discovering: yes");
|
||||
command: ["bluetoothctl", "show"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.powered = text.includes("Powered: yes");
|
||||
root.discovering = text.includes("Discovering: yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getDevices
|
||||
|
||||
running: true
|
||||
command: ["fish", "-c", `for a in (bluetoothctl devices | cut -d ' ' -f 2); bluetoothctl info $a | jq -R 'reduce (inputs / ":") as [$key, $value] ({}; .[$key | ltrimstr("\t")] = ($value | ltrimstr(" ")))' | jq -c --arg addr $a '.Address = $addr'; end | jq -sc`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const devices = JSON.parse(data).filter(d => d.Name);
|
||||
command: ["fish", "-c", `
|
||||
for a in (bluetoothctl devices)
|
||||
if string match -q 'Device *' $a
|
||||
bluetoothctl info $addr (string split ' ' $a)[2]
|
||||
echo
|
||||
end
|
||||
end`]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const devices = text.trim().split("\n\n").map(d => ({
|
||||
name: d.match(/Name: (.*)/)[1],
|
||||
alias: d.match(/Alias: (.*)/)[1],
|
||||
address: d.match(/Device ([0-9A-Z:]{17})/)[1],
|
||||
icon: d.match(/Icon: (.*)/)[1],
|
||||
connected: d.includes("Connected: yes"),
|
||||
paired: d.includes("Paired: yes"),
|
||||
trusted: d.includes("Trusted: yes")
|
||||
}));
|
||||
const rDevices = root.devices;
|
||||
|
||||
const destroyed = rDevices.filter(rd => !devices.find(d => d.Address === rd.address));
|
||||
const destroyed = rDevices.filter(rd => !devices.find(d => d.address === rd.address));
|
||||
for (const device of destroyed)
|
||||
rDevices.splice(rDevices.indexOf(device), 1).forEach(d => d.destroy());
|
||||
|
||||
for (const device of devices) {
|
||||
const match = rDevices.find(d => d.address === device.Address);
|
||||
const match = rDevices.find(d => d.address === device.address);
|
||||
if (match) {
|
||||
match.lastIpcObject = device;
|
||||
} else {
|
||||
|
|
@ -63,13 +79,13 @@ Singleton {
|
|||
|
||||
component Device: QtObject {
|
||||
required property var lastIpcObject
|
||||
readonly property string name: lastIpcObject.Name
|
||||
readonly property string alias: lastIpcObject.Alias
|
||||
readonly property string address: lastIpcObject.Address
|
||||
readonly property string icon: lastIpcObject.Icon
|
||||
readonly property bool connected: lastIpcObject.Connected === "yes"
|
||||
readonly property bool paired: lastIpcObject.Paired === "yes"
|
||||
readonly property bool trusted: lastIpcObject.Trusted === "yes"
|
||||
readonly property string name: lastIpcObject.name
|
||||
readonly property string alias: lastIpcObject.alias
|
||||
readonly property string address: lastIpcObject.address
|
||||
readonly property string icon: lastIpcObject.icon
|
||||
readonly property bool connected: lastIpcObject.connected
|
||||
readonly property bool paired: lastIpcObject.paired
|
||||
readonly property bool trusted: lastIpcObject.trusted
|
||||
}
|
||||
|
||||
Component {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import QtQuick
|
|||
Singleton {
|
||||
id: root
|
||||
|
||||
property var ddcMonitors: []
|
||||
property list<var> ddcMonitors: []
|
||||
readonly property list<Monitor> monitors: variants.instances
|
||||
|
||||
function getMonitorForScreen(screen: ShellScreen): var {
|
||||
|
|
@ -49,19 +49,12 @@ Singleton {
|
|||
id: ddcProc
|
||||
|
||||
command: ["ddcutil", "detect", "--brief"]
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n\n"
|
||||
onRead: data => {
|
||||
if (data.startsWith("Display ")) {
|
||||
const lines = data.split("\n").map(l => l.trim());
|
||||
root.ddcMonitors.push({
|
||||
model: lines.find(l => l.startsWith("Monitor:")).split(":")[2],
|
||||
busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1]
|
||||
});
|
||||
}
|
||||
}
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
|
||||
model: d.match(/Monitor:.*:(.*):.*/)[1],
|
||||
busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1]
|
||||
}))
|
||||
}
|
||||
onExited: root.ddcMonitorsChanged()
|
||||
}
|
||||
|
||||
Process {
|
||||
|
|
@ -87,9 +80,9 @@ Singleton {
|
|||
property real brightness
|
||||
|
||||
readonly property Process initProc: Process {
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const [, , , current, max] = data.split(" ");
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const [, , , current, max] = text.split(" ");
|
||||
monitor.brightness = parseInt(current) / parseInt(max);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ Singleton {
|
|||
|
||||
Process {
|
||||
id: getClients
|
||||
command: ["sh", "-c", "hyprctl -j clients | jq -c"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const clients = JSON.parse(data);
|
||||
command: ["hyprctl", "-j", "clients"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const clients = JSON.parse(text);
|
||||
const rClients = root.clients;
|
||||
|
||||
const destroyed = rClients.filter(rc => !clients.find(c => c.address === rc.address));
|
||||
|
|
@ -68,10 +68,9 @@ Singleton {
|
|||
Process {
|
||||
id: getActiveClient
|
||||
command: ["hyprctl", "-j", "activewindow"]
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: data => {
|
||||
const client = JSON.parse(data);
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const client = JSON.parse(text);
|
||||
const rClient = root.activeClient;
|
||||
if (client.address) {
|
||||
if (rClient)
|
||||
|
|
|
|||
|
|
@ -23,31 +23,36 @@ Singleton {
|
|||
Process {
|
||||
id: getNetworks
|
||||
running: true
|
||||
command: ["sh", "-c", `nmcli -g ACTIVE,SIGNAL,FREQ,SSID,BSSID d w | jq -ncR '[(inputs | split("(?<!\\\\\\\\):"; "g")) | select(.[3] | length >= 4)]'`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const networks = JSON.parse(data).map(n => [n[0] === "yes", parseInt(n[1]), parseInt(n[2]), n[3], n[4].replace(/\\/g, "")]);
|
||||
command: ["nmcli", "-g", "ACTIVE,SIGNAL,FREQ,SSID,BSSID", "d", "w"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED";
|
||||
const rep = new RegExp("\\\\:", "g");
|
||||
const rep2 = new RegExp(PLACEHOLDER, "g");
|
||||
|
||||
const networks = text.trim().split("\n").map(n => {
|
||||
const net = n.replace(rep, PLACEHOLDER).split(":");
|
||||
return {
|
||||
active: net[0] === "yes",
|
||||
strength: parseInt(net[1]),
|
||||
frequency: parseInt(net[2]),
|
||||
ssid: net[3],
|
||||
bssid: net[4].replace(rep2, ":")
|
||||
};
|
||||
});
|
||||
const rNetworks = root.networks;
|
||||
|
||||
const destroyed = rNetworks.filter(rn => !networks.find(n => n[2] === rn.frequency && n[3] === rn.ssid && n[4] === rn.bssid));
|
||||
const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid));
|
||||
for (const network of destroyed)
|
||||
rNetworks.splice(rNetworks.indexOf(network), 1).forEach(n => n.destroy());
|
||||
|
||||
for (const network of networks) {
|
||||
const match = rNetworks.find(n => n.frequency === network[2] && n.ssid === network[3] && n.bssid === network[4]);
|
||||
const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid);
|
||||
if (match) {
|
||||
match.active = network[0];
|
||||
match.strength = network[1];
|
||||
match.frequency = network[2];
|
||||
match.ssid = network[3];
|
||||
match.bssid = network[4];
|
||||
match.lastIpcObject = network;
|
||||
} else {
|
||||
rNetworks.push(apComp.createObject(root, {
|
||||
active: network[0],
|
||||
strength: network[1],
|
||||
frequency: network[2],
|
||||
ssid: network[3],
|
||||
bssid: network[4]
|
||||
lastIpcObject: network
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -56,11 +61,12 @@ Singleton {
|
|||
}
|
||||
|
||||
component AccessPoint: QtObject {
|
||||
required property string ssid
|
||||
required property string bssid
|
||||
required property int strength
|
||||
required property int frequency
|
||||
required property bool active
|
||||
required property var lastIpcObject
|
||||
readonly property string ssid: lastIpcObject.ssid
|
||||
readonly property string bssid: lastIpcObject.bssid
|
||||
readonly property int strength: lastIpcObject.strength
|
||||
readonly property int frequency: lastIpcObject.frequency
|
||||
readonly property bool active: lastIpcObject.active
|
||||
}
|
||||
|
||||
Component {
|
||||
|
|
|
|||
|
|
@ -98,38 +98,40 @@ Singleton {
|
|||
|
||||
running: true
|
||||
command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"]
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: data => {
|
||||
const deviceMap = new Map();
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const deviceMap = new Map();
|
||||
|
||||
for (const line of data.trim().split("\n")) {
|
||||
if (line.trim() === "") continue;
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line.trim() === "")
|
||||
continue;
|
||||
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length >= 3) {
|
||||
const device = parts[0];
|
||||
const used = parseInt(parts[1], 10) || 0;
|
||||
const avail = parseInt(parts[2], 10) || 0;
|
||||
|
||||
// only keep the entry with the largest total space for each device
|
||||
if (!deviceMap.has(device) ||
|
||||
(used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
|
||||
deviceMap.set(device, { used: used, avail: avail });
|
||||
}
|
||||
}
|
||||
}
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length >= 3) {
|
||||
const device = parts[0];
|
||||
const used = parseInt(parts[1], 10) || 0;
|
||||
const avail = parseInt(parts[2], 10) || 0;
|
||||
|
||||
let totalUsed = 0;
|
||||
let totalAvail = 0;
|
||||
|
||||
for (const [device, stats] of deviceMap) {
|
||||
totalUsed += stats.used;
|
||||
totalAvail += stats.avail;
|
||||
}
|
||||
// Only keep the entry with the largest total space for each device
|
||||
if (!deviceMap.has(device) || (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
|
||||
deviceMap.set(device, {
|
||||
used: used,
|
||||
avail: avail
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.storageUsed = totalUsed;
|
||||
root.storageTotal = totalUsed + totalAvail;
|
||||
let totalUsed = 0;
|
||||
let totalAvail = 0;
|
||||
|
||||
for (const [device, stats] of deviceMap) {
|
||||
totalUsed += stats.used;
|
||||
totalAvail += stats.avail;
|
||||
}
|
||||
|
||||
root.storageUsed = totalUsed;
|
||||
root.storageTotal = totalUsed + totalAvail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,10 +140,10 @@ Singleton {
|
|||
id: cpuTemp
|
||||
|
||||
running: true
|
||||
command: ["fish", "-c", "cat /sys/class/thermal/thermal_zone*/temp | string join ' '"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const temps = data.trim().split(" ");
|
||||
command: ["sh", "-c", "cat /sys/class/thermal/thermal_zone*/temp"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const temps = text.trim().split(" ");
|
||||
const sum = temps.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||
root.cpuTemp = sum / temps.length / 1000;
|
||||
}
|
||||
|
|
@ -153,10 +155,9 @@ Singleton {
|
|||
|
||||
running: true
|
||||
command: ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"]
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: data => {
|
||||
const percs = data.trim().split("\n");
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const percs = text.trim().split("\n");
|
||||
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||
root.gpuPerc = sum / percs.length / 100;
|
||||
}
|
||||
|
|
@ -167,13 +168,14 @@ Singleton {
|
|||
id: gpuTemp
|
||||
|
||||
running: true
|
||||
command: ["sh", "-c", "sensors | jq -nRc '[inputs]'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
command: ["sensors"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
let eligible = false;
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
for (const line of JSON.parse(data)) {
|
||||
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line === "Adapter: PCI adapter")
|
||||
eligible = true;
|
||||
else if (line === "")
|
||||
|
|
@ -186,6 +188,7 @@ Singleton {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.gpuTemp = count > 0 ? sum / count : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,10 +78,9 @@ Singleton {
|
|||
id: getPreviewColoursProc
|
||||
|
||||
command: ["caelestia", "wallpaper", "-p", root.previewPath]
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: data => {
|
||||
Colours.load(data, true);
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
Colours.load(text, true);
|
||||
Colours.showPreview = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -98,9 +97,8 @@ Singleton {
|
|||
Process {
|
||||
running: true
|
||||
command: ["fd", ".", root.path, "-t", "f", "-e", "jpg", "-e", "jpeg", "-e", "png", "-e", "webp", "-e", "tif", "-e", "tiff"]
|
||||
stdout: SplitParser {
|
||||
splitMarker: ""
|
||||
onRead: data => wallpapers.model = data.trim().split("\n")
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: wallpapers.model = text.trim().split("\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Quickshell.Io
|
|||
Singleton {
|
||||
id: root
|
||||
|
||||
property string loc
|
||||
property string icon
|
||||
property string description
|
||||
property real temperature
|
||||
|
|
@ -15,17 +16,28 @@ Singleton {
|
|||
wttrProc.running = true;
|
||||
}
|
||||
|
||||
onLocChanged: wttrProc.running = true
|
||||
|
||||
Process {
|
||||
id: ipProc
|
||||
|
||||
running: true
|
||||
command: ["curl", "ipinfo.io"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.loc = JSON.parse(text).loc
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: wttrProc
|
||||
|
||||
running: true
|
||||
command: ["fish", "-c", `curl "https://wttr.in/$(curl ipinfo.io | jq -r '.city' | string replace -a ' ' '%20')?format=j1" | jq -c '.current_condition[0] | {code: .weatherCode, desc: .weatherDesc[0].value, temp: .temp_C}'`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
const json = JSON.parse(data);
|
||||
root.icon = Icons.getWeatherIcon(json.code);
|
||||
root.description = json.desc;
|
||||
root.temperature = parseFloat(json.temp);
|
||||
command: ["curl", `https://wttr.in/${root.loc}?format=j1`]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const json = JSON.parse(text).current_condition[0];
|
||||
root.icon = Icons.getWeatherIcon(json.weatherCode);
|
||||
root.description = json.weatherDesc[0].value;
|
||||
root.temperature = parseFloat(json.temp_C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ Image {
|
|||
property string path
|
||||
|
||||
command: ["sha256sum", path]
|
||||
stdout: SplitParser {
|
||||
onRead: data => root.hash = data.split(" ")[0]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.hash = text.split(" ")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue