Krolyxon
Commit a52a0fa

Branches

Refs →

aurora.configquickshellauroraRec.qml

82 lines · 3.2 KB · QML

1pragma Singleton
2import QtQuick
3import Quickshell
4import Quickshell.Io
5import Quickshell.Hyprland
6import Quickshell.Services.Pipewire
7
8// Screen recording with wf-recorder (the focused monitor, or a region via slurp), saved to ~/vids/rec.
9// Records desktop audio: the monitor source of the current default output (whatever you hear).
10// Two steps so each can be cancelled: `selecting` (slurp is up) then `running` (wf-recorder records).
11// stop() works in both. Everything is hidden if wf-recorder / slurp aren't installed.
12Singleton {
13 id: root
14 property bool available: false
15 readonly property bool running: recProc.running
16 readonly property bool selecting: delay.running || selectProc.running
17 readonly property bool busy: running || selecting
18 property string dir: Quickshell.env("HOME") + "/vids/recs"
19 property string file: ""
20 readonly property string log: Quickshell.env("HOME") + "/.cache/aurora/rec.log"
21 property string mode: "screen"
22 property int elapsed: 0 // seconds
23
24 function start(m) { // "region" | "screen"
25 if (!available || busy) return
26 mode = m
27 delay.start() // let the panel close before slurp grabs the screen
28 }
29 function stop() {
30 if (delay.running) delay.stop()
31 if (selectProc.running) selectProc.signal(15)
32 if (recProc.running) recProc.signal(2) // SIGINT: wf-recorder finalises the file
33 }
34 function toggle(m) { if (busy) stop(); else start(m) }
35
36 function record(geometry) {
37 file = dir + "/" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm-ss") + ".mp4"
38 var mon = Hyprland.focusedMonitor
39 // exec so the Process pid is wf-recorder itself and SIGINT reaches it.
40 // its (very chatty) output must go to a file: left on the Process pipe it dies without writing anything
41 var sink = Pipewire.defaultAudioSink
42 var audio = sink ? "--audio=" + sink.name + ".monitor" : "--audio"
43 var run = 'mkdir -p "${1%/*}" "${3%/*}"; exec wf-recorder ' + (geometry !== "" ? '-g' : '-o') + ' "$2" "$4" -f "$1" >"$3" 2>&1'
44 recProc.command = ["sh", "-c", run, "sh", file, geometry !== "" ? geometry : (mon ? mon.name : ""), log, audio]
45 elapsed = 0
46 recProc.running = true
47 }
48
49 Timer {
50 id: delay
51 interval: 250
52 onTriggered: {
53 if (root.mode === "region") selectProc.running = true
54 else root.record("")
55 }
56 }
57 Process {
58 id: selectProc
59 command: ["slurp"]
60 // slurp prints nothing when cancelled (Esc, or stop() killing it)
61 stdout: StdioCollector {
62 onStreamFinished: {
63 var g = text.trim()
64 if (g !== "") root.record(g)
65 }
66 }
67 }
68 Process {
69 id: recProc
70 onExited: {
71 Quickshell.execDetached(["sh", "-c",
72 '[ -s "$1" ] && notify-send -a aurora "recording saved" "$1"', "sh", root.file])
73 }
74 }
75 Timer { interval: 1000; repeat: true; running: recProc.running; onTriggered: root.elapsed++ }
76
77 Process {
78 command: ["sh", "-c", "command -v wf-recorder && command -v slurp"]
79 running: true
80 onExited: code => root.available = code === 0
81 }
82}